最近看到幾篇自定義View和動畫效果的文章,于是想自己抽幾個練練手放吩,主要是鞏固和分析一下智听,加深自定義view和viewgroup流程。
58同城頁面加載動畫:
一.分析
需求如上圖渡紫。先觀察一下到推,這個動畫可以分為三部分:第一部分是三角形,圓形和矩形在做同樣一個平移動畫惕澎,第二部分是做縮放動畫的陰影莉测,第三是不動的文字部分。
這個效果有很多種實現(xiàn)方式集灌,今天主要研究自定義VIEW怎么去實現(xiàn)主體部分的動畫悔雹。
動畫的主體部分是這個一直在變形狀并上下平移的部分复哆,先不管陰影和文字。仔細觀察腌零,這部分一直在做同一組動畫梯找,那么我們只需要在動畫的某個臨界點改變它的形狀即可,再深入一點益涧,如果用自定view 锈锤,只需要在這個臨界點重新draw一個形狀即可,即調用invalidate()闲询,在onDraw()里面判斷畫圓形久免,三角形還是矩形。
在這里扭弧,我們將三角形阎姥,圓形和矩形看成同一個view,這個view平移到底部后然后彈回去時改變了形狀然后重復這一過程。作者在這兒采用的是屬性動畫ObjectAnimation去實現(xiàn)的平移鸽捻,只需要作出向下平移的這段動畫即可呼巴,彈回去這段可以調用setRepeatMode(ObjectAnimator.REVERSE)讓其重復時反向即可,臨界點的操作可以到AnimatorListener里面去做御蒲。
二.主要代碼部分
1.自定義一個View,先畫出圖形衣赶,設置枚舉狀態(tài)
private Paint paint=newPaint(Paint.ANTI_ALIAS_FLAG);//到構造方法初始化,此處省略
private int width;
private float height;
private boolean isFirst=true;//第一次invalidate()
private int radius;//圓半徑
private int mcount=1;//累加動畫重復次數
privateViewShapemshape=ViewShape.CIRCLE厚满;//默認圓形
@Override
protected voidonSizeChanged(intw, inth, intoldw, intoldh) {
super.onSizeChanged(w,h,oldw,oldh);
width=(float)w;//
height=(float) h;
radius=width/20;
doAnimation();//動畫
}
//繪制
@Override
protected voidonDraw(Canvas canvas) {
super.onDraw(canvas);
if(mshape==ViewShape.CIRCLE) {//圓形
paint.setColor(Color.BLUE);
canvas.drawCircle(width/2,height/4,radius,paint);
}else if(mshape==ViewShape.TRIANGLE){//三角形府瞄,用Path繪制,需要計算坐標
paint.setColor(Color.GREEN);
Path path=newPath();
path.moveTo(width/2,height/4-radius);
path.lineTo(width/2-radius,height/4+radius);
path.lineTo(width/2+radius,height/4+radius);
canvas.drawPath(path,paint);
}else{//矩形
paint.setColor(Color.RED);
canvas.drawRect(width/2-radius,height/4-radius,width/2+radius,height/4+radius,paint);
}}
//列出枚舉
public enum ViewShape{
CIRCLE,RANGE,TRIANGLE
}
2.動畫效果碘箍,以及設置監(jiān)聽去改變枚舉狀態(tài)
private void doAnimation(){
ObjectAnimator anim=ObjectAnimator.ofFloat(this,"translationY",0f,height-height/3);
anim.setInterpolator(newAccelerateInterpolator());
anim.setDuration(800);
anim.setRepeatMode(ObjectAnimator.REVERSE);
anim.setRepeatCount(ObjectAnimator.INFINITE);
anim.start();
anim.addListener(newAnimator.AnimatorListener() {
@Override
public voidonAnimationRepeat(Animator animation) {//只需要在重復監(jiān)聽里操作即可
if(isFirst){
isFirst=false;
}else{
if(mcount%2==0){//判斷彈上去的時候遵馆,圖形并沒有發(fā)生變化
if(mshape==ViewShape.CIRCLE){//改變枚舉狀態(tài)
mshape=ViewShape.TRIANGLE;
}else if(mshape==ViewShape.TRIANGLE){
mshape=ViewShape.RANGE;
}else{
mshape=ViewShape.CIRCLE;
}
}
}
mcount++;//累加用于判斷
invalidate();
}
});
}
這里我調用控件時設置的控件寬高均為matchParent,效果如下
The end
ok敲街,今天實現(xiàn)的效果就到這里团搞,關于陰影部分:可以看到它在view下落的時候縮小,彈回去變大多艇,實現(xiàn)思路基本差不多。這樣寫完還不能用像吻,需要進一步的去做屏幕適配和性能優(yōu)化峻黍,但是大概的流程我們已經清楚了。
關于一些思考問題:1.onDraw()的canvas在調用invalidate()之后和原來相比并不是同一個拨匆,原因在哪?
2.view的繪制流程姆涩,onSizeChanged()
哈哈,發(fā)現(xiàn)問題請多反饋惭每。