這次高仿的是QQ運動的周報界面的網(wǎng)圖。這個控件剛開始的時候以為代碼量不大,沒想到一路下來界面代碼在加上動畫代碼還是蠻多的。好了老規(guī)矩先上圖:

效果還是和qq的才不多吧。 1. 首先我把各個變量都貼出來以便在后續(xù)中你們可以更好理解代碼的意思:
//屏幕的寬度
private int mScreemWidth;
//屏幕的高度
private int mScreemHight;
//圓的線
private Paint mCirclePaint;
//圓區(qū)域的顏色
private Paint mCirclePaintColor;
//虛線
private Paint mLineCircle;
//圓點
private Paint mCircleHoldPaint;
//畫字體
private Paint mCenterCircle;
//最外的圓的透明度
private int mCircleAlpha1=0;
//中間的圓的透明度
private int mCircleAlpha2=0;
//最內(nèi)的圓的透明度
private int mCircleAlpha3=0;
//好友排名
private int mFriendDranking=0;
//達(dá)標(biāo)天數(shù)
private int mStandardDay=0;
//平均步數(shù)
private int mAverageCount=0;
//好友排名的X軸坐標(biāo)
private float mFriendDrankingX=0;
//好友排名的Y軸坐標(biāo)
private float mFriendDrankingY=0;
//平均步數(shù)的X軸坐標(biāo)
private float mStandardDayX=0;
//平均步數(shù)的Y軸坐標(biāo)
private float mStandardDayY=0;
//達(dá)標(biāo)天數(shù)的X軸坐標(biāo)
private float mAverageCountX=0;
//達(dá)標(biāo)天數(shù)的Y軸坐標(biāo)
private float mAverageCountY=0;
//臨時的View的半徑
private int tempCircleRadius=0;
//View的半徑
private int circleRadius=0;
//每個圓圈的間隔
private float marginCircleSize=0;
//圓的顏色
private int circleColor=0;
//朋友區(qū)域的顏色
private int friendColor;
//平均步數(shù)區(qū)域的顏色
private int averageColor;
//達(dá)標(biāo)天數(shù)區(qū)域的顏色
private int standardColor;
//總步數(shù)
private String allStep;
//好友排名
private String firendDrank;
//達(dá)標(biāo)天數(shù)
private String standarDay;
//平均步數(shù)
private String averageCount;
//波浪動畫的數(shù)值
private int waveData=-30;
//中間文字翻轉(zhuǎn)動畫的數(shù)值
private float centerData=0;
//畫波浪的看門狗
private boolean waveWatchDag=false;
//畫虛線的看門狗
private boolean lineWatchDag=false;
//各點解釋的看門狗
private boolean expainWatchDag=false;
//中心圓的內(nèi)容的看門狗
private boolean centerWatchDag=false;
//解釋的字符串
private String averageCountTxt="平均步數(shù)";
private String friendDrankTxt="好友排名";
private String standarDayTxt="達(dá)標(biāo)天數(shù)";
private String theyCount="本周總步數(shù)";
private String tip="步";
2.有點多了,其次就是測量View的大小的onMeasure():
@Override protected void onMeasure(
int widthMeasureSpec, int heightMeasureSpec) {
int widthModel=MeasureSpec.getMode(widthMeasureSpec);
int heightModel=MeasureSpec.getMode(heightMeasureSpec);
int measureWidth=MeasureSpec.getSize(widthMeasureSpec);
int measureHeight=MeasureSpec.getSize(heightMeasureSpec);
int width;
int height;
if(widthModel==MeasureSpec.EXACTLY){
width=measureWidth;
}else{
width=getPaddingLeft()+getPaddingRight()+measureWidth;
}
if(heightModel==MeasureSpec.EXACTLY){
height=measureHeight;
}else{
height=(getPaddingLeft()+getPaddingRight()+measureHeight)/2;
}
setMeasuredDimension(width,height);
loadAnimator();
}
3.這里當(dāng)設(shè)置大小為wrap_content的時候,View的寬度的話是用屏幕的的寬,而View的高的話是屏幕的高度的一半。當(dāng)View的大小生成之后會調(diào)用onSizeChange()方法,具體操作如下:
@Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
super.onSizeChanged(w, h, oldw, oldh);
mScreemWidth=w;
mScreemHight=h;
//得出最大的圓的半徑
if(mScreemWidth>mScreemHight){
circleRadius=Float.valueOf((w/3.4)+"").intValue();
}else{
circleRadius=Float.valueOf((h/3.4)+"").intValue();
}
if(tempCircleRadius!=0&&tempCircleRadius<=circleRadius){
circleRadius=tempCircleRadius;
}
//得出每個圓的間隔
marginCircleSize=circleRadius/6;
}
當(dāng)View的寬度大于View的高度時,最外邊的圓的半徑就是w/3.4,反之當(dāng)View的高度大于View的寬度時,最外邊的圓的半徑就是h/3.4,而每個圓的間隔就是圓半徑的六分之一。4.接著就是最重要的onDraw()方法了,代碼如下:
@Override protected void onDraw(Canvas canvas) {
canvas.translate(getWidth()/2,getHeight()/2-(circleRadius/6));
canvas.save();
//畫出三條圓圈
drawCircle(canvas);
//畫出波浪圖形
drawWaves(canvas);
//畫虛線
drawDottedLine(canvas);
//畫點
drawCircleHold(canvas);
//畫解釋的內(nèi)容
drawExpain(canvas);
//畫中心圓的內(nèi)容
centerCircleContent(canvas);
}
首先把canvas的原點移到X軸為寬度的一半,Y軸為高度的一半再減去六分之一的半徑,保存canvas的狀態(tài)。接著就一個個說這里面的每一個方法:
//畫出三條圓圈
public void drawCircle(Canvas canvas){
//畫出最大的圓
mCirclePaint.setAlpha(mCircleAlpha1);
canvas.drawCircle(0,0,circleRadius,mCirclePaint);
//畫出第二大的圓
mCirclePaint.setAlpha(mCircleAlpha2);
canvas.drawCircle(0,0,circleRadius-marginCircleSize,mCirclePaint);
mCirclePaintColor.setColor(Color.parseColor("#F1FCFE"));
mCirclePaintColor.setAlpha(mCircleAlpha2);
canvas.drawCircle(0,0,circleRadius-marginCircleSize-2,mCirclePaintColor);
//畫出第三大的圓
mCirclePaint.setAlpha(mCircleAlpha3);
canvas.drawCircle(0,0,circleRadius-marginCircleSize*2,mCirclePaint);
mCirclePaintColor.setColor(Color.parseColor("#E7F9FE"));
mCirclePaintColor.setAlpha(mCircleAlpha3);
canvas.drawCircle(0,0,circleRadius-marginCircleSize*2-2,mCirclePaintColor);
}
這個方法是比較簡單的,就是畫出三個圓圈,每個圓圈的間隔就是前面所初始化的marginCircleSize,圓圈的圓心就是canvas的原點,之前我們移動過原點了。第二和第三個圓圈里面還配有圓的背景,效果如下圖:
接著就是畫出波浪圖形的方法 drawWaves(canvas)代碼如下:
//畫出波浪圖形
public void drawWaves(Canvas canvas){
if(!waveWatchDag){
return ;
}
canvas.rotate(waveData);
float inCircleRadius=circleRadius-marginCircleSize*3;
//算出最上面的點
float topPointX=0;
float topPointY=-inCircleRadius;
//算出左下角的點
float leftBottpmPointX=-(float)Math.sqrt(Math.pow(inCircleRadius,2)-Math.pow(inCircleRadius/2,2));
float leftBottomPointY=inCircleRadius/2;
//算出右小角的點
float rightBottomPointX=-leftBottpmPointX;
float rightBottomPointY=inCircleRadius/2;
//得到好友排名半徑
float mFriendDrankingData=circleValue(mFriendDranking);
//得到達(dá)標(biāo)天數(shù)半徑
float mStandarDayData=circleValue(mStandardDay);
//得到平均步數(shù)半徑
float mAverageCountData=circleValue(mAverageCount);
/*畫好友排名*/
//得出左上角的圓的坐標(biāo)
float[] mFriendDrankingPoint=calculatePoint(mFriendDrankingData);
//好友排名的X軸坐標(biāo)
mFriendDrankingX=-mFriendDrankingPoint[0];
//好友排名的Y軸坐標(biāo)
mFriendDrankingY=-mFriendDrankingPoint[1];
//畫出還有排名的波浪線
Path mFriendDrankingPath=new Path();
mFriendDrankingPath.moveTo(leftBottpmPointX,leftBottomPointY);
mFriendDrankingPath.lineTo(mFriendDrankingX-6,mFriendDrankingY-6);
mFriendDrankingPath.lineTo(topPointX,topPointY);
mFriendDrankingPath.lineTo(topPointX+10,topPointY+10);
mCirclePaintColor.setPathEffect(new CornerPathEffect(20));
mCirclePaintColor.setColor(friendColor);
canvas.drawPath(mFriendDrankingPath,mCirclePaintColor);
/*畫達(dá)標(biāo)天數(shù)*/
//得出右上角的圓的坐標(biāo)
float[] mStandarDayPoint=calculatePoint(mStandarDayData);
//達(dá)標(biāo)天數(shù)的X軸坐標(biāo)
mStandardDayX=mStandarDayPoint[0];
//達(dá)標(biāo)天數(shù)的Y軸坐標(biāo)
mStandardDayY=-mStandarDayPoint[1];
//畫出還有達(dá)標(biāo)天數(shù)的波浪線
Path mStandarDayPath=new Path();
mStandarDayPath.moveTo(topPointX,topPointY);
mStandarDayPath.lineTo(mStandardDayX+6,mStandardDayY-6);
mStandarDayPath.lineTo(rightBottomPointX,rightBottomPointY);
mStandarDayPath.lineTo(rightBottomPointX-10,rightBottomPointY+10);
mCirclePaintColor.setColor(standardColor);
canvas.drawPath(mStandarDayPath,mCirclePaintColor);
/*平均步數(shù)*/
//平均步數(shù)的X軸坐標(biāo)
mAverageCountX=0;
//平均步數(shù)的Y軸坐標(biāo)
mAverageCountY=mAverageCountData;
//畫出還有平均步數(shù)的波浪線
Path mAverageCountPath=new Path();
mAverageCountPath.moveTo(rightBottomPointX,rightBottomPointY);
mAverageCountPath.lineTo(topPointX,mAverageCountData+8);
mAverageCountPath.lineTo(leftBottpmPointX,leftBottomPointY);
mAverageCountPath.lineTo(leftBottpmPointX+10,leftBottomPointY+10);
mCirclePaintColor.setColor(averageColor);
canvas.drawPath(mAverageCountPath,mCirclePaintColor);
//最里面的圓 mCirclePaintColor.setColor(Color.WHITE);
canvas.drawCircle(0,0,circleRadius-marginCircleSize*3,mCirclePaintColor);
}
這方法里最核心的就是數(shù)學(xué)計算了,整個View有3個波浪區(qū)域,各占一個圓的三分之一,所以第一步就是計算出這個圓的左下角,右小角和正上角的三個點,如圖
的藍(lán)色點所示。具體代碼見注釋。在通過circleValue算出波浪線的半徑:
//算出弧線區(qū)域的半徑
public float circleValue(int mDataDranking){
if(mDataDranking==1){
return circleRadius-marginCircleSize*2;
}else if(mDataDranking==2){
return circleRadius-marginCircleSize;
}else if(mDataDranking==3){
return circleRadius;
}else{
return circleRadius-marginCircleSize*2;
} }
然后通過calculatePoint()方法來各個波浪區(qū)域?qū)?yīng)的頂點,代碼如下:
//算出右上角或左上角的坐標(biāo)
public float[] calculatePoint(float radius){
float[] result=new float[2];
float pointY=radius/2;
float pointX=(float)Math.sqrt(Math.pow(radius,2)-Math.pow(pointY,2));
result[0]=pointX;
result[1]=pointY;
return result;
}
最后轉(zhuǎn)化為形象的圖就是:
接著用Path把各個區(qū)域的點連起來就是形成區(qū)域,不過現(xiàn)在還是尖角,要把它變成原角就要用mCirclePaintColor.setPathEffect(new CornerPathEffect(20));方法,這樣各個邊的連接處都可以轉(zhuǎn)換成圓角,可是因為是圓角所以到不到圓圈的邊,這時候你要對你的頂點進(jìn)行微調(diào),所以我再頂點都進(jìn)行了減6或者加6的操作。至于我這個6是怎么得出來的,我用的等比例的數(shù)學(xué)方法來求出來的,到時有優(yōu)化我可以把我的方法用代碼表示出來。至此,重要的就說完了,剩下的只是用canvas和path和paint畫出來就是了。效果如下:
接著就是畫虛線的方法了drawDottedLine(canvas)代碼如下:
//畫圓點和虛線
public void drawDottedLine(Canvas canvas){
if(!lineWatchDag){
return;
}
for(int i=0;i<3;i++){
canvas.rotate(120);
if(i==0){
//畫好友排名的虛線
mLineCircle.setTextSize(18);
mLineCircle.setColor(friendColor);
drawDottedLine(canvas,judgeDotte(mFriendDranking));
}else if(i==1){
//畫達(dá)標(biāo)天數(shù)的虛線
mLineCircle.setColor(standardColor);
drawDottedLine(canvas,judgeDotte(mStandardDay));
}else if(i==2){
//畫平均步數(shù)的虛線
mLineCircle.setColor(averageColor);
drawDottedLine(canvas,judgeDotte(mAverageCount));
} }
canvas.restore();
}
//判斷虛線
public List<Float> judgeDotte(int value){ List<Float> temp=new ArrayList<>();
if(value==1){
//當(dāng)為1時,波浪頂點到第三個圓
temp.add(circleRadius-marginCircleSize*2);
temp.add((float)circleRadius);
temp.add(circleRadius-marginCircleSize*3);
}else if(value==2){
//當(dāng)為2時,波浪頂點到第二個圓
temp.add(circleRadius-marginCircleSize);
temp.add((float)circleRadius);
temp.add(circleRadius-marginCircleSize*3);
}else if(value==3){
//當(dāng)為3時,波浪頂點到第一個圓
temp.add(circleRadius-marginCircleSize*3);
temp.add((float)circleRadius);
}
return temp;
}
//畫虛線
public void drawDottedLine(Canvas canvas,List<Float> data){
if(data.size()==2){
/*當(dāng)數(shù)值是最大的是時候也就是3*/
mLineCircle.setColor(Color.WHITE);
Path path=new Path();
path.moveTo(0,data.get(0));
path.lineTo(0,data.get(1));
canvas.drawPath(path,mLineCircle);
return ;
}else{
/*當(dāng)數(shù)值在1和2的時候*/
//畫出數(shù)值外的虛線
Path pathOut=new Path();
pathOut.moveTo(0,data.get(0));
pathOut.lineTo(0,data.get(1));
mLineCircle.setPathEffect(new DashPathEffect(new float[]{7,5,7,5},5));
canvas.drawPath(pathOut,mLineCircle);
//畫出數(shù)值內(nèi)的虛線
Path pathIn=new Path();
pathIn.moveTo(0,data.get(1));
pathIn.lineTo(0,data.get(2));
mLineCircle.setColor(Color.WHITE);
canvas.drawPath(pathIn,mLineCircle);
}
}
首先canvas通過每次旋轉(zhuǎn)120度來畫出每一條波浪線,通過judgeDotte()方法得出波浪線三個點對應(yīng)的Y軸的坐標(biāo),假如judgeDotte返回的個數(shù)是兩個的話那就是證明頂點在最外面的圓,假如是3個的話就畫出頂點之外和頂點之內(nèi)的線就可以了,代碼注釋已經(jīng)很詳細(xì)了,效果圖如下:
接著是畫虛線上的圓點,drawCircleHold(Canvas canvas)代碼如下:
//畫虛線上的圓點
public void drawCircleHold(Canvas canvas){
if(!lineWatchDag){
return;
}
float[] yuan1=calculatePoint(circleRadius-marginCircleSize*2);
float[] yuan2=calculatePoint(circleRadius-marginCircleSize);
float[] yuan3=calculatePoint(circleRadius);
//畫好友排名的圓點
drawCircleHoldImpl(-yuan1[0],-yuan1[1],-yuan2[0],-yuan2[1], -yuan3[0],-yuan3[1],mFriendDranking,canvas,friendColor);
//畫達(dá)標(biāo)天數(shù)的圓點
drawCircleHoldImpl(yuan1[0],-yuan1[1],yuan2[0],-yuan2[1], yuan3[0],-yuan3[1],mStandardDay,canvas,standardColor);
//畫平均步數(shù)的圓點 drawCircleHoldImpl(0,circleRadius-marginCircleSize*2,0,circleRadius-marginCircleSize, 0,circleRadius,mAverageCount,canvas,averageColor);
expainWatchDag=true;
}
//畫圓的具體的方法
public void drawCircleHoldImpl(float mCirlce1X,float mCircle1Y,float mCirlce2X,float mCircle2Y, float mCirlce3X,float mCircle3Y,int action,Canvas canvas,int color){
mCircleHoldPaint.setColor(color);
if(action==1){
//當(dāng)數(shù)值為3時畫所有圓圈 canvas.drawCircle(mCirlce1X,mCircle1Y,8,mCircleHoldPaint);
canvas.drawCircle(mCirlce2X,mCircle2Y,8,mCircleHoldPaint);
}else if(action==2){
//當(dāng)數(shù)值為2時畫中間的圓圈
canvas.drawCircle(mCirlce2X,mCircle2Y,8,mCircleHoldPaint);
}
//畫一定要畫的圓圈和圓點
canvas.drawCircle(mCirlce3X,mCircle3Y,8,mCircleHoldPaint);
mCircleHoldPaint.setColor(Color.WHITE);
canvas.drawCircle(mCirlce1X,mCircle1Y,6,mCircleHoldPaint);
canvas.drawCircle(mCirlce2X,mCircle2Y,6,mCircleHoldPaint);
canvas.drawCircle(mCirlce3X,mCircle3Y,6,mCircleHoldPaint);
}
這里同樣注釋也是很詳細(xì)的,整個思路就是通過calculatePoint()算出三個圓點的坐標(biāo),在通過傳進(jìn)去的數(shù)值來要畫多少個圓圈,而原點是不管數(shù)值多少都要畫的。效果圖如下:
接著就是畫解釋的內(nèi)容drawExpain(Canvas canvas)代碼如下:
//畫解釋的內(nèi)容
public void drawExpain(Canvas canvas){
if(!expainWatchDag){
return ;
}
//間隔 int margin=circleRadius/5;
//畫平均步數(shù)和對應(yīng)的數(shù)值
Rect txtRect=new Rect();
mCenterCircle.setColor(Color.BLACK);
mCenterCircle.setTextSize(circleRadius/6);
mCenterCircle.setTypeface(Typeface.SANS_SERIF);
canvas.drawText(averageCount,0,circleRadius+margin,mCenterCircle);
mCenterCircle.setColor(friendColor); mCenterCircle.setTextSize(circleRadius/10);
mCenterCircle.getTextBounds(averageCountTxt,0,averageCountTxt.length(),txtRect);
canvas.drawText(averageCountTxt,0,circleRadius+margin+(txtRect.bottom- txtRect.top),mCenterCircle);
//畫好友排名和對應(yīng)的數(shù)值
mCenterCircle.setColor(Color.BLACK);
mCenterCircle.setTextSize(circleRadius/6);
canvas.drawText(firendDrank,-circleRadius,-(circleRadius- marginCircleSize),mCenterCircle);
mCenterCircle.setColor(friendColor);
mCenterCircle.setTextSize(circleRadius/10);
mCenterCircle.getTextBounds(friendDrankTxt,0,friendDrankTxt.length(),txtRect);
canvas.drawText(friendDrankTxt,-circleRadius,-(circleRadius-marginCircleSize)+(txtRect.bottom-txtRect.top),mCenterCircle);
//畫達(dá)標(biāo)天數(shù)和對應(yīng)的數(shù)值
mCenterCircle.setColor(Color.BLACK);
mCenterCircle.setTextSize(circleRadius/6);
canvas.drawText(standarDay,circleRadius,-(circleRadius- marginCircleSize),mCenterCircle);
mCenterCircle.setColor(friendColor);
mCenterCircle.setTextSize(circleRadius/10);
mCenterCircle.getTextBounds(friendDrankTxt,0,friendDrankTxt.length(),txtRect);
canvas.drawText(standarDayTxt,circleRadius,-(circleRadius-marginCircleSize)+(txtRect.bottom-txtRect.top),mCenterCircle); centerWatchDag=true;
}
看起來代碼有點多,其實是最簡單的,就是確定好友排名的坐標(biāo)(-circleRadius,-(circleRadius-marginCircleSize)),int margin=circleRadius/5,平均步數(shù)的坐標(biāo)(0,circleRadius+margin),達(dá)標(biāo)天數(shù)的坐標(biāo)(circleRadius,-(circleRadius-marginCircleSize))來進(jìn)行drawText的操作而已,沒什么可以說的,Rect是得出字體大小的,具體看上面代碼。效果如下圖:
最后就是畫中心圓的內(nèi)容的centerCircleContent(canvas)了,代碼如下:
//畫中心圓的內(nèi)容
public void centerCircleContent(Canvas canvas){
if(!centerWatchDag){
return ;
}
//畫出顏色漸變的圓圈
canvas.rotate(140);
float centerSize=circleRadius-marginCircleSize*3-(circleRadius/20);
mCenterCircle.setShader(new SweepGradient(0,0,new int[]{ friendColor,friendColor,standardColor,averageColor},null));
canvas.drawCircle(0,0,centerSize,mCenterCircle);
canvas.rotate(-140);
//畫出運動的總步數(shù)
mCenterCircle.setShader(null);
mCenterCircle.setColor(friendColor);
mCenterCircle.setTextSize(circleRadius/4);
mCenterCircle.setTextAlign(Paint.Align.CENTER);
Rect numRect=new Rect();
mCenterCircle.getTextBounds(allStep,0,allStep.length(),numRect);
Camera camera=new Camera(); camera.rotateY(centerData);
camera.applyToCanvas(canvas);
canvas.drawText(allStep,0,(numRect.bottom-numRect.top)/2,mCenterCircle);
//畫出總運動步數(shù)右邊的字
Rect tipRect=new Rect();
mCenterCircle.setTextSize(circleRadius/12);
mCenterCircle.getTextBounds(tip,0,tip.length(),tipRect);
canvas.drawText(tip,(numRect.right-numRect.left)/2+(tipRect.right-tipRect.left)/2+5 ,(numRect.bottom-numRect.top)/2-3,mCenterCircle);
//畫出總運動步數(shù)下面的提示
Rect theyRect=new Rect();
mCenterCircle.getTextBounds(theyCount,0,theyCount.length(),theyRect);
float marginBottom=circleRadius/12;
mCenterCircle.setTextSize(circleRadius/11);
canvas.drawText(theyCount,0,marginBottom+(numRect.bottom-numRect.top)/2 +(theyRect.bottom-theyRect.top)/2,mCenterCircle);
}
中心圓的內(nèi)容里實現(xiàn)的大概思路畫解釋的內(nèi)容的思路都差不多,我覺得值得講的就是這個Camera類了,這里的Camera類可不是相機(jī)里的Camera類,他可以實現(xiàn)Camera的旋轉(zhuǎn)縮放的功能,是一個十分強(qiáng)大的類,而camera.rotateY(centerData)就是設(shè)置Y軸旋轉(zhuǎn)的效果的關(guān)鍵代碼。其次就是用mCenterCircle.setShader(new SweepGradient(0,0,new int[]{ friendColor,friendColor,standardColor,averageColor},null));來實現(xiàn)圓圈顏色的漸變功能的關(guān)鍵代碼,里面還可以實現(xiàn)更多效果,這就需要小伙伴們用外的時間學(xué)了。最后效果如下:
至此整個繪畫就結(jié)束了,接著就是動畫效果,代碼如下:
//啟動動畫的方法
public void loadAnimator(){
final ValueAnimator alphaAmimator3=ValueAnimator.ofInt(0,225);
final ValueAnimator alphaAmimator2=ValueAnimator.ofInt(0,225);
final ValueAnimator wavesAminator=ValueAnimator.ofInt(-30,0);
final ValueAnimator centerAnimator=ValueAnimator.ofFloat(0,360);
ValueAnimator alphaAmimator1=ValueAnimator.ofInt(0,225);
centerAnimator.setDuration(1000);
centerAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
centerData=(float)animation.getAnimatedValue(); postInvalidate();
}
});
wavesAminator.setDuration(1000);
wavesAminator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
waveData=(int)animation.getAnimatedValue();
waveWatchDag=true;
if(waveData==0&&lineWatchDag==false){
lineWatchDag=true; centerAnimator.start();
}
postInvalidate();
} });
alphaAmimator3.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { @Override
public void onAnimationUpdate(ValueAnimator animation) {
mCircleAlpha3=(int)animation.getAnimatedValue();
postInvalidate();
if(mCircleAlpha3==225){
wavesAminator.start();
}
}
});
alphaAmimator3.setDuration(250);
alphaAmimator2.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { @Override
public void onAnimationUpdate(ValueAnimator animation) {
mCircleAlpha2=(int)animation.getAnimatedValue();
postInvalidate();
if(mCircleAlpha2==225){
alphaAmimator3.start();
}
} });
alphaAmimator2.setDuration(250);
alphaAmimator1.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { @Override
public void onAnimationUpdate(ValueAnimator animation) {
mCircleAlpha1=(int)animation.getAnimatedValue(); postInvalidate();
if(mCircleAlpha1==225){
alphaAmimator2.start();
}
}
});
alphaAmimator1.setDuration(250);
alphaAmimator1.start();
}
其實就是通過ValueAnimator不斷的生成狀態(tài)量然后調(diào)用postInvalidate()不斷的刷新View即可實現(xiàn)。最后要想更詳細(xì)的了解整個流程請看源碼吧。
奉上源碼。如果對你有幫助就請給我給星星或喜歡吧