Android動畫之幀動畫,補間動畫和屬性動畫

Android動畫基本上可以分為視圖動畫和屬性動畫,視圖動畫包括幀動畫和補間動畫。

一.概述

通過本篇文章的學習,你將學會:
1.如何使用幀動畫
2.如何使用補間動畫
3.如何使用屬性動畫

二.幀動畫

幀動畫就是按照順序播放一幀一幀的照片達到動畫的效果。我們可以看一下實現(xiàn)過程:
在drawable目錄下新建frame_list.xml:

<?xml version="1.0" encoding="utf-8"?>
<animation-list xmlns:android="http://schemas.android.com/apk/res/android"
    android:oneshot="false">
    <item
        android:drawable="@mipmap/a_0"
        android:duration="100" />
    <item
        android:drawable="@mipmap/a_1"
        android:duration="100" />
    <item
        android:drawable="@mipmap/a_2"
        android:duration="100" />
</animation-list>
<!--oneshot表示是否只播放一次,默認false-->

在activity用兩個按鈕來啟動動畫和暫停動畫:

    Button bt_start, bt_stop;
    ImageView iv;
    AnimationDrawable animationDrawable;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_frame);
        bt_start = (Button) findViewById(R.id.bt_start);
        bt_stop = (Button) findViewById(R.id.bt_stop);
        iv = (ImageView) findViewById(R.id.iv);
        iv.setImageResource(R.drawable.frame_list);
        animationDrawable = (AnimationDrawable) iv.getDrawable();
        bt_start.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                //啟動幀動畫
                animationDrawable.start();
            }
        });
        bt_stop.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                //暫停幀動畫
                animationDrawable.stop();
            }
        });
    }

幀動畫使用簡單方便,但是注意在比較復雜的時候圖片比較多的時候容易發(fā)生oom,因此盡量避免使用尺寸較大的圖片。

三.補間動畫

補間動畫是通過確定視圖開始和結束的樣式,然后中間的樣式由系統(tǒng)進行補全形成。但是它只是去改變了視覺效果,并不會改變控件本身的屬性。補間動畫包括基本的平移動畫,縮放動畫,旋轉動畫和透明度動畫,我們也可以將這些基本動畫進行組合在一起。
所有的補間動畫共有的屬性:
duration:動畫時長
startOffset:動畫延遲開始時間
fillAfter:動畫結束后是否停留在結束狀態(tài)
repeatMode:重復播放動畫模式restart代表正序重放,reverse代表倒序回放
repeatCount:重放次數(shù)(+1),為infinite時無限重復
interpolator:插值器:選擇動畫變化的模式,有勻速,加速,減速,先加速在減速。。。
平移動畫
平移動畫有其特有的屬性,平移動畫在水平方向初始值和結束值,在豎直方向的初始值和結束值
有兩種方式實現(xiàn)平移動畫:

  • xml形式:
    1.在res目錄下新建anim文件夾,創(chuàng)建animation_translate.xml:
<?xml version="1.0" encoding="utf-8"?>
<translate xmlns:android="http://schemas.android.com/apk/res/android"
    android:duration="3000"
    android:startOffset ="1000"
    android:fillAfter = "false"
    android:repeatMode= "reverse"
    android:repeatCount = "infinite"
    android:interpolator="@android:anim/accelerate_decelerate_interpolator"

    android:fromXDelta="0"
    android:toXDelta="500"
    android:fromYDelta="0"
    android:toYDelta="0">

    <!--duration:動畫時長
    startOffset:動畫延遲開始時間
    fillAfter:動畫結束后是否停留在結束狀態(tài)
    repeatMode:重復播放動畫模式restart代表正序重放,reverse代表倒序回放
    repeatCount:重放次數(shù)(+1),為infinite時無限重復
    interpolator:插值器:選擇動畫變化的模式,有勻速,加速,減速,先加速在減速。。。

    以上是所有補間動畫共有的屬性,以下是平移動畫特有的屬性
    fromXDelta:平移動畫在水平方向x初始值
    toXDelta:平移動畫在水平方向x結束值
    fromYDelta:平移動畫在豎直方向y初始值
    toYDelta:平移動畫在豎直方向y結束值-->
</translate>

