動(dòng)畫(huà)框架(1)-屬性動(dòng)畫(huà)基礎(chǔ)用法

主目錄見(jiàn):Android高級(jí)進(jìn)階知識(shí)(這是總目錄索引)
?其實(shí)講這篇有點(diǎn)虛,因?yàn)槲矣X(jué)得別人講的夠好了,但是增加這一篇就是提一下,免得下一篇講動(dòng)畫(huà)框架源碼會(huì)看不懂,當(dāng)然你如果非常熟悉用法了,那這一篇可以跳過(guò),完全沒(méi)有影響。

一.目標(biāo)

動(dòng)畫(huà)框架雖然簡(jiǎn)單,但是還是比較重要的,能起到畫(huà)龍點(diǎn)睛的作用,用戶卸不卸載你的app可能這會(huì)是最后一根稻草,所以厚臉皮重提一下:
1.復(fù)習(xí)下屬性動(dòng)畫(huà)用法;
2.為下一篇屬性動(dòng)畫(huà)源碼分析做基礎(chǔ)吧;

二.屬性動(dòng)畫(huà)

我們知道,屬性動(dòng)畫(huà)是安卓3.0之后引入的,自從引入屬性動(dòng)畫(huà),完全可以替代以前的動(dòng)畫(huà),而且大家也知道,擴(kuò)展性和改變屬性的這個(gè)特性決定了它更符合開(kāi)發(fā)的意愿,當(dāng)然我也不例外,這篇文章不會(huì)非常一個(gè)一個(gè)字摳,會(huì)列出知識(shí)點(diǎn),不詳細(xì)敬請(qǐng)?jiān)彙?/p>

1.知識(shí)點(diǎn)鋪墊

1)ValueAnimator:包含了屬性動(dòng)畫(huà)的核心功能,動(dòng)畫(huà)時(shí)間,開(kāi)始和結(jié)束屬性值計(jì)算方法等,這個(gè)類也是屬性動(dòng)畫(huà)的基類。
2)ObjectAnimator:繼承自ValueAnimator,其實(shí)如果要改變一個(gè)事物的某個(gè)屬性變化會(huì)比較經(jīng)常用到這個(gè)方法。
3)AnimationSet:用于組合多個(gè)動(dòng)畫(huà)的,可以設(shè)置要組合動(dòng)畫(huà)的時(shí)序關(guān)系。
4)TypeEvalutors:都是翻譯成估值器,其實(shí)就是計(jì)算下一個(gè)運(yùn)動(dòng)到的值的類(根據(jù)動(dòng)畫(huà)的開(kāi)始和結(jié)束還有TimeInterpolation計(jì)算出當(dāng)前時(shí)間的屬性值)
5)TimeInterplator:這個(gè)翻譯都是插值器,他是一個(gè)描述運(yùn)動(dòng)變化的方式,如勻速運(yùn)動(dòng),加速運(yùn)動(dòng)或者先加速后減速等,他有很多子類,待會(huì)會(huì)介紹。
6)ViewPropertyAnimator:這個(gè)類其實(shí)就是對(duì)View做屬性動(dòng)畫(huà)的一個(gè)簡(jiǎn)略版,有些情況用到這個(gè)會(huì)簡(jiǎn)單很多。

2.ValueAnimator

這個(gè)方法用法很簡(jiǎn)單,我們來(lái)看一下我們寫(xiě)的代碼:

  ValueAnimator valueAnimator = ValueAnimator.ofFloat(0f,10f);
                valueAnimator.setDuration(1000);
                valueAnimator.addListener(new AnimatorListenerAdapter() {
                    @Override
                    public void onAnimationEnd(Animator animation) {
                        Log.e(TAG,"動(dòng)畫(huà)結(jié)束了");
                    }
                });
                valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
                    @Override
                    public void onAnimationUpdate(ValueAnimator valueAnimator) {
                            float animatorValue = (float) valueAnimator.getAnimatedValue();
                            Log.e(TAG,"當(dāng)前動(dòng)畫(huà)值是"+animatorValue);
                    }
                });
                valueAnimator.start();

我們看到我們動(dòng)畫(huà)首先用到ofFloat方法,其實(shí)ValueAnimator還有很多類似的方法:


of系列方法

