Android自定義View(3)畫兩個(gè)好玩的數(shù)據(jù)加載進(jìn)度緩沖控件

1、仿58同城數(shù)據(jù)加載緩沖控件動(dòng)畫效果

先看下效果圖:

58city.gif

#######1.1 實(shí)現(xiàn)步驟拆解
(1)自定義一個(gè)ShapeView繼承自View,按順序分別重繪三角形、圓形和正方形,如此不斷重復(fù)。
(2)自定義一個(gè)ViewGroup,創(chuàng)建一個(gè)ShapeView加進(jìn)布局當(dāng)中,并往布局中再添加一個(gè)TextView以顯示文字。onLayout分別擺放好ShapeView和TextView。
(3)使用屬性動(dòng)畫實(shí)現(xiàn)ShapeView的上下移動(dòng)和旋轉(zhuǎn)

#######1.2 實(shí)現(xiàn)分析
2.1 自定義一個(gè)ShapeView
自定義一個(gè)ShapeView實(shí)現(xiàn)三種形狀切換效果的原理也很簡(jiǎn)單。圓形通過(guò)畫布的canvas.drawCircle()方法來(lái)繪制,正方形通過(guò)畫布的canvas.drawRect()方法來(lái)繪制。等邊三角形的繪制稍復(fù)雜,可通過(guò)繪制路徑來(lái)實(shí)現(xiàn): canvas.drawPath(),等邊三角形路徑的三個(gè)頂點(diǎn)坐標(biāo)通過(guò)計(jì)算得出,以下是分析圖 :


triangle.png

如上圖,控件ShapeView的寬高可通過(guò)getMeasureHeight()或getMeasureWidth()獲得,這里測(cè)量時(shí)已確保ShapeView的寬高相等。因此,三角形邊長(zhǎng)S即為控件寬或高。
然后,如上圖,三角形的三個(gè)頂點(diǎn)A 、B 、C即可通過(guò)勾股定理算出。
三角形路徑設(shè)置代碼如下:

Path trianglePath = new Path();
trianglePath.moveTo(getWidth() / 2f, 0);
trianglePath.lineTo(0, (float) (Math.sqrt(3) * getHeight() / 2)); // 等邊三角形
trianglePath.lineTo(getWidth(), (float) (Math.sqrt(3) * getHeight() / 2));
trianglePath.close();

確定好三個(gè)形狀的繪制方法后,就可以循環(huán)地延時(shí)一秒鐘,不斷地改變當(dāng)前所要繪制的圖形形狀,調(diào)用 invalidate()方法實(shí)現(xiàn)圖形的重繪。三種圖形繪制方法如下 :

 @Override
    protected void onDraw(Canvas canvas) {
        switch (mShape) { // 當(dāng)前所要繪制的形狀
            case circle:  // 圓
                canvas.drawCircle(getWidth() / 2f, getHeight() / 2f, getHeight() / 2f, circlePaint);
                break;
            case rect:  // 正方形
                canvas.drawRect(0, 0, getWidth(), getHeight(), rectPaint);
                break;
            case triangle: // 三角形
                canvas.drawPath(trianglePath, trianglePaint);
                break;
        }
    }

ShapeView的代碼見(jiàn) :https://github.com/EthanLee-88/LoadingView/blob/master/app/src/main/java/com/ethan/loadingview/view/ShapeView.java

2.2 自定義一個(gè)布局ShapeChangeLoadingViewGroup。

第二步驟就是自定義一個(gè)布局ShapeChangeLoadingViewGroup,繼承自ViewGroup。再創(chuàng)建ShapeView和一個(gè)TextView,TextView用于顯示文字“拼命加載中...”。這個(gè)步驟的主要內(nèi)容在于布局,將TextView放在ViewGroup的最底部,ShapeView放在上面。ShapeChangeLoadingViewGroup的布局部分代碼如下 :