各個參數(shù)的意義在xml文件中已注明
2.通過AnimationUtils.loadAnimation方法獲取Animation對象讓控件開始動畫:

        Animation animation = AnimationUtils.loadAnimation(this, R.anim.animation_translate);
        bt_translate.startAnimation(animation);
  • java動態(tài)執(zhí)行動畫:
        //分別對應xml中的fromXDelta,toXDelta,fromYDelta,toYDelta
        Animation animation2 = new TranslateAnimation(0, 500, 0, 500);
        animation2.setStartOffset(1000);//動畫延遲開始時間
        animation2.setDuration(3000);//動畫持續(xù)時長
        bt_translate2.startAnimation(animation2);

注意:兩種方式都一定需要有duration屬性設置動畫時長,否則動畫不起作用
縮放動畫
縮放動畫有其特有的屬性,縮放動畫在水平方向起始縮放倍數(shù)和結束縮放倍數(shù),在豎直方向的初始縮放倍數(shù)和結束縮放倍數(shù)
有兩種方式實現(xiàn)縮放動畫:

  • xml形式:
    1.在res的anim目錄下創(chuàng)建animation_scale.xml:
<?xml version="1.0" encoding="utf-8"?>
<scale xmlns:android="http://schemas.android.com/apk/res/android"
    android:duration="3000"
    android:startOffset ="1000"
    android:fillAfter = "false"
    android:repeatMode= "reverse"
    android:repeatCount = "infinite"
    android:interpolator="@android:anim/accelerate_decelerate_interpolator"

    android:fromXScale="0"
    android:toXScale="2"
    android:fromYScale="1"
    android:toYScale="1"
    android:pivotX="50%"
    android:pivotY="50%">

    <!--fromXScale:動畫在水平方向X的起始縮放倍數(shù)
    fromYScale:動畫在豎直方向Y的起始縮放倍數(shù)
    pivotX:縮放軸點的x坐標
    pivotY:縮放軸點的y坐標

    pivotX pivotY,可取值為數(shù)字,百分比,或者百分比p
    設置為數(shù)字時(如50),軸點為View的左上角的原點在x方向和y方向加上50px的點。在Java代碼里面設置這個參數(shù)的對應參數(shù)是Animation.ABSOLUTE。
    設置為百分比時(如50%),軸點為View的左上角的原點在x方向加上自身寬度50%和y方向自身高度50%的點。在Java代碼里面設置這個參數(shù)的對應參數(shù)是Animation.RELATIVE_TO_SELF。
    設置為百分比p時(如50%p),軸點為View的左上角的原點在x方向加上父控件寬度50%和y方向父控件高度50%的點。在Java代碼里面設置這個參數(shù)的對應參數(shù)是Animation.RELATIVE_TO_PARENT-->
</scale>

各個參數(shù)的意義在xml文件中已注明
2.通過AnimationUtils.loadAnimation方法獲取Animation對象讓控件開始動畫:

        Animation animation = AnimationUtils.loadAnimation(this, R.anim.animation_scale);
        bt_scale1.startAnimation(animation);
  • java動態(tài)執(zhí)行動畫:
        //參數(shù)分別對應fromXScale,toXScale,fromYScale,toYScale,縮放軸點X坐標類型,pivotX,縮放軸點Y坐標類型,pivotY
        Animation animation2 = new ScaleAnimation(0, 2, 0, 2, Animation.RELATIVE_TO_SELF, 0.5f, Animation.RELATIVE_TO_SELF, 0.5f);
        animation2.setStartOffset(1000);
        animation2.setDuration(3000);
        bt_scale2.startAnimation(animation2);

注意:兩種方式都一定需要有duration屬性設置動畫時長,否則動畫不起作用
旋轉動畫
旋轉動畫有其特有的屬性,旋轉動畫在動畫開始時視圖的旋轉角度,在動畫結束時視圖的旋轉角度
有兩種方式實現(xiàn)縮放動畫:

  • xml形式:
    1.在res的anim目錄下創(chuàng)建animation_rotate.xml:
<?xml version="1.0" encoding="utf-8"?>
<rotate xmlns:android="http://schemas.android.com/apk/res/android"
    android:duration="3000"
    android:startOffset ="1000"
    android:fillAfter = "false"
    android:repeatMode= "reverse"
    android:repeatCount = "infinite"
    android:interpolator="@android:anim/accelerate_decelerate_interpolator"

    android:fromDegrees="0"
    android:toDegrees="360"
    android:pivotX="50%"
    android:pivotY="50%">

    <!--fromDegrees:動畫開始時 視圖的旋轉角度    正數(shù) = 順時針,負數(shù) = 逆時針
    toDegrees:動畫結束時 視圖的旋轉角度
    pivotX:旋轉軸點的x坐標
    pivotY:旋轉軸點的y坐標

    pivotX pivotY,可取值為數(shù)字,百分比,或者百分比p
    設置為數(shù)字時(如50),軸點為View的左上角的原點在x方向和y方向加上50px的點。在Java代碼里面設置這個參數(shù)的對應參數(shù)是Animation.ABSOLUTE。
    設置為百分比時(如50%),軸點為View的左上角的原點在x方向加上自身寬度50%和y方向自身高度50%的點。在Java代碼里面設置這個參數(shù)的對應參數(shù)是Animation.RELATIVE_TO_SELF。
    設置為百分比p時(如50%p),軸點為View的左上角的原點在x方向加上父控件寬度50%和y方向父控件高度50%的點。在Java代碼里面設置這個參數(shù)的對應參數(shù)是Animation.RELATIVE_TO_PARENT-->
</rotate>

各個參數(shù)的意義在xml文件中已注明
2.通過AnimationUtils.loadAnimation方法獲取Animation對象讓控件開始動畫:

        Animation animation = AnimationUtils.loadAnimation(this, R.anim.animation_rotate);
        bt_rotate1.startAnimation(animation);
  • java動態(tài)執(zhí)行動畫:
        //參數(shù)分別對應fromDegrees,toDegrees,旋轉軸點X坐標類型,pivotX,旋轉軸點Y坐標類型,pivotY
        Animation animation2 = new RotateAnimation(0, -360, Animation.RELATIVE_TO_SELF, 0.5f, Animation.RELATIVE_TO_SELF, 0.5f);
        animation2.setStartOffset(1000);
        animation2.setDuration(3000);
        bt_rotate2.startAnimation(animation2);

注意:兩種方式都一定需要有duration屬性設置動畫時長,否則動畫不起作用
透明度動畫
透明度動畫有其特有的屬性,透明度動畫在動畫開始時視圖的初始透明度,在動畫結束時視圖的結束透明度
有兩種方式實現(xiàn)透明度動畫:

  • xml形式:
    1.在res的anim目錄下創(chuàng)建animation_alpha.xml:
<?xml version="1.0" encoding="utf-8"?>
<alpha xmlns:android="http://schemas.android.com/apk/res/android"
    android:duration="3000"
    android:startOffset ="1000"
    android:fillAfter = "false"
    android:repeatMode= "reverse"
    android:repeatCount = "infinite"
    android:interpolator="@android:anim/accelerate_decelerate_interpolator"

    android:fromAlpha="0"
    android:toAlpha="1">

    <!--fromAlpha:動畫開始時視圖的初始透明度
    toAlpha:動畫結束時視圖的結束透明度-->
</alpha>

各個參數(shù)的意義在xml文件中已注明
2.通過AnimationUtils.loadAnimation方法獲取Animation對象讓控件開始動畫:

        Animation animation = AnimationUtils.loadAnimation(this, R.anim.animation_alpha);
        bt_alpha1.startAnimation(animation);
  • java動態(tài)執(zhí)行動畫:
        //參數(shù)分別對應fromAlpha,toAlpha
        Animation animation2 = new AlphaAnimation(0, 1);
        animation2.setStartOffset(1000);
        animation2.setDuration(3000);
        bt_alpha2.startAnimation(animation2);

注意:兩種方式都一定需要有duration屬性設置動畫時長,否則動畫不起作用
組合動畫
組合動畫就是將上面的四種動畫組合在一起,同事?lián)碛衅揭?,縮放,旋轉和透明度變化的動畫。同樣有兩種方式:

  • xml形式:
    1.在res目錄下新建anim文件夾,創(chuàng)建animation_set.xml:
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android">
    <alpha
        android:duration="1000"
        android:fromAlpha="0"
        android:interpolator="@android:anim/accelerate_decelerate_interpolator"
        android:toAlpha="1" />
    <translate
        android:duration="2000"
        android:fromXDelta="0"
        android:fromYDelta="0"
        android:interpolator="@android:anim/accelerate_decelerate_interpolator"
        android:startOffset="3000"
        android:toXDelta="500"
        android:toYDelta="0" />
    <rotate
        android:duration="3000"
        android:fromDegrees="0"
        android:interpolator="@android:anim/accelerate_decelerate_interpolator"
        android:pivotX="50%"
        android:pivotY="50%"
        android:repeatCount="infinite"
        android:repeatMode="restart"
        android:toDegrees="360" />
    <scale
        android:duration="3000"
        android:fromXScale="1"
        android:fromYScale="1"
        android:interpolator="@android:anim/accelerate_decelerate_interpolator"
        android:pivotX="50%"
        android:pivotY="50%"
        android:startOffset="4000"
        android:toXScale="0.5"
        android:toYScale="0.5" />
