Android属性动画 TypeEvaluator
轉(zhuǎn)載請標(biāo)明出處:http://blog.csdn.net/zhaoyanjun6/article/details/118913435
本文出自【趙彥軍的博客】
文章目錄
- TypeEvaluator
TypeEvaluator
那么TypeEvaluator的作用到底是什么呢?
簡單來說,就是告訴動(dòng)畫系統(tǒng)如何從初始值過度到結(jié)束值。
我們在上一篇文章中學(xué)到的ValueAnimator.ofFloat()方法就是實(shí)現(xiàn)了初始值與結(jié)束值之間的平滑過度,那么這個(gè)平滑過度是怎么做到的呢?其實(shí)就是系統(tǒng)內(nèi)置了一個(gè)FloatEvaluator,它通過計(jì)算告知?jiǎng)赢嬒到y(tǒng)如何從初始值過度到結(jié)束值,我們來看一下FloatEvaluator的代碼實(shí)現(xiàn):
public class FloatEvaluator implements TypeEvaluator {public Object evaluate(float fraction, Object startValue, Object endValue) {float startFloat = ((Number) startValue).floatValue();return startFloat + fraction * (((Number) endValue).floatValue() - startFloat);} }可以看到,FloatEvaluator實(shí)現(xiàn)了TypeEvaluator接口,然后重寫evaluate()方法。
evaluate()方法當(dāng)中傳入了三個(gè)參數(shù),第一個(gè)參數(shù)fraction非常重要,這個(gè)參數(shù)用于表示動(dòng)畫的完成度的,我們應(yīng)該根據(jù)它來計(jì)算當(dāng)前動(dòng)畫的值應(yīng)該是多少,第二第三個(gè)參數(shù)分別表示動(dòng)畫的初始值和結(jié)束值。那么上述代碼的邏輯就比較清晰了,用結(jié)束值減去初始值,算出它們之間的差值,然后乘以fraction這個(gè)系數(shù),再加上初始值,那么就得到當(dāng)前動(dòng)畫的值了。
好的,那FloatEvaluator是系統(tǒng)內(nèi)置好的功能,并不需要我們自己去編寫,但介紹它的實(shí)現(xiàn)方法是要為我們后面的功能鋪路的。前面我們使用過了ValueAnimator的ofFloat()和ofInt()方法,分別用于對浮點(diǎn)型和整型的數(shù)據(jù)進(jìn)行動(dòng)畫操作的,但實(shí)際上ValueAnimator中還有一個(gè)ofObject()方法,是用于對任意對象進(jìn)行動(dòng)畫操作的。
但是相比于浮點(diǎn)型或整型數(shù)據(jù),對象的動(dòng)畫操作明顯要更復(fù)雜一些,因?yàn)橄到y(tǒng)將完全無法知道如何從初始對象過度到結(jié)束對象,因此這個(gè)時(shí)候我們就需要實(shí)現(xiàn)一個(gè)自己的TypeEvaluator來告知系統(tǒng)如何進(jìn)行過度。
下面來先定義一個(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{@Overridepublic 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對象,然后同樣根據(jù)fraction來計(jì)算當(dāng)前動(dòng)畫的x和y的值,最后組裝到一個(gè)新的Point對象當(dāng)中并返回。
這樣我們就將PointEvaluator編寫完成了,接下來我們就可以非常輕松地對Point對象進(jìn)行動(dòng)畫操作了,比如說我們有兩個(gè)Point對象,現(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對象,并在構(gòu)造函數(shù)中分別設(shè)置了它們的坐標(biāo)點(diǎn)。然后調(diào)用ValueAnimator的ofObject()方法來構(gòu)建ValueAnimator的實(shí)例,這里需要注意的是,ofObject()方法要求多傳入一個(gè)TypeEvaluator參數(shù),這里我們只需要傳入剛才定義好的PointEvaluator的實(shí)例就可以了。
好的,這就是自定義TypeEvaluator的全部用法,掌握了這些知識(shí)之后,我們就可以來嘗試一下如何通過對Point對象進(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);}@Overrideprotected 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() {@Overridepublic void onAnimationUpdate(ValueAnimator animation) {currentPoint = (Point) animation.getAnimatedValue();invalidate();}});anim.setDuration(5000);anim.start();}}基本上還是很簡單的,總共也沒幾行代碼。首先在自定義View的構(gòu)造方法當(dāng)中初始化了一個(gè)Paint對象作為畫筆,并將畫筆顏色設(shè)置為藍(lán)色,接著在onDraw()方法當(dāng)中進(jìn)行繪制。
這里我們繪制的邏輯是由currentPoint這個(gè)對象控制的,如果currentPoint對象不等于空,那么就調(diào)用drawCircle()方法在currentPoint的坐標(biāo)位置畫出一個(gè)半徑為50的圓,如果currentPoint對象是空,那么就調(diào)用startAnimation()方法來啟動(dòng)動(dòng)畫。
那么我們來觀察一下startAnimation()方法中的代碼,其實(shí)大家應(yīng)該很熟悉了,就是對Point對象進(jìn)行了一個(gè)動(dòng)畫操作而已。這里我們定義了一個(gè)startPoint和一個(gè)endPoint,坐標(biāo)分別是View的左上角和右下角,并將動(dòng)畫的時(shí)長設(shè)為5秒。然后有一點(diǎn)需要大家注意的,就是我們通過監(jiān)聽器對動(dòng)畫的過程進(jìn)行了監(jiān)聽,每當(dāng)Point值有改變的時(shí)候都會(huì)回調(diào)onAnimationUpdate()方法。
在這個(gè)方法當(dāng)中,我們對currentPoint對象進(jìn)行了重新賦值,并調(diào)用了invalidate()方法,這樣的話onDraw()方法就會(huì)重新調(diào)用,并且由于currentPoint對象的坐標(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.MyAnimViewandroid:layout_width="match_parent"android:layout_height="match_parent" /></RelativeLayout>最后運(yùn)行一下程序,效果如下圖所示:
OK!這樣我們就成功實(shí)現(xiàn)了通過對對象進(jìn)行值操作來實(shí)現(xiàn)動(dòng)畫效果的功能,這就是ValueAnimator的高級(jí)用法。
總結(jié)
以上是生活随笔為你收集整理的Android属性动画 TypeEvaluator的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Android属性动画 XML
- 下一篇: Android属性动画 Property