首頁 > 軟體

Android自定義View實現APP啟動頁倒計時效果

2022-02-10 13:01:12

Android自定義View實現APP啟動頁倒計時效果,供大家參考,具體內容如下

之前也是做過APP啟動頁的倒計時效果,但是隻有文字變化,沒有動畫效果,這次通過使用自定義View控制元件來製作一個帶有動畫效果的倒計時。

倒計時效果的基本思路如下:

Canvas提供了繪製弧形的方法,drawArc(),使用這個方法通過定時重新整理計算當前弧形的角度,就可以模擬出倒計時的動畫效果,同時藉助drawText()方法可以實現倒計時文字。
(1)繼承View
(2)使用canvas的drawArc()來繪製弧形,模擬動畫效果
(3)使用canvas的drawText()來繪製倒計時文字
(4)向外部(Activity或者Fragment)提供介面,倒計時結束之後通過介面告訴外部

具體看程式碼:

首先定義當前view的寬度和高度的預設值,並重寫onMeasure()方法,否則在佈局檔案中即使使用wrap_content當前view也會佈滿全螢幕

 //當前view高度和寬度的預設值
 private static final int DEFAULT_WIDTH = 100;
 private static final int DEFAULT_HEIGHT = 100;

定義三個變數,分別是倒計時總長度,當前剩餘倒計時長度,以及剩餘時間比例,根據這個比例繪製弧形劃過的角度

private int countDownTime = 5000;//倒計時的時間,預設是5秒
private int countDownNow = 5000;//當前的時間,預設也是5秒
private float timeTatio = 1f;//剩餘時間比例,預設為1

定義畫筆以及向外部提供的介面

使用Android提供的倒計時類,如果不使用這個類,也可以通過thread+handler實現,初始化這個類需要傳入兩個引數,第一個引數是倒計時總長度,第二個引數是倒計時間隔,也就是每隔多長時間停止一次。這個類重寫了兩個方法,第一個方法是倒計時暫停的時候需要執行的操作,第二個方法是倒計時完全結束之後需要執行的操作,在這裡,我設定了每隔10ms暫停一次,計算剩餘時間的比例並重新繪製整個view,倒計時完全結束後通過介面告訴外部。

private Paint paint;
    private ViewCountDownFinishListener viewCountDownFinishListener;
    //倒計時,每隔100毫秒倒計時一次
    private CountDownTimer countDownTimer = new CountDownTimer(countDownTime,10) {
        @Override
        public void onTick(long l) {
            LogUtils.logI("倒計時:"+l);
            countDownNow = (int) l;
            //計算比例
            timeTatio = (float) countDownNow / (float)countDownTime;
            invalidate();
        }

        @Override
        public void onFinish() {
            countDownTimer.cancel();
            if(viewCountDownFinishListener != null){
                viewCountDownFinishListener.countDownFinish();
            }
        }
    };

在構造方法中呼叫init()方法以啟動倒計時

private void init(){
        if(countDownTimer != null) {
            countDownTimer.start();
        }
    }
//設定倒計時完成的介面
    public void setViewCountDownFinishListener(ViewCountDownFinishListener viewCountDownFinishListener){
        this.viewCountDownFinishListener = viewCountDownFinishListener;
    }

重寫onDraw()方法,根據
canvas.drawArc(float left,float top,float right,float bottom,float startAngle,float sweepAngle,boolean useCenter, Paint paint)
引數說明:
前四個參數列明當前的弧形所在的橢圓,只要設定橢圓寬度和高度一樣,就是一個圓了,
startAngle是開始繪製的角度,以正右方向(X軸正方向)為0都,順時針為正度數,逆時針為負度數,這裡我設定從-90°(也就是Y軸負方向)開始,
sweep是指弧形劃過的角度,這裡我設定的是從0開始一直劃過360度,剛好畫一個圓,但是其實並沒有完全到360度,因為我設定了每隔10ms執行一次,最後並不會完全是360度,但是非常接近,幾乎看不出來。
useCenter表示是否連線到圓心,如果連線到圓心,就是扇形,這裡需要弧形,就選擇false

繪製完弧形後開始繪製倒計時文字,這個比較簡單,就是計算倒計時剩餘時間就可以了,然後繪製出來。

protected void onDraw(Canvas canvas) {
        LogUtils.logI("onDraw()方法執行");
        super.onDraw(canvas);
        paint = new Paint();
        paint.setStyle(Paint.Style.STROKE);
        paint.setColor(Color.BLACK);
        paint.setAntiAlias(true);
        paint.setStrokeWidth(2);
        paint.setAntiAlias(true);
        //根據比例繪製一個扇形,也就是一個圓形
        //當前的弧度
        float currentRadian = 360 - 360 * timeTatio;


        canvas.drawArc(10,10,60,60,-90,currentRadian,false,paint);
        //繪製文字
        paint.reset();
        paint.setStyle(Paint.Style.FILL);
        paint.setColor(Color.parseColor("#3399ff"));
        paint.setAntiAlias(true);
        paint.setTextSize(30);
        canvas.drawText(String.valueOf((int) (countDownNow/1000)),27,45,paint);
    }

重寫onMeasure()方法,為了將View顯示在正確的位置上。

//重寫onMeasure方法
    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        //super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        setMeasuredDimension(measureSpecHandler(widthMeasureSpec,DEFAULT_WIDTH),measureSpecHandler(heightMeasureSpec,DEFAULT_HEIGHT));
    }

    //計算高度和寬度的具體值
    private int measureSpecHandler(int measureSpec,int defaultSize){
        int result = defaultSize;
        int specModel = MeasureSpec.getMode(measureSpec);
        int specSize = MeasureSpec.getSize(measureSpec);
        switch(specModel){
            case MeasureSpec.EXACTLY:
                result = specSize;
                break;

            case MeasureSpec.AT_MOST:
                result = Math.min(result,specSize);
                break;

            default:
                result = defaultSize;
                break;

        }
        return result;
    }

定義介面,向外部提供倒計時完成的通知資訊

 //定義一個介面,當倒計時完成之後通知activity做出相應改變
    public interface ViewCountDownFinishListener{
        void countDownFinish();
    }

在xml中直接使用:

<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context="com.fanjuan.project.wisdomclass.activity.ActivityMain">

    <com.fanjuan.project.wisdomclass.view.CountDownView
        android:id="@+id/cv_count_down"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="right"
        android:layout_marginRight="20dp"
        android:layout_marginTop="20dp" />

</FrameLayout>

在activity中使用:

 protected void initView() {
        countDownView = findViewById(R.id.cv_count_down);
    }

    @Override
    protected void initListener() {
        super.initListener();
        countDownView.setViewCountDownFinishListener(new CountDownView.ViewCountDownFinishListener() {
            @Override
            public void countDownFinish() {
                ToastUtils.toastInfo("倒計時結束");
            }
        });
    }

最後的效果:

以上就是本文的全部內容,希望對大家的學習有所幫助,也希望大家多多支援it145.com。


IT145.com E-mail:sddin#qq.com