教你玩轉自定義View—手擼一個倒數計時控制元件如此簡單

codeGoogle發表於2019-01-29

在一個APP啟動的時候呢,一般經常見到倒數計時3秒或幾秒的場景,在這個場景中,也經常看到一個有動畫載入的view,效果圖如下:

倒數計時效果圖
倒數計時效果圖

分析

正所謂知己知彼百戰百勝,所以我們每去做一件事情之前都要去花費一定的時間去了解一些相關的東西。那麼這樣的一個效果呢其實不難,我們只需兩個東西即可實現。——canvas和屬性動畫。

1.自定義我們需要的屬性:

那麼為了考慮擴充套件性,那麼有些屬性呢我們不能寫死,自定義屬性是最好的選擇!首先在values資料夾下新建檔案attrs.xml

<declare-styleable name="CountDownView">
        <!--view半徑-->
        <attr name="cd_circle_radius" format="dimension" />
        <!--畫筆寬度-->
        <attr name="cd_arc_width" format="dimension" />
        <!--畫筆顏色-->
        <attr name="cd_arc_color" format="color" />
        <!--背景顏色-->
        <attr name="cd_bg_color" format="color" />
        <!--字型顏色-->
        <attr name="cd_text_color" format="color" />
        <!--字型尺寸-->
        <attr name="cd_text_size" format="dimension" />
        <!--動畫執行時長-->
        <attr name="cd_animator_time" format="integer" />
        <!--時間單位-->
        <attr name="cd_animator_time_unit" format="string" />
        <!--動畫進退方式-->
        <attr name="cd_retreat_type" format="enum">
            <!--外層的圓弧逐漸變長-->
            <enum name="forward" value="1" />
            <!--外層的圓弧逐漸減短-->
            <enum name="back" value="2" />
        </attr>
        <!--載入進度的開始位置-->
        <attr name="cd_location" format="enum">
            <enum name="left" value="1" />
            <enum name="top" value="2" />
            <enum name="right" value="3" />
            <enum name="bottom" value="4" />
        </attr>
    </declare-styleable>複製程式碼

然後在自定義View中獲取並設定這些屬性:
首先,來宣告和獲取定義好的屬性:

private Paint mPaintBackGround;//背景畫筆
    private Paint mPaintArc;//圓弧畫筆
    private Paint mPaintText;//文字畫筆
    private int mRetreatType;//圓弧繪製方式(增加和減少)
    private float mPaintArcWidth;//最外層圓弧的寬度
    private int mCircleRadius;//圓圈的半徑
    private int mPaintArcColor = Color.parseColor("#3C3F41");//初始值
    private int mPaintBackGroundColor = Color.parseColor("#55B2E5");//初始值
......複製程式碼

獲取這些屬性值:

TypedArray array = context.obtainStyledAttributes(attrs, R.styleable.CountDownView);
mRetreatType = array.getInt(R.styleable.CountDownView_cd_retreat_type, 1);
location = array.getInt(R.styleable.CountDownView_cd_location, 1);複製程式碼

初始化畫筆等操作:

2.畫出需要的效果:畫圓弧,畫字型,畫背景

這裡我們使用cancas的drawArc()方法,不瞭解這個方法是什麼意思的請跳至此處檢視詳細解釋~drawArc()方法詳細介紹

環形進度
環形進度

3.改變屬性值,重新繪製

4.介面回撥。

這一步就很簡單了,只要監聽動畫執行結束就是完成了載入,所以我們先來寫一個介面。

private OnLoadingFinishListener loadingFinishListener;

    public void setOnLoadingFinishListener(OnLoadingFinishListener listener) {
        this.loadingFinishListener = listener;
    }

    public interface OnLoadingFinishListener {
        void finish();
    }複製程式碼

在對應的Activity中回撥介面就可以了。

OK,到這裡就算全部結束了,下面是部分原始碼:

@Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        //因為必須是圓形的view,所以在這裡重新賦值
        setMeasuredDimension(mCircleRadius * 2, mCircleRadius * 2);
    }

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        //畫北景園
        canvas.drawCircle(mWidth / 2, mHeight / 2, mWidth / 2 - mPaintArcWidth, mPaintBackGround);
        //畫圓弧
        RectF rectF = new RectF(0 + mPaintArcWidth / 2, 0 + mPaintArcWidth / 2
                , mWidth - mPaintArcWidth / 2, mHeight - mPaintArcWidth / 2);
        canvas.drawArc(rectF, startAngle, mSweepAngle, false, mPaintArc);
        //畫文字
        float mTetxWidth = mPaintText.measureText(mText, 0, mText.length());
        float dx = mWidth / 2 - mTetxWidth / 2;
        Paint.FontMetricsInt fontMetricsInt = mPaintText.getFontMetricsInt();
        float dy = (fontMetricsInt.bottom - fontMetricsInt.top) / 2 - fontMetricsInt.bottom;
        float baseLine = mHeight / 2 + dy;
        canvas.drawText(mText, dx, baseLine, mPaintText);

    }複製程式碼

部落格地址:

www.jianshu.com/p/2b5ef5e18…

專案地址:

github.com/SuperKotlin…

相信自己,沒有做不到的,只有想不到的

如果你覺得此文對您有所幫助,歡迎入群 QQ交流群 :232203809
微信公眾號:終端研發部

技術+職場
技術+職場

相關文章