前言:
安卓里面由于補(bǔ)間動(dòng)畫,只是變化的是視圖的內(nèi)容换衬,但是屬性的話痰驱,是沒有變的证芭,就是以前大家在使用動(dòng)畫的時(shí)候,如果在tagView(目標(biāo)視圖)上設(shè)置了監(jiān)聽事件担映,但是废士,當(dāng)tagView在移動(dòng)的時(shí)候,點(diǎn)擊事件還在原位置蝇完,這樣很不方便官硝,后面在API3.0以后就新增了屬性動(dòng)畫,很好的解決了以上問題短蜕,而且新增的功能還可以擴(kuò)展很多的動(dòng)畫效果氢架,下面就先來說說ValueAnimator的重要性
分析:
動(dòng)畫,簡單來說就是在一段時(shí)間里面進(jìn)行一系列視圖的變化朋魔,也就是必須有一定的過程岖研,在數(shù)學(xué)里面也是就時(shí)間段,而不是時(shí)間刻警检,(小裝個(gè)逼缎玫,嘻嘻!)
一解滓、ValueAnimator(非常重要的):
1.首先ValueAnimator繼承于父類的Animator,而它的實(shí)現(xiàn)子類ObjectAnimator以及TimeAnimator,暫時(shí)這里先不說這兩個(gè)子類
2.學(xué)習(xí)新的類筝家,肯定要先了解其API的使用:
ValueAnimator valueAnimator = ValueAnimator.ofInt(0, 1);
valueAnimator.setEvaluator();//設(shè)置評(píng)估者
valueAnimator.setRepeatCount();//設(shè)置動(dòng)畫重復(fù)的次數(shù)
valueAnimator.setInterpolator();//設(shè)置動(dòng)畫的插值器洼裤;也就是動(dòng)畫如何變化,就像速度的描述加速度一樣
valueAnimator.setDuration();//動(dòng)畫的時(shí)間
valueAnimator.setStartDelay();//動(dòng)畫在開始之前延遲多少
valueAnimator.setRepeatMode();//動(dòng)畫重復(fù)的方式溪王;RESTART:開始-結(jié)束 開始-結(jié)束腮鞍;REVERSE:開始-結(jié)束-開始
valueAnimator.addListener();//動(dòng)畫的監(jiān)聽
valueAnimator.addUpdateListener();//動(dòng)畫屬性值更新的監(jiān)聽
二、ValueAnimator的重要使用:
1.setEvaluator()的方法:
public class IntEvaluator implements TypeEvaluator<Integer> {
public Integer evaluate(float fraction, Integer startValue, Integer endValue)
{
int startInt = startValue;
return (int)(startInt + fraction * (endValue - startInt));
}
}
里面有三個(gè)參數(shù):
- fraction:這個(gè)值是由插值器返回的一個(gè)百分比的數(shù)值莹菱,范圍0~1之間
- startValue:起始值
- endValue:結(jié)束值
這個(gè)評(píng)估者的類里面就是返回一個(gè)一直在疊加的值移国,也就是一段時(shí)間里面變化的值,如果能得到這個(gè)值道伟,是不是很多的動(dòng)畫效果就迎刃而解了迹缀,因?yàn)閂iew變化的時(shí)候,其實(shí)就是時(shí)期位置在一段時(shí)間里面不斷的變化蜜徽,當(dāng)間隔小于肉眼所感知的崢祝懂,就認(rèn)為是在動(dòng)
2.addUpdateListener();這個(gè)方法就是監(jiān)聽動(dòng)畫在動(dòng)的過程中的回調(diào),那么這里面應(yīng)該有我們想要的東西
valueAnimator.addUpdateListener(new
ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
Object animatedValue = animation.getAnimatedValue();//這個(gè)不正式我們上面?zhèn)鞯? 值嗎
//在這里面我們是不是可以設(shè)置View的透明度拘鞋,平移砚蓬,旋轉(zhuǎn),以及放大盆色,其實(shí)一段時(shí)間里面這還可以變換顏色
}
});
3.當(dāng)然顏色變換的評(píng)估者系統(tǒng)已經(jīng)給大家定義好了:
public class ArgbEvaluator implements TypeEvaluator {
public Object evaluate(float fraction, Object startValue, Object endValue) {
int startInt = (Integer) startValue;
int startA = (startInt >> 24);
int startR = (startInt >> 16) & 0xff;
int startG = (startInt >> 8) & 0xff;
int startB = startInt & 0xff;
int endInt = (Integer) endValue;
int endA = (endInt >> 24);
int endR = (endInt >> 16) & 0xff;
int endG = (endInt >> 8) & 0xff;
int endB = endInt & 0xff;
return (int)((startA + (int)(fraction * (endA - startA))) << 24) |
(int)((startR + (int)(fraction * (endR - startR))) << 16) |
(int)((startG + (int)(fraction * (endG - startG))) << 8) |
(int)((startB + (int)(fraction * (endB - startB))));
}
}
大家要做變背景色的效果是不是很簡單就可以實(shí)現(xiàn)
三灰蛙、ValueAnimator的高級(jí)用法
對(duì)一個(gè)Point作用:
public class Point {
private float x;
private float y;
public Point(float x, float y) {
this.x = x;
this.y = y;
}
public float getX() {
return x;
}
public float getY() {
return y;
}
}
Point類非常簡單祟剔,只有x和y兩個(gè)變量用于記錄坐標(biāo)的位置,并提供了構(gòu)造方法來設(shè)置坐標(biāo)摩梧,以及get方法來獲取坐標(biāo)物延。接下來定義PointEvaluator,如下所示:
public class PointEvaluator implements TypeEvaluator{
@Override
public Object evaluate(float fraction, Object startValue, Object endValue) {
Point startPoint = (Point) startValue;
Point endPoint = (Point) endValue;
float x = startPoint.getX() + fraction * (endPoint.getX() - startPoint.getX());
float y = startPoint.getY() + fraction * (endPoint.getY() - startPoint.getY());
Point point = new Point(x, y);
return point;
}
}
可以看到障本,PointEvaluator同樣實(shí)現(xiàn)了TypeEvaluator接口并重寫了evaluate()方法教届。其實(shí)evaluate()方法中的邏輯還是非常簡單的,先是將startValue和endValue強(qiáng)轉(zhuǎn)成Point對(duì)象驾霜,然后同樣根據(jù)fraction來計(jì)算當(dāng)前動(dòng)畫的x和y的值案训,最后組裝到一個(gè)新的Point對(duì)象當(dāng)中并返回。
這樣我們就將PointEvaluator編寫完成了粪糙,接下來我們就可以非常輕松地對(duì)Point對(duì)象進(jìn)行動(dòng)畫操作了强霎,比如說我們有兩個(gè)Point對(duì)象,現(xiàn)在需要將Point1通過動(dòng)畫平滑過度到Point2蓉冈,就可以這樣寫:
Point point1 = new Point(0, 0);
Point point2 = new Point(300, 300);
ValueAnimator anim = ValueAnimator.ofObject(new PointEvaluator(), point1, point2);
anim.setDuration(5000);
anim.start();
代碼很簡單城舞,這里我們先是new出了兩個(gè)Point對(duì)象,并在構(gòu)造函數(shù)中分別設(shè)置了它們的坐標(biāo)點(diǎn)寞酿。然后調(diào)用ValueAnimator的ofObject()方法來構(gòu)建ValueAnimator的實(shí)例家夺,這里需要注意的是,ofObject()方法要求多傳入一個(gè)TypeEvaluator參數(shù)伐弹,這里我們只需要傳入剛才定義好的PointEvaluator的實(shí)例就可以了拉馋。
好的,這就是自定義TypeEvaluator的全部用法惨好,掌握了這些知識(shí)之后煌茴,我們就可以來嘗試一下如何通過對(duì)Point對(duì)象進(jìn)行動(dòng)畫操作,從而實(shí)現(xiàn)整個(gè)自定義View的動(dòng)畫效果日川。
新建一個(gè)MyAnimView繼承自View蔓腐,代碼如下所示:
public class MyAnimView extends View {
public static final float RADIUS = 50f;
private Point currentPoint;
private Paint mPaint;
public MyAnimView(Context context, AttributeSet attrs) {
super(context, attrs);
mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
mPaint.setColor(Color.BLUE);
}
@Override
protected void onDraw(Canvas canvas) {
if (currentPoint == null) {
currentPoint = new Point(RADIUS, RADIUS);
drawCircle(canvas);
startAnimation();
} else {
drawCircle(canvas);
}
}
private void drawCircle(Canvas canvas) {
float x = currentPoint.getX();
float y = currentPoint.getY();
canvas.drawCircle(x, y, RADIUS, mPaint);
}
private void startAnimation() {
Point startPoint = new Point(RADIUS, RADIUS);
Point endPoint = new Point(getWidth() - RADIUS, getHeight() - RADIUS);
ValueAnimator anim = ValueAnimator.ofObject(new PointEvaluator(), startPoint, endPoint);
anim.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
currentPoint = (Point) animation.getAnimatedValue();
invalidate();
}
});
anim.setDuration(5000);
anim.start();
}
}
基本上還是很簡單的,總共也沒幾行代碼龄句。首先在自定義View的構(gòu)造方法當(dāng)中初始化了一個(gè)Paint對(duì)象作為畫筆回论,并將畫筆顏色設(shè)置為藍(lán)色,接著在onDraw()方法當(dāng)中進(jìn)行繪制分歇。這里我們繪制的邏輯是由currentPoint這個(gè)對(duì)象控制的透葛,如果currentPoint對(duì)象不等于空,那么就調(diào)用drawCircle()方法在currentPoint的坐標(biāo)位置畫出一個(gè)半徑為50的圓卿樱,如果currentPoint對(duì)象是空僚害,那么就調(diào)用startAnimation()方法來啟動(dòng)動(dòng)畫。
那么我們來觀察一下startAnimation()方法中的代碼,其實(shí)大家應(yīng)該很熟悉了萨蚕,就是對(duì)Point對(duì)象進(jìn)行了一個(gè)動(dòng)畫操作而已靶草。這里我們定義了一個(gè)startPoint和一個(gè)endPoint,坐標(biāo)分別是View的左上角和右下角岳遥,并將動(dòng)畫的時(shí)長設(shè)為5秒奕翔。然后有一點(diǎn)需要大家注意的,就是我們通過監(jiān)聽器對(duì)動(dòng)畫的過程進(jìn)行了監(jiān)聽浩蓉,每當(dāng)Point值有改變的時(shí)候都會(huì)回調(diào)onAnimationUpdate()方法派继。在這個(gè)方法當(dāng)中,我們對(duì)currentPoint對(duì)象進(jìn)行了重新賦值捻艳,并調(diào)用了invalidate()方法驾窟,這樣的話onDraw()方法就會(huì)重新調(diào)用,并且由于currentPoint對(duì)象的坐標(biāo)已經(jīng)改變了认轨,那么繪制的位置也會(huì)改變绅络,于是一個(gè)平移的動(dòng)畫效果也就實(shí)現(xiàn)了。
下面我們只需要在布局文件當(dāng)中引入這個(gè)自定義控件:
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
>
<com.example.tony.myapplication.MyAnimView
android:layout_width="match_parent"
android:layout_height="match_parent" />
</RelativeLayout>
總結(jié):有時(shí)候大家可能對(duì)一些動(dòng)畫可能很沒有頭緒嘁字,也可能是一些屬性變化沒有什么頭緒恩急,希望鄙人上面所講的會(huì)對(duì)你有更大的幫助,你只要知道了思想才可能纪蜒,應(yīng)對(duì)更對(duì)的可能
注意:因?yàn)閷傩詣?dòng)畫是API3.0以后的屬性衷恭;所以在GitHub有大神給出來兼容的屬性動(dòng)畫:只要在AS里面依賴:
compile 'com.nineoldandroids:library:2.4.0'