【Android 動畫】動畫詳解之補間動畫(一)

歡子發表於2019-02-23

前言

之前很早就想寫寫Android 的動畫,最近剛好有時間,大概聊一聊安卓動畫。

個人習慣將動畫分為:補間動畫(透明度、旋轉、位移、縮放)、幀動畫、和屬性動畫,這一篇,我們先說說補間動畫。

補間動畫這個詞出於flash,在兩個關鍵幀(可以理解成動畫開始和結束)中間需要做“補間動畫”,才能實現圖畫的運動;插入補間動畫後兩個關鍵幀之間的插補幀是由計算機自動運算而得到的。 實際上,Android 的補間動畫也是由我們指定動畫開始、動畫結束2個關鍵點,中間部分的動畫由系統完成

在正式開始之前,我們先說下Android 系統的座標系,螢幕左上角為座標原點,假如螢幕為1080*1980,那麼左上角為(0,0),右上角為(1080,0),左下角為(0,1980),右下角為(1080,1980)

image.png

1.公共屬性

所有動畫有以下公共屬性,註釋比較詳細,這裡就不在詳述了

               //動畫持續時間
                scaleAnimation.setDuration(2000);
                //如果設定為true,控制元件動畫結束時,將保持動畫最後時的狀態
                scaleAnimation.setFillAfter(true);
                //如果設定為true,控制元件動畫結束時,還原到開始動畫前的狀態
                scaleAnimation.setFillBefore(false);
                //重複次數
                scaleAnimation.setRepeatCount(2);
                //重複型別,有reverse和restart兩個值,reverse表示倒序回放,restart表示重新放一遍,必須與repeatCount一起使用
                scaleAnimation.setRepeatMode(Animation.RESTART);
複製程式碼

2.縮放動畫(ScaleAnimation)

ScaleAnimation有3種構造方法

 public ScaleAnimation(float fromX, float toX, float fromY, float toY) {
  }
 public ScaleAnimation(float fromX, float toX, float fromY, float toY,
            float pivotX, float pivotY) {
  }
public ScaleAnimation(float fromX, float toX, float fromY, float toY,
            int pivotXType, float pivotXValue, int pivotYType, float pivotYValue) {
  }
複製程式碼

我們先看第一種,其起始比例為0,縮放比例為1.4,即放大到1.4倍

                //fromXScale    起始的X方向上相對自身的縮放比例,浮點值,比如1.0代表自身無變化,0.5代表起始時縮小一倍,2.0代表放大一倍;
                //toXScale        結尾的X方向上相對自身的縮放比例,浮點值;
                //fromYScale    起始的Y方向上相對自身的縮放比例,浮點值
                //toYScale        結尾的Y方向上相對自身的縮放比例,浮點值
                scaleAnimation = new ScaleAnimation(0, 1.4f, 0, 1.4f);
                //動畫持續時間
                scaleAnimation.setDuration(2000);
            
                tvDemo.startAnimation(scaleAnimation);
複製程式碼

效果如下:

scale放大1.4倍.gif
第二種,pivotx,pivotY分別代表起始位置的x、y方向的座標,我們設定為(100,100)

               //pivotx,pivotY 動畫起始位置+100
                scaleAnimation = new ScaleAnimation(0, 1.4f, 0, 1.4f, 100, 100);
                scaleAnimation.setDuration(2000);
                tvDemo.startAnimation(scaleAnimation);
複製程式碼

效果如下:

scale起始位置+100.gif

第三種,pivotXType和pivotYType有2種模式,RELATIVE_TO_SELF(相對於自身)和RELATIVE_TO_PARENT(相對於父佈局),如果設定這個,pivotx,pivotY的值就應該是0-1的浮點數,這裡分別對應xml中的%(自身)和%p(父佈局)

  • 1.設定為RELATIVE_TO_SELF
             //如果是50%(程式碼0.5),表示在當前控制元件的左上角加上自己寬度的50%做為起始點
                scaleAnimation = new ScaleAnimation(0, 1.4f, 0, 1.4f, ScaleAnimation.RELATIVE_TO_SELF,
                        0.5f, ScaleAnimation.RELATIVE_TO_SELF, 0.5f);
                scaleAnimation.setDuration(2000);
                tvDemo.startAnimation(scaleAnimation);
複製程式碼

