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

#######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ì)算得出,以下是分析圖 :

如上圖,控件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è)加載控件
效果看圖 :

實(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