這類方法可以設(shè)置多個(gè)值,我們看到參數(shù)是可變類型參數(shù),然后我們可以添加監(jiān)聽(tīng)接口,我們第一個(gè)監(jiān)聽(tīng)用到了AnimatorListenerAdapter,這個(gè)適配器會(huì)讓我們選擇實(shí)現(xiàn)我們想實(shí)現(xiàn)的方法,不然會(huì)讓我們?nèi)慷紝?shí)現(xiàn),有些我們方法沒(méi)用到導(dǎo)致沒(méi)用代碼太多。下一個(gè)監(jiān)聽(tīng)AnimatorUpdateListener是用來(lái)監(jiān)聽(tīng)動(dòng)畫(huà)改變過(guò)程的,只要?jiǎng)赢?huà)值有變化都會(huì)回調(diào)這個(gè)監(jiān)聽(tīng)。最后我們只要start啟動(dòng)就可以了。我們的打印如下,這個(gè)截圖不是很完全,湊合著看:

動(dòng)畫(huà)執(zhí)行過(guò)程

3.ObjectAnimator

這個(gè)類主要用來(lái)改變視圖的屬性值,記住這里是屬性值,只要這個(gè)屬性對(duì)應(yīng)的setter方法正確就可以改變:

   ObjectAnimator objectAnimator = ObjectAnimator.ofFloat(tvAlpha,"alpha",1f,0f,1f);
                objectAnimator.setDuration(1000);
                objectAnimator.start();

我們這里用透明度來(lái)使用這個(gè)類,其中第二個(gè)屬性名必須是第一個(gè)參數(shù)View中有對(duì)應(yīng)的setter方法的,不然不會(huì)有效果,我們的效果如下:


改變透明度

當(dāng)然這個(gè)類也可以監(jiān)聽(tīng),因?yàn)檫@個(gè)類是ValueAnimator的子類,所以ValueAnimator有的他也有,這里就不詳細(xì)說(shuō)了。

3.AnimationSet

這個(gè)類主要用來(lái)組合幾個(gè)動(dòng)畫(huà)的,而且這個(gè)類可以控制執(zhí)行時(shí)序,我們還是用那個(gè)改變透明度的例子,然后加上旋轉(zhuǎn)最后執(zhí)行下移:

ObjectAnimator alphaAnimator = ObjectAnimator.ofFloat(tvAlpha,"alpha",1f,0f,1f);
                ObjectAnimator rotationAnimator = ObjectAnimator.ofFloat(tvAlpha,"rotation",0f,360f);
                ObjectAnimator translateYAnimator = ObjectAnimator.ofFloat(tvAlpha,"translationY",0f,700f,0f);
                AnimatorSet animatorSet = new AnimatorSet();
                animatorSet.play(alphaAnimator).with(rotationAnimator).before(translateYAnimator);
                animatorSet.addListener(new AnimatorListenerAdapter() {
                    @Override
                    public void onAnimationEnd(Animator animation) {
                        Log.e(TAG,"動(dòng)畫(huà)結(jié)束了");
                    }
                });
                animatorSet.setDuration(1000);
                animatorSet.start();

這個(gè)類就是先得到多個(gè)ObjectAnimator對(duì)象,然后用play(),with(),before(),after()方法來(lái)設(shè)置動(dòng)畫(huà)執(zhí)行的次序,這個(gè)類也有動(dòng)畫(huà)監(jiān)聽(tīng)可以監(jiān)聽(tīng)開(kāi)始,結(jié)束等等事件,但是沒(méi)有AnimatorUpdateListener這個(gè)監(jiān)聽(tīng),想想也知道,這是幾個(gè)動(dòng)畫(huà)的集合,所以變化值要讓它為啥呢?明顯不合理。


AnimationSet

4.TypeEvalutors

這是估值器,系統(tǒng)里面其實(shí)內(nèi)置了很多的估值器,如果不知道怎么寫(xiě)其實(shí)可以去參考(PointFEvaluator,ArgbEvaluator,F(xiàn)loatEvaluator,IntEvaluator等等自己可以查看)。今天我們這里自定義一個(gè)View然后添加一個(gè)自定義的估值器來(lái)改變位置。其實(shí)這個(gè)地方很多人也都講過(guò),如果你已經(jīng)看過(guò)請(qǐng)略過(guò):

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 void setX(float x) {
        this.x = x;
    }

    public float getY() {
        return y;
    }

    public void setY(float y) {
        this.y = y;
    }
}

首先自定義一個(gè)Point類用來(lái)存儲(chǔ)x和y軸的值。用來(lái)等會(huì)改變視圖的位置。然后我們看下自定義的視圖:

public class TypeEvaluatorView extends View{
    private static final float RADIUS = 50f;
    private Paint mPaint;

    private Point currentPoint;

    public TypeEvaluatorView(Context context, @Nullable AttributeSet attrs) {
        super(context, attrs);

        mPaint = new Paint();
        mPaint.setAntiAlias(true);
        mPaint.setColor(Color.RED);
    }