scale自身50.gif

  • 2.設定為RELATIVE_TO_PARENT
 //如果是50%p(程式碼0.5),那麼就是表示在當前的左上角加上父控制元件寬度的50%做為起始點x軸座標。
                scaleAnimation = new ScaleAnimation(0, 1.4f, 0, 1.4f, ScaleAnimation.RELATIVE_TO_PARENT,
                        0.5f, ScaleAnimation.RELATIVE_TO_PARENT, 0.5f);
                scaleAnimation.setDuration(2000);
                tvDemo.startAnimation(scaleAnimation);
複製程式碼

scale父佈局50.gif

3.位移動畫(TranslateAnimation)

TranslateAnimation有2種構造方法,和ScaleAnimation類似

 public TranslateAnimation(float fromXDelta, float toXDelta, float fromYDelta, float toYDelta) {
  }
 public TranslateAnimation(int fromXType, float fromXValue, int toXType, float toXValue,
            int fromYType, float fromYValue, int toYType, float toYValue) {
  }
複製程式碼
  • 1.fromXDelta為起始點X軸座標;fromYDelta 為起始點Y軸從標;toXDelta為結束點X軸座標;toYDelta為 結束點Y軸座標
                //fromXDelta     起始點X軸座標,可以是數值、百分數、百分數p 三種樣式,同scale
                //fromYDelta    起始點Y軸從標,可以是數值、百分數、百分數p 三種樣式
                //toXDelta         結束點X軸座標
                //toYDelta        結束點Y軸座標   
                translateAnimation = new TranslateAnimation(0, 100, 0, 100);
                translateAnimation.setDuration(2000);
                tvDemo.startAnimation(translateAnimation);
複製程式碼

效果如下:

translate100.gif

  • 2.fromYType、toYType同ScaleAnimation,先來看RELATIVE_TO_SELF
 translateAnimation = new TranslateAnimation(TranslateAnimation.RELATIVE_TO_SELF, 0, TranslateAnimation.RELATIVE_TO_SELF, 0.5f,
                        TranslateAnimation.RELATIVE_TO_SELF, 0, TranslateAnimation.RELATIVE_TO_SELF, 0.5f);
                translateAnimation.setDuration(2000);
                tvDemo.startAnimation(translateAnimation);
複製程式碼

效果如下:

translate自身50.gif
RELATIVE_TO_PARENT

 translateAnimation = new TranslateAnimation(TranslateAnimation.RELATIVE_TO_PARENT, 0, TranslateAnimation.RELATIVE_TO_PARENT, 0.5f,
                        TranslateAnimation.RELATIVE_TO_PARENT, 0, TranslateAnimation.RELATIVE_TO_PARENT, 0.5f);
                translateAnimation.setDuration(2000);
                tvDemo.startAnimation(translateAnimation);
複製程式碼

效果如下:

translate父佈局50.gif

4.旋轉動畫(RotateAnimation)

RotateAnimation有3種構造方法

 public RotateAnimation(float fromDegrees, float toDegrees) {
  }
  public RotateAnimation(float fromDegrees, float toDegrees, float pivotX, float pivotY) {
  }
  public RotateAnimation(float fromDegrees, float toDegrees, int pivotXType, float pivotXValue,
            int pivotYType, float pivotYValue) {
  }
複製程式碼
  • 1.fromDegrees 為開始旋轉的角度,正值代表順時針方向度數,負值程式碼逆時針方向度數,toDegrees為結束時旋轉角度,取值同fromDegrees

順時針720度

                rotateAnimation = new RotateAnimation(0, 720, 0, 0);
                rotateAnimation.setDuration(2000);
                tvDemo.startAnimation(rotateAnimation);
複製程式碼

效果如下:

rotate順720.gif

逆時針720度

                 rotateAnimation = new RotateAnimation(0, -720, 0, 0);
                rotateAnimation.setDuration(2000);
                tvDemo.startAnimation(rotateAnimation);
複製程式碼

效果如下:

rotate逆720.gif

  • 2.pivotXType、pivotYType同ScaleAnimation,先看RELATIVE_TO_SELF
             rotateAnimation = new RotateAnimation(0, -720, RotateAnimation.RELATIVE_TO_SELF, 0.5f,
                        RotateAnimation.RELATIVE_TO_SELF, 0.5f);
                rotateAnimation.setDuration(2000);
                tvDemo.startAnimation(rotateAnimation);
複製程式碼

效果如下:

rotate自身720.gif
再來RELATIVE_TO_PARENT

              rotateAnimation = new RotateAnimation(0, -720, RotateAnimation.RELATIVE_TO_PARENT, 0.5f,
                        RotateAnimation.RELATIVE_TO_PARENT, 0.5f);
                rotateAnimation.setDuration(2000);
                tvDemo.startAnimation(rotateAnimation);