</set>

2.通過AnimationUtils.loadAnimation方法獲取Animation對象讓控件開始動畫:

        Animation animation = AnimationUtils.loadAnimation(this, R.anim.animation_set);
        bt_animation1.startAnimation(animation);
  • java動態(tài)執(zhí)行動畫:
//動態(tài)
        bt_animation2 = (Button) findViewById(R.id.bt_animation2);
        AnimationSet animationSet = new AnimationSet(true);
        //子動畫一
        Animation animation1 = new AlphaAnimation(0, 1);
        animation1.setDuration(1000);
        //子動畫二
        Animation animation2 = new TranslateAnimation(0, 500, 0, 0);
        animation2.setDuration(2000);
        animation2.setStartOffset(3000);
        //子動畫三
        Animation animation3 = new RotateAnimation(0, 360, Animation.RELATIVE_TO_SELF, 0.5f, Animation.RELATIVE_TO_SELF, 0.5f);
        animation3.setDuration(3000);
        animation3.setRepeatMode(Animation.RESTART);
        animation3.setRepeatCount(Animation.INFINITE);
        //子動畫四
        Animation animation4 = new ScaleAnimation(1, 0.5f, 1, 0.5f, Animation.RELATIVE_TO_SELF, 0.5f, Animation.RELATIVE_TO_SELF, 0.5f);
        animation4.setDuration(3000);
        animation4.setStartOffset(4000);

        animationSet.addAnimation(animation1);
        animationSet.addAnimation(animation2);
        animationSet.addAnimation(animation3);
        animationSet.addAnimation(animation4);
        bt_animation2.startAnimation(animationSet);

這樣就能實現(xiàn)組合動畫。
動畫監(jiān)聽
通過setAnimationListener得到動畫監(jiān)聽回調,開始和結束

animation2.setAnimationListener(new Animation.AnimationListener() {
            @Override
            public void onAnimationStart(Animation animation) {

            }

            @Override
            public void onAnimationEnd(Animation animation) {

            }

            @Override
            public void onAnimationRepeat(Animation animation) {

            }
        });

四.屬性動畫

我們知道幀動畫和補間動畫都只是改變視覺效果,并沒有真正改變控件的屬性,因此我們接觸到了屬性動畫,屬性動畫中一些類的繼承關系如下:

屬性動畫

我們可以著重看到ValueAnimator,ObjectAnimator和AnimatorSet三個類,因此,屬性動畫主要圍繞這三個類展開,看看屬性動畫是怎么實現(xiàn)的。
ValueAnimator
通過不斷控制值的變化,變化過程中再不斷手動賦給對象的屬性,從而實現(xiàn)動畫效果。
它有三個主要的方法:ValueAnimator.ofInt(int values),ValueAnimator.oFloat(float values)和ValueAnimator.ofObject()。
1.ValueAnimator.ofInt(int values):
它的參數(shù)可以傳入多個int值,表示多個int值之間進行一個平滑過渡,得到一個動畫實例,通過動畫的更新監(jiān)聽器將平滑過渡的值傳給控件來改變控件的屬性打到動畫效果。
縮放效果:

bt_value1 = (Button) findViewById(R.id.bt_value1);
        //步驟1.創(chuàng)建動畫實例,將傳入的多個Int參數(shù)進行平滑過渡,這里只有兩個int參數(shù),可以有多個
        ValueAnimator valueAnimator = ValueAnimator.ofInt(bt_value1.getLayoutParams().width, 500);
        //步驟2.設置動畫的播放各種屬性,如動畫運行的時長setDuration,動畫延遲播放時間setStartDelay,動畫重復播放次數(shù)setRepeatCount,重復播放動畫模式setRepeatMode
        valueAnimator.setDuration(3000);
        //步驟3.將改變的值手動賦值給對象的屬性值:通過動畫的更新監(jiān)聽器,值每次改變、變化一次,該方法就會被調用一次
        valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
            @Override
            public void onAnimationUpdate(ValueAnimator valueAnimator) {
                int currentValue = (int) valueAnimator.getAnimatedValue();
                bt_value1.getLayoutParams().width = currentValue;//將當前的值給button作為寬度
                bt_value1.requestLayout();//對button進行重新繪制
            }
        });
        //步驟4.開啟動畫
        valueAnimator.start();

平移效果:

bt_value2 = (Button) findViewById(R.id.bt_value2);
        ValueAnimator valueAnimator2 = ValueAnimator.ofInt(0, 300);
        valueAnimator2.setDuration(3000);
        valueAnimator2.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
            @Override
            public void onAnimationUpdate(ValueAnimator valueAnimator) {
                int currentMargin = (int) valueAnimator.getAnimatedValue();
                RelativeLayout.LayoutParams layoutParams = new RelativeLayout.LayoutParams(bt_value2.getLayoutParams());
                layoutParams.setMargins(currentMargin, 0, 0, 0);
                bt_value2.setLayoutParams(layoutParams);
            }
        });
        valueAnimator2.start();

透明度效果:

bt_value3 = (Button) findViewById(R.id.bt_value3);
        ValueAnimator valueAnimator3 = ValueAnimator.ofFloat(0, 1);
        valueAnimator3.setDuration(3000);
        valueAnimator3.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
            @Override
            public void onAnimationUpdate(ValueAnimator valueAnimator) {
                float currentValue = (float) valueAnimator.getAnimatedValue();
                bt_value3.setAlpha(currentValue);
                bt_value3.requestLayout();
            }
        });
        valueAnimator3.start();

接下來主要講一下ValueAnimator.ofObject()方法的使用。
2.ValueAnimator.ofObject(TypeEvaluator evaluator,Object object):
在補間動畫的時候我們有一個interpolator屬性是用來設置插值器的用于設置 屬性值 從初始值過渡到結束值 的變化規(guī)律,諸如減速,加速,勻速,先減速在加速等等這些。該方法的第一個參數(shù)是TypeEvaluator表示的是估值器用于設置 屬性值 從初始值過渡到結束值 的變化具體數(shù)值,也就是根據(jù)時間的進度獲取該方法第二個參數(shù)和第三個參數(shù)在變化過程中的數(shù)值的方法。前面的ofInt是作用于int數(shù)值,ofFloat是作用于Float數(shù)值,所以ofObject是作用于對象,我們先創(chuàng)建一個實例對象Point表示控件距離左側和上側控件的邊距:

public class Point {

    // 設置兩個變量用于記錄控件距離左側和上側控件的邊距
    private int x;
    private int y;

    // 構造方法用于設置邊距
    public Point(int x, int y) {
        this.x = x;
        this.y = y;
    }

    // get方法用于獲取邊距
    public int getX() {
        return x;
    }

    public int getY() {
        return y;
    }
}

然后自定義估值器PointEvaluator用于獲取根據(jù)時間變化過程中的對象objec:

// 實現(xiàn)TypeEvaluator接口
public class PointEvaluator implements TypeEvaluator {

    // 復寫evaluate()
    // 在evaluate()里寫入對象動畫過渡的邏輯
    @Override
    public Object evaluate(float fraction, Object startValue, Object endValue) {

        // 將動畫初始值startValue 和 動畫結束值endValue 強制類型轉換成Point對象
        Point startPoint = (Point) startValue;
        Point endPoint = (Point) endValue;

        // 根據(jù)fraction來計算當前動畫的x和y的值
        int x = (int) (startPoint.getX() + fraction * (endPoint.getX() - startPoint.getX()));
        int y = (int) (startPoint.getY() + fraction * (endPoint.getY() - startPoint.getY()));

        // 將計算后的坐標封裝到一個新的Point對象中并返回
        Point point = new Point(x, y);
        return point;
    }
}