    @Override
    protected void onDraw(Canvas canvas) {
        if (null == currentPoint){
            currentPoint = new Point(300,300);
        }
        drawBall(canvas);
    }

    private void drawBall(Canvas canvas){
        canvas.drawCircle(currentPoint.getX(),currentPoint.getY(),RADIUS,mPaint);
    }

    public void startAnimation(){
        Point endPoint = new Point(getWidth() - RADIUS,getHeight() - RADIUS);
        ValueAnimator valueAnimator = ValueAnimator.ofObject(new PointEvaluator(),currentPoint,endPoint);
        valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
            @Override
            public void onAnimationUpdate(ValueAnimator valueAnimator) {
                currentPoint = (Point) valueAnimator.getAnimatedValue();
                invalidate();
            }
        });
        valueAnimator.setDuration(2000);
        valueAnimator.start();
    }
}

我們看到首先我們根據(jù)一個(gè)currentPoint來(lái)draw一個(gè)圓形,這個(gè)圓形位置就是currentPoint對(duì)應(yīng)的x和y軸的值,然后我們?cè)趕tartAnimation就可以改變這個(gè)currentPoint的值。這里面我們用到我們自己自定義的估值器,我們看下:

public class PointEvaluator implements TypeEvaluator<Point> {
    @Override
    public Point evaluate(float fraction, Point startPoint, Point endPoint) {
        float x = startPoint.getX() + fraction * (endPoint.getX()- startPoint.getX());
        float y = startPoint.getY() + fraction * (endPoint.getY() - startPoint.getY());
        return new Point(x,y);
    }
}

這個(gè)非常簡(jiǎn)單,其實(shí)就是根據(jù)fraction來(lái)計(jì)算當(dāng)前的位置Point,其實(shí)看下內(nèi)置的幾個(gè)估值器很明白。

自定義估值器

5.TimeInterplator

估值器講完了,我們來(lái)講插值器,這兩個(gè)東西其實(shí)不難理解,估值器里面的fraction其實(shí)會(huì)受到差值器的影響,也就是說(shuō)差值器會(huì)影響估值器計(jì)算出來(lái)的結(jié)果值,差值器有很多:


插值器

這些都是繼承的TimeInterplator,我們就選擇其中一種先加速再減速的插值器來(lái)演示一下:

   Point endPoint = new Point(getWidth() - RADIUS,getHeight() - RADIUS);
        ValueAnimator valueAnimator = ValueAnimator.ofObject(new PointEvaluator(),currentPoint,endPoint);
        valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
            @Override
            public void onAnimationUpdate(ValueAnimator valueAnimator) {
                currentPoint = (Point) valueAnimator.getAnimatedValue();
                invalidate();
            }
        });
        valueAnimator.setInterpolator(new AccelerateDecelerateInterpolator());
        valueAnimator.setDuration(2000);
        valueAnimator.start();

很簡(jiǎn)單,直接設(shè)置進(jìn)去就可以了,如果你要自己定義插值器,可以參考系統(tǒng)已經(jīng)有的差值器進(jìn)行自定義。

添加插值器

你看好像沒(méi)啥區(qū)別,那是因?yàn)橄到y(tǒng)默認(rèn)的就是這個(gè)插值器,所以感覺(jué)沒(méi)啥變化。尷尬。。。。

6.ViewPropertyAnimator

這個(gè)更簡(jiǎn)單,因?yàn)楫吘咕褪菫榱藢?xiě)法簡(jiǎn)單才創(chuàng)造的嘛,我們就簡(jiǎn)單看下:

 tevTypeEvaluator.animate().x(600).y(600).alpha(0.7f).setDuration(1000).start();

有沒(méi)有看到,先調(diào)用下animate()方法然后直接設(shè)置要改變的屬性的值就可以了,so so so easy!所以我們?nèi)绻苡眠@種寫(xiě)法的可以用這種寫(xiě)法,簡(jiǎn)單有木有。

ViewPropertyAnimator

到這里已經(jīng)簡(jiǎn)單介紹完了,知識(shí)還是非常簡(jiǎn)單的,就是在實(shí)際應(yīng)用中多體驗(yàn)體驗(yàn)就可以。
總結(jié):之前都是分析的源碼內(nèi)容,會(huì)比較枯燥,這里就先講一下基礎(chǔ)用法,然后接下來(lái)一篇我們來(lái)分析屬性動(dòng)畫(huà)的源代碼,這篇就當(dāng)做放松放松了。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

推薦閱讀更多精彩內(nèi)容