@Override
    protected void onLayout(boolean changed, int l, int t, int r, int b) {
        int shapeLeft = getWidth() / 2 - mShapeView.getMeasuredWidth() / 2;
        int shapeTop = (int) (mShapeView.getMeasuredHeight() * 3.5);
        int shapeRight = shapeLeft + mShapeView.getMeasuredWidth();
        int shapeBottom = shapeTop + mShapeView.getMeasuredHeight();
        mShapeView.layout(shapeLeft, shapeTop, shapeRight, shapeBottom);
        int textLeft = 0;
        int textTop = getHeight() - mLoadTextView.getMeasuredHeight();
        int textRight = getWidth();
        int textBottom = getHeight();
        mLoadTextView.layout(textLeft, textTop, textRight, textBottom);
        setAnimator();
    }

2.3 使用屬性動(dòng)畫讓ShapeView動(dòng)起來(lái)
第三部就是實(shí)現(xiàn)ShapeView上下移動(dòng)以及旋轉(zhuǎn)的效果,這里分別使用了屬性動(dòng)畫的translationY 和 rotation 兩個(gè)屬性實(shí)現(xiàn)。代碼如下 :

        translationObjectAnimator = ObjectAnimator.ofFloat(mShapeView,
                "translationY", -distance, 0, -distance);  //實(shí)現(xiàn)上下平移
        translationObjectAnimator.setDuration(1500);
        translationObjectAnimator.setInterpolator(new AccelerateDecelerateInterpolator());
        translationObjectAnimator.setRepeatCount(-1);  // -1 無(wú)限循環(huán)

        rotationObjectAnimator = ObjectAnimator.ofFloat(mShapeView,
                "rotation", 0f, 360f);  // 實(shí)現(xiàn)360度旋轉(zhuǎn)
        rotationObjectAnimator.setDuration(1500);
        rotationObjectAnimator.setRepeatCount(-1);  // -1 無(wú)限循環(huán)

        rotationObjectAnimator.start();
        translationObjectAnimator.start();

最后效果實(shí)現(xiàn)了,但有一點(diǎn)要優(yōu)化。對(duì)外提供一個(gè)接口,將屬性動(dòng)畫資源釋放 :

public void release(){  //優(yōu)化,釋放屬性動(dòng)畫資源
        if (translationObjectAnimator != null){
            translationObjectAnimator.end();
            translationObjectAnimator.removeAllListeners();
            translationObjectAnimator.cancel();
            translationObjectAnimator = null;
        }
        if (rotationObjectAnimator != null){
            rotationObjectAnimator.end();
            rotationObjectAnimator.removeAllListeners();
            rotationObjectAnimator.cancel();
            rotationObjectAnimator = null;
        }
        if (mShapeView != null) mShapeView.setRepeat(false);
    }

完整代碼 :https://github.com/EthanLee-88/LoadingView

2、另一個(gè)加載控件

效果看圖 :

loadingView.gif

實(shí)現(xiàn)步驟 :
(1) 自定義一個(gè)CircleView繼承自View,畫一個(gè)圓,對(duì)外提供可改變顏色的接口。
(2) 自定義一個(gè)LoadingView繼承自ViewGroup,創(chuàng)建三個(gè)CircleView,分別擺放在LoadingView的左、中、右的位置。
(3) 利用屬性動(dòng)畫實(shí)現(xiàn)左右兩個(gè)CircleView往中間方向來(lái)回移動(dòng),中間的CircleView保持不動(dòng)。
(4) 監(jiān)聽屬性動(dòng)畫的回調(diào),實(shí)現(xiàn)每移動(dòng)一次,三個(gè)CircleView顏色互換一次,達(dá)到變色的效果。
這部分實(shí)現(xiàn)比較簡(jiǎn)單,實(shí)現(xiàn)原理和上面第一個(gè)控件相似,這里不再詳細(xì)講述??丛创a:https://github.com/EthanLee-88/LoadingView

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容