我們創(chuàng)建初始對象startPoint和結束對象endPoint,在變化過程中獲取當前point對象并給Button設置距離左側和上側控件的邊距如下:

        bt = (Button) findViewById(R.id.bt);
        Point startPoint = new Point(0, 0);
        Point endPoint = new Point(500, 500);
        ValueAnimator valueAnimator = ValueAnimator.ofObject(new PointEvaluator(), startPoint, endPoint);
        valueAnimator.setDuration(3000);
        valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
            @Override
            public void onAnimationUpdate(ValueAnimator valueAnimator) {
                Point currentPoint = (Point) valueAnimator.getAnimatedValue();
                RelativeLayout.LayoutParams lp = new RelativeLayout.LayoutParams(bt.getLayoutParams());
                lp.setMargins(currentPoint.getX(), currentPoint.getY(), 0, 0);
                bt.setLayoutParams(lp);
                bt.requestLayout();
            }
        });
        valueAnimator.start();

這樣就實現(xiàn)了Button在3秒時間里從startPoint到endPoint邊距的變化過程的動畫,這就是ValueAnimator.ofObject的使用
ObjectAnimator
直接對對象的屬性值進行改變操作,從而實現(xiàn)動畫效果。用法上和ValueAnimator比較類似:
先看下面的對控件進行透明度,平移,縮放和旋轉的動畫:

        bt_alpha = (Button) findViewById(R.id.bt_alpha);
        ObjectAnimator objectAnimator = ObjectAnimator.ofFloat(bt_alpha, "alpha", 0, 1);
        objectAnimator.setDuration(3000);
        objectAnimator.start();

        bt_translate = (Button) findViewById(R.id.bt_translate);
        ObjectAnimator.ofFloat(bt_translate, "translationX", bt_translate.getTranslationX(), 300, bt_translate.getTranslationX()).setDuration(3000).start();


        bt_scale = (Button) findViewById(R.id.bt_scale);
        ObjectAnimator.ofFloat(bt_scale, "scaleX", 0, 2, 1).setDuration(3000).start();

        bt_rotate = (Button) findViewById(R.id.bt_rotate);
        ObjectAnimator objectAnimator2 = ObjectAnimator.ofFloat(bt_rotate, "rotationY", 0, 360).setDuration(3000);
        objectAnimator2.setRepeatCount(ValueAnimator.INFINITE);
        objectAnimator2.start();

注意上面ObjectAnimator.ofFloat方法中的第二個參數(shù)決定了對控件什么操作,參數(shù)名稱對應作用見下表:

屬性 作用 數(shù)值類型
Alpha 控制View的透明度 float
TranslationX 控制X方向的位移 float
TranslationY 控制Y方向的位移 float
ScaleX 控制X方向的縮放倍數(shù) float
ScaleY 控制Y方向的縮放倍數(shù) float
Rotation 控制以屏幕方向為軸的旋轉度數(shù) float
RotationX 控制以X軸為軸的旋轉度數(shù) float
RotationY 控制以Y軸為軸的旋轉度數(shù) float

注意:ObjectAnimator是對對象的屬性值進行改變操作,那么要動畫生效,必須滿足兩個條件:
1.對象必須要提供屬性a的set()方法,而且如果沒傳遞初始值,那么需要提供get()方法,因為系統(tǒng)要去拿屬性a的初始值
2.屬性a的set()方法 對 屬性a的改變帶來ui上的變化
只有同時滿足上面兩個條件,動畫才會生效。那么如果不滿足上面兩個條件但是想用怎么辦,有兩種方法:
1.通過繼承原始類,直接給類加上該屬性的 get()& set(),從而實現(xiàn)給對象加上該屬性的 get()& set()
2.通過包裝原始動畫對象,間接給對象加上該屬性的 get()&set()。即 用一個類來包裝原始對象。
比如,width這個屬性,雖然控件有set和get的方法,但是控件的set方法并不是設置控件寬度用的,而是設置控件最大寬度和最小寬度的,因此無法去改變控件的寬度,自然動畫無法生效。我們可以使用第二種方法進行包裝來進行動畫改變控件的寬度。先自定義類ViewWrapper添加對View寬度的set個get方法:

public class ViewWrapper {
        View view;

        public ViewWrapper(View view) {
            this.view = view;
        }

        //得到控件的寬度
        public int getWidth() {
            return view.getLayoutParams().width;
        }

        //設置控件的寬度
        public void setWidth(int width) {
            view.getLayoutParams().width = width;
            view.requestLayout();
        }
    }

在使用ObjectAnimator對ViewWrapper 對象的width屬性進行動態(tài)改變也就改變了控件的寬度從而達到動畫的效果:

        bt = (Button) findViewById(R.id.bt);
        ViewWrapper viewWrapper = new ViewWrapper(bt);
        ObjectAnimator animator = ObjectAnimator.ofInt(viewWrapper, "width", 0, 500);
        animator.setDuration(3000);
        animator.start();