複製程式碼

效果如下:

rotate父佈局720.gif

這是什麼鬼???怎麼跑到螢幕外面去了? 原來設定為RELATIVE_TO_PARENT時,旋轉中心x方向應該為該空間離左邊的邊距+父佈局寬度/2,y方向同理,而此時,我們佈局中紅色的Textview為居中狀態,所以旋轉中心為螢幕右下角。讓我們來看個例子 修改佈局如下:

 <TextView
        android:id="@+id/tv_demo"
        android:layout_width="10dp"
        android:layout_height="160dp"
        android:layout_marginLeft="100dp"
        app:layout_constraintLeft_toLeftOf="parent"
        android:background="@color/colorAccent" />


    <TextView
        android:layout_width="match_parent"
        android:layout_height="1dp"
        android:background="@color/colorAccent"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintTop_toTopOf="parent" />

    <TextView
        android:layout_width="1dp"
        android:layout_height="match_parent"
        android:layout_marginLeft="100dp"
        android:background="@color/colorAccent"
        app:layout_constraintLeft_toLeftOf="parent" />
複製程式碼
                rotateAnimation = new RotateAnimation(0, -720, RotateAnimation.RELATIVE_TO_PARENT, 0f,
                        RotateAnimation.RELATIVE_TO_PARENT, 0.5f);
                rotateAnimation.setDuration(2000);
                tvDemo.startAnimation(rotateAnimation);
複製程式碼

效果如下:

rotate100dp.gif
這時,我們看到旋轉中心x方向為離左邊100dp處

5.透明度動畫(AlphaAnimation)

AlphaAnimation只有1種構造方法

 public AlphaAnimation(float fromAlpha, float toAlpha) {
  }
複製程式碼

其中fromAlpha為動畫開始的透明度;toAlpha為動畫結束的透明度

                //fromAlpha   動畫開始的透明度,從0.0 --1.0 ,0.0表示全透明,1.0表示完全不透明
                //toAlpha       動畫結束時的透明度,也是從0.0 --1.0 ,0.0表示全透明,1.0表示完全不透明
                alphaAnimation = new AlphaAnimation(0, 1);
                alphaAnimation.setDuration(2000);
                tvDemo.startAnimation(alphaAnimation);
複製程式碼

效果如下:

alpha漸顯.gif

                alphaAnimation = new AlphaAnimation(1, 0);
                alphaAnimation.setDuration(2000);
                tvDemo.startAnimation(alphaAnimation);
複製程式碼

效果如下:

alpha漸消失.gif

6.動畫集合(AnimationSet)

AnimationSet是一個動畫的集合,可以按照新增的順序播放動畫,讓我們來看個例子,通過組合動畫,實現旋轉漸入動畫

 rotateAnimation = new RotateAnimation(0, -720, RotateAnimation.RELATIVE_TO_SELF, 0.5f,
                        RotateAnimation.RELATIVE_TO_SELF, 0.5f);
                rotateAnimation.setDuration(2000);

                translateAnimation = new TranslateAnimation(TranslateAnimation.RELATIVE_TO_PARENT, 0, TranslateAnimation.RELATIVE_TO_PARENT, 0.5f,
                        TranslateAnimation.RELATIVE_TO_PARENT, 0, TranslateAnimation.RELATIVE_TO_PARENT, 0.5f);
                translateAnimation.setDuration(2000);

                scaleAnimation = new ScaleAnimation(0, 1.4f, 0, 1.4f, ScaleAnimation.RELATIVE_TO_SELF,
                        0.5f, ScaleAnimation.RELATIVE_TO_SELF, 0.5f);
                scaleAnimation.setDuration(2000);

                alphaAnimation = new AlphaAnimation(0, 1);
                alphaAnimation.setDuration(2000);


                animationSet = new AnimationSet(true);
                animationSet.addAnimation(rotateAnimation);
                animationSet.addAnimation(translateAnimation);
                animationSet.addAnimation(scaleAnimation);
                animationSet.addAnimation(alphaAnimation);
                animationSet.setDuration(4000);
                animationSet.setFillAfter(true);


                tvDemo.startAnimation(animationSet);
複製程式碼

效果如下:

旋轉漸入.gif

總結

到這裡,補間動畫就介紹完了

最後獻上原始碼 github

參考資料:自定義控制元件三部曲之動畫篇

相關文章