AnimatorSet
AnimatorSet是組合動畫,畢竟淡一點動畫還是比較少,很多時候動畫都是由單一的屬性動畫組合在一起。AnimatorSet的使用有如下方法:

AnimatorSet.play(Animator anim)   :播放當前動畫
AnimatorSet.after(long delay)   :將現(xiàn)有動畫延遲delay毫秒后執(zhí)行
AnimatorSet.with(Animator anim)   :將現(xiàn)有動畫和傳入的動畫同時執(zhí)行
AnimatorSet.after(Animator anim)   :將現(xiàn)有動畫插入到傳入的動畫之后執(zhí)行
AnimatorSet.before(Animator anim) :  將現(xiàn)有動畫插入到傳入的動畫之前執(zhí)行

比如我們需要一個延遲一秒后,先透明度由0-1,然后平移加旋轉加縮放的動畫:

        bt2= (Button) findViewById(R.id.bt2);
        //子動畫一
        ObjectAnimator objectAnimator=ObjectAnimator.ofFloat(bt2,"alpha",0,1);
        objectAnimator.setDuration(2000);
        //子動畫二
        ObjectAnimator objectAnimator2=ObjectAnimator.ofFloat(bt2,"translationX",0,300);
        objectAnimator2.setDuration(3000);
        //子動畫三
        ObjectAnimator objectAnimator3=ObjectAnimator.ofFloat(bt2,"rotation",0,360);
        objectAnimator3.setDuration(3000);
        //子動畫四
        ObjectAnimator objectAnimator4=ObjectAnimator.ofFloat(bt2,"scaleX",1,0.5f);
        objectAnimator4.setDuration(3000);
        //子動畫五
        ObjectAnimator objectAnimator5=ObjectAnimator.ofFloat(bt2,"scaleY",1,0.5f);
        objectAnimator5.setDuration(3000);

        AnimatorSet animatorSet=new AnimatorSet();
        animatorSet.play(objectAnimator2).with(objectAnimator3).with(objectAnimator4).with(objectAnimator5).after(objectAnimator).after(1000);
        animatorSet.start();

ViewPropertyAnimator
屬性動畫最終都是對控件的值屬性進行操作,因此,谷歌也開放了直接用控件進行動畫的方法,可以認為是屬性動畫的簡便操作方式:View.animate().xxx();View.animate()返回的是ViewPropertyAnimator,后面調用的方法都是在ViewPropertyAnimator的基礎上進行調用開啟動畫,但是不需要調用start方法去啟動。

        bt3 = (Button) findViewById(R.id.bt3);
//        bt3.animate().alpha(0).setDuration(3000);//透明度由原來變?yōu)?
//        bt3.animate().translationX(300).setDuration(3000);//平移
//        bt3.animate().scaleX(0.5f).scaleY(0.5f).setDuration(3000);//X,Y縮放為原來0.5
        bt3.animate().rotation(360).setDuration(3000);//順時針旋轉360度

動畫監(jiān)聽
通過addListener添加動畫監(jiān)聽得到動畫開始,結束,取消方法回調

animator.addListener(new Animator.AnimatorListener() {
            @Override
            public void onAnimationStart(Animator animator) {

            }

            @Override
            public void onAnimationEnd(Animator animator) {

            }

            @Override
            public void onAnimationCancel(Animator animator) {

            }

            @Override
            public void onAnimationRepeat(Animator animator) {

            }
        });

當然,可以使用AnimatorListenerAdapter只監(jiān)聽開始或者結束的其中一個方法:

animator.addListener(new AnimatorListenerAdapter() {
            @Override
            public void onAnimationEnd(Animator animation) {
                super.onAnimationEnd(animation);
            }
        });

以上就是屬性動畫相關的用法。

五.總結

以上就是關于Android幀動畫,補間動畫和屬性動畫的相關知識點,如有不足或者錯誤的地方請在下方指正。我們需要多看更需要多寫,只有不斷學習,不斷進步才能不被淘汰。

?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
【社區(qū)內容提示】社區(qū)部分內容疑似由AI輔助生成,瀏覽時請結合常識與多方信息審慎甄別。
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發(fā)布,文章內容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

相關閱讀更多精彩內容

友情鏈接更多精彩內容