android 動畫

憤怒的小鹹菜發表於2018-08-28

補間動畫

原理:
  通過確定開始和結束時的檢視樣式, 中間動畫的變化過程由系統來補全。

作用物件:
  作用於View物件,不可作用於View的顏色,背景等屬性

分類:

  • 平移(Translate)
  • 縮放(Scale)
  • 旋轉(Rotate)
  • 透明度(Alpha)

    對應的具體實現類
名稱 原理 實現類
平移動畫(Translate) 移動檢視的位置 TranslateAnimation
縮放動畫(Scale) 放大或者縮小檢視大小 ScaleAnimation
旋轉動畫(Rotate) 旋轉檢視 RotateAnimation
透明動畫(Alpha) 改變檢視的透明度 AlphaAnimation

TIPS:
  補間動畫只會改變View的視覺效果圖,在ScalAnimation和TranslateAnimation中,不會改變View在螢幕上的位置,所以就會導致在執行TranslateAniamtion時,點選平移的View不會觸發click監聽,只有點選它原來的位置時才會觸發click監聽。

***4種動畫(包括set組合動畫)共有的屬性:***

Animation屬性 解釋
android:duration 動畫執行的時間
android:fillAfter 如果為true,那麼動畫執行完就會定格在執行完的那個畫面,也就是動畫的最後一幀,不會恢復到原位。優先於fillBefore值,預設為false
android:fillBefore 動畫播放完後,檢視是否會停留在動畫開始的狀態。只有當android:fillEnable為true時,才有效
android:fillEnabled 是否考慮android:fillBefore的值。只要為true時,android:fillBefore的值才會被考慮。
android:interpolator 設定插值器,控制動畫不同時間段的速度,預設是加速減速插值器。
android:repeatCount 動畫重複的次數,所以總共會執行的動畫次數是這個重複次數+1;為infinite時無限重複
android:repeatMode 動畫重複的方式,有兩個值,reverse 和 restart。reverse表示動畫會正反輪流執行;restart
android:startOffset 動畫延遲執行的時間,單位是毫秒

插值器

插值器 xml中的值 效果
AccelerateDecelerateInterpolator @android:anim/accelerate_decelerate_interpolator 加速減速插值器 動畫先加速再減速
AccelerateInterpolator @android:anim/accelerate_interpolator 加速插值器 動畫速度越來越快
DecelerateInterpolator @android:anim/decelerate_interpolator 減速插值器 動畫速度越來越慢
BounceInterpolator @android:anim/bounce_interpolator 回彈插值器 動畫結束會回彈幾下
CycleInterpolator @android:anim/cycle_interpolator 圓插值器,動畫會重複幾次,動畫的速度沿著正弦曲線變化
LinearInterpolator @android:anim/linear_interpolator 線性插值器 動畫速度保持勻速
AnticipateOvershootInterpolator @android:anim/anticipate_overshoot_interpolator 預期預期超調插值器。先往前甩一定的值,然後開始動畫,結束時往後甩一定的值,結束動畫。
AnticipateInterpolator @android:anim/anticipate_interpolator 預期插值器,動畫開始時會往前甩一下
OvershootInterpolator @android:anim/overshoot_interpolator 超調插值器 動畫結束時往後甩一下

具體使用
  在xml中或者java程式碼中。

     Translate:
       xml初始化

  <!--
 以下引數是4種動畫效果的公共屬性,即都有的屬性
    android:duration="3000" // 動畫持續時間(ms),必須設定,動畫才有效果
    android:startOffset ="1000" // 動畫延遲開始時間(ms)
    android:fillBefore = “true” // 動畫播放完後,檢視是否會停留在動畫開始的狀態,預設為true
    android:fillAfter = “false” // 動畫播放完後,檢視是否會停留在動畫結束的狀態,優先於fillBefore值,預設為false
    android:fillEnabled= “true” // 是否應用fillBefore值,對fillAfter值無影響,預設為true
    android:repeatMode= “restart” // 選擇重複播放動畫模式,restart代表正序重放,reverse代表倒序回放,預設為restart|
    android:repeatCount = “0” // 重放次數(所以動畫的播放次數=重放次數+1),為infinite時無限重複

     以下引數是平移動畫特有的屬性
    android:fromXDelta="0" // 檢視在水平方向x 移動的起始值
    android:toXDelta="100%" // 檢視在水平方向x 移動的結束值

    android:fromYDelta="0" // 檢視在豎直方向y 移動的起始值
    android:toYDelta="500" // 檢視在豎直方向y 移動的結束值
    -->
    <translate xmlns:android="http://schemas.android.com/apk/res/android"
        android:duration="3000"
        android:startOffset ="10"
        android:fillBefore = "true"
        android:fillAfter = "false"
        android:fillEnabled= "false"
        android:repeatMode= "restart"
        android:repeatCount = "0"
        android:interpolator = "@android:anim/bounce_interpolator"
    
        android:fromXDelta="0"
        android:toXDelta="100%"
        android:fromYDelta="0"
        android:toYDelta="100%"/>
    
        //在class中使用:
        translateAnimation = AnimationUtils.loadAnimation(this,R.anim.anim_translate)
        btn.startAnimation(translateAnimation)
複製程式碼

       java程式碼初始化:

~~~
 fun initTraslateForCode() : Animation{
 //絕對座標
       // translateAnimation = TranslateAnimation(0F,100F,0F,100F)
 //絕對座標
      //  translateAnimation = TranslateAnimation(Animation.ABSOLUTE,0F,Animation.ABSOLUTE,150F,Animation.ABSOLUTE,0F,Animation.ABSOLUTE,150F)
  //相對於自己的百分比座標
        translateAnimation = TranslateAnimation(Animation.RELATIVE_TO_SELF,0F,Animation.RELATIVE_TO_SELF,100F,Animation.RELATIVE_TO_SELF,0F,Animation.RELATIVE_TO_SELF,100F)
 //相對於ParentView的百分比座標
       // translateAnimation = TranslateAnimation(Animation.RELATIVE_TO_PARENT,0F,Animation.RELATIVE_TO_PARENT,100F,Animation.RELATIVE_TO_PARENT,0F,Animation.RELATIVE_TO_PARENT,100F)
        translateAnimation.duration = 3000

    return translateAnimation
}
~~~
複製程式碼

TranslateAnimation獨有屬性

TranslateAnimation獨有屬性 含義
android:fromXDelta 動畫開始時View左上角的X座標,也有三種寫法:
數值:50;百分數:50%;百分數p:50%p。
如果是數值,表示以View的左上角為(0,0),然後加上寫的數值,以這個點作為開始點。
如果為百分數,如50%,表示總左上角(0,0)加上自身高度的50%,
作為開始點。
如果是百分數p,如50%p,表示總左上角(0,0)加上父控制元件高度的50%,作為開始點。
android:fromYDelta 動畫開始時View左上角的Y座標,也有三種寫法
android:toXDelta 動畫結束時View左上角的X座標,也有三種寫法
android:toYDelta 動畫結束時View左上角的Y座標,也有三種寫法

Scale:
  ScaleAnimation獨有屬性:

ScaleAnimation獨有屬性 含義
android:pivotX float,縮放起點,或縮放原點的X軸座標。
縮放圍繞這個點執行。 這個座標預設是View的左上角,(0,0)
在XML中的值有三種寫法.
android:pivotY float,同上 Y軸座標. 在XML中的值有三種寫法
android:fromXScale float 動畫開始時,X軸上縮放的比例。1表示本身大小。
android:fromYScale float 動畫開始時,Y軸上縮放的比例。1表示本身大小。
android:toXScale float Y動畫結束時,X軸上縮放的比例。1表示本身大小。
android:toYScale float Y動畫結束時,Y軸上縮放的比例。1表示本身大小。

Rotate   Rotate獨有屬性:

RotateAnimation獨有屬性 含義
android:pivotX 旋轉動畫的中心的X座標,旋轉圍繞這個點進行,也有三種寫法,
android:pivotY 旋轉動畫的中心的Y座標,旋轉圍繞這個點進行,也有三種寫法
android:fromDegrees 動畫開始時的旋轉角度。角度順時針轉增加,逆時針轉減少。
所以根據開始角度和結束角度來判斷是順時針還是逆時針。360度為一圈。
android:toDegrees 動畫結束時的旋轉角度。

Alpha   Alpha獨有屬性:

AlphaAnimation的獨有屬性 含義
android:fromAlpha 動畫開始時的透明度 從0.0-1.0 0.0表示完全透明,1.0表示完全不透明
android:toAlpha 動畫結束時的透明度

set組合動畫

//anim_set.xml
<set xmlns:android="http://schemas.android.com/apk/res/android"
   android:duration="3000">
   <rotate
       android:pivotX="50%"
       android:pivotY="50%"
       android:fromDegrees="360"
       android:toDegrees="-90"
       />
   <alpha
       android:fromAlpha="1"
       android:toAlpha="0.2"/>
</set>
//java
Animation translateAnimation = AnimationUtils.loadAnimation(this, R.anim.set);
// 步驟2:建立 動畫物件 並傳入設定的動畫效果xml檔案
mButton.startAnimation(translateAnimation);
複製程式碼

java程式碼設定:

 // 組合動畫設定
AnimationSet setAnimation = new AnimationSet(true);
// 步驟1:建立組合動畫物件(設定為true)
// 步驟2:設定組合動畫的屬性
// 特別說明以下情況
// 因為在下面的旋轉動畫設定了無限迴圈(RepeatCount = INFINITE)
// 所以動畫不會結束,而是無限迴圈
// 所以組合動畫的下面兩行設定是無效的
setAnimation.setRepeatMode(Animation.RESTART);
setAnimation.setRepeatCount(1);// 設定了迴圈一次,但無效
// 步驟3:逐個建立子動畫(方式同單個動畫建立方式)
// 子動畫1:旋轉動畫
Animation rotate = new RotateAnimation(0,360,Animation.RELATIVE_TO_SELF,0.5f,Animation.RELATIVE_TO_SELF,0.5f);
rotate.setDuration(1000);
rotate.setRepeatMode(Animation.RESTART);
rotate.setRepeatCount(Animation.INFINITE);

// 子動畫2:平移動畫
Animation translate = new TranslateAnimation(TranslateAnimation.RELATIVE_TO_PARENT,-0.5f,
        TranslateAnimation.RELATIVE_TO_PARENT,0.5f,
        TranslateAnimation.RELATIVE_TO_SELF,0
        ,TranslateAnimation.RELATIVE_TO_SELF,0);
translate.setDuration(10000);

// 子動畫3:透明度動畫
Animation alpha = new AlphaAnimation(1,0);
alpha.setDuration(3000);
alpha.setStartOffset(7000);

// 子動畫4:縮放動畫
Animation scale1 = new ScaleAnimation(1,0.5f,1,0.5f,Animation.RELATIVE_TO_SELF,0.5f,Animation.RELATIVE_TO_SELF,0.5f);
scale1.setDuration(1000);
scale1.setStartOffset(4000);

// 步驟4:將建立的子動畫新增到組合動畫裡
setAnimation.addAnimation(alpha);
setAnimation.addAnimation(rotate);
setAnimation.addAnimation(translate);
setAnimation.addAnimation(scale1);
複製程式碼

動畫的監聽   補間動畫只需設定開始檢視和結束檢視,中間的動畫過程由系統完成,因此智慧監聽器開始和結束狀態。

animation.setAnimationListener(new Animation.AnimationListener() {
            @Override
            public void onAnimationStart(Animation animation) {
                Log.i(TAG, "動畫開始時做操作: ");
            }

            @Override
            public void onAnimationEnd(Animation animation) {
                Log.i(TAG, "動畫重複時做操作: ");
            }

            @Override
            public void onAnimationRepeat(Animation animation) {
                Log.i(TAG, "動畫結束時做操作: ");
            }
        });
複製程式碼

補充:ListView可以設定出場動畫

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="#FFFFFF"
    android:orientation="vertical" >
    <ListView
        android:id="@+id/listView1"
        android:layoutAnimation="@anim/anim_layout"
        // 指定layoutAnimation屬性用以指定子元素的入場動畫
        android:layout_width="match_parent"
        android:layout_height="match_parent" />
</LinearLayout>
複製程式碼

逐幀動畫

作用物件 檢視控制元件(View)

1.如Android的TextView、Button等等
2.不可作用於View元件的屬性,如:顏色、背景、長度等等
複製程式碼

原理

  • 將動畫拆分為 幀 的形式,且定義每一幀 = 每一張圖片
  • 逐幀動畫的本質:按序播放一組預先定義好的圖片

具體使用 xml:

//knight_attack.xml
<?xml version="1.0" encoding="utf-8"?>
<animation-list
   xmlns:android="http://schemas.android.com/apk/res/android"
   android:oneshot="true" // 設定是否只播放一次,預設為false>

// item = 動畫圖片資源;duration = 設定一幀持續時間(ms)
   <item android:drawable="@drawable/a0" android:duration="100"/>
   <item android:drawable="@drawable/a1" android:duration="100"/>
   <item android:drawable="@drawable/a2" android:duration="100"/>
   <item android:drawable="@drawable/a3" android:duration="100"/>
   <item android:drawable="@drawable/a4" android:duration="100"/>
   <item android:drawable="@drawable/a5" android:duration="100"/>
   <item android:drawable="@drawable/a6" android:duration="100"/>
   <item android:drawable="@drawable/a7" android:duration="100"/>
   <item android:drawable="@drawable/a8" android:duration="100"/>
   <item android:drawable="@drawable/a9" android:duration="100"/>
   <item android:drawable="@drawable/a10" android:duration="100"/>
   <item android:drawable="@drawable/a11" android:duration="100"/>
   <item android:drawable="@drawable/a12" android:duration="100"/>
   <item android:drawable="@drawable/a13" android:duration="100"/>
   <item android:drawable="@drawable/a14" android:duration="100"/>
   <item android:drawable="@drawable/a15" android:duration="100"/>
   <item android:drawable="@drawable/a16" android:duration="100"/>
   <item android:drawable="@drawable/a17" android:duration="100"/>
   <item android:drawable="@drawable/a18" android:duration="100"/>
   <item android:drawable="@drawable/a19" android:duration="100"/>
   <item android:drawable="@drawable/a20" android:duration="100"/>
   <item android:drawable="@drawable/a21" android:duration="100"/>
   <item android:drawable="@drawable/a22" android:duration="100"/>
   <item android:drawable="@drawable/a23" android:duration="100"/>
   <item android:drawable="@drawable/a24" android:duration="100"/>
   <item android:drawable="@drawable/a25" android:duration="100"/>
</animation-list>

//java 程式碼:
iv.setImageResource(R.drawable.knight_attack);
               // 1. 設定動畫
               animationDrawable = (AnimationDrawable) iv.getDrawable();
               // 2. 獲取動畫物件
               animationDrawable.start();
   
複製程式碼

在Java程式碼中實現:

 animationDrawable = new AnimationDrawable();
 for (int i = 0; i <= 25; i++) {
            int id = getResources().getIdentifier("a" + i, "drawable", getPackageName());
            Drawable drawable = getResources().getDrawable(id);
            animationDrawable.addFrame(drawable, 100);
 }
 animationDrawable.setOneShot(true);
 iv.setImageDrawable(animationDrawable);
 // 獲取資源物件
 animationDrawable.stop();
 // 特別注意:在動畫start()之前要先stop(),不然在第一次動畫之後會停在最後一幀,這樣動畫就只會觸發一次
 animationDrawable.start();
 // 啟動動畫

作者:Carson_Ho
連結:https://www.jianshu.com/p/225fe1feba60
複製程式碼

注意
  儘量避免使用尺寸較大的圖片,否則會引起oom

屬性動畫

補間動畫的侷限性:
  1.作用物件有侷限性,只能作用在View上,無法對view的屬性進行動哈操作;
  2.沒有改變View的屬性,只是改變視覺效果;
  3.效果單一,智慧實現平移,選擇,縮放,透明度4中或者這4種組合的動畫

屬性動畫的原理
在一定時間間隔內,通過不斷對值進行改變,並不斷將該值賦給物件的屬性,從而實現該物件在該屬性上的動畫效果

ValueAnimation

  • ValueAnimator.ofInt(int values)
      將初始值 以整型數值的形式 過渡到結束值,即使整型估值器 - IntEvalutor
 private void initValueAnimator() {
        // ofInt()作用有兩個
        // 1. 建立動畫例項
        //2. 將傳入的多個Int引數進行平滑過渡:此處傳入0和1,表示將值從0平滑過渡到1
        // 如果傳入了3個Int引數 a,b,c ,則是先從a平滑過渡到b,再從b平滑過渡到C,以此類推
        // ValueAnimator.ofInt()內建了整型估值器,直接採用預設的.不需要設定,即預設設定瞭如何從初始值 過渡到 結束值
        final ValueAnimator valueAnimator = ValueAnimator.ofInt(0,3);

        // 步驟2:設定動畫的播放各種屬性
        valueAnimator.setDuration(500);

        // 設定動畫延遲播放時間
        valueAnimator.setStartDelay(500);

        // 設定動畫重複播放次數 = 重放次數+1
        // 動畫播放次數 = infinite時,動畫無限重複
        valueAnimator.setRepeatCount(0);

        // 設定重複播放動畫模式
        // ValueAnimator.RESTART(預設):正序重放
        // ValueAnimator.REVERSE:倒序回放
        valueAnimator.setRepeatMode(ValueAnimator.RESTART);

        valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
            @Override
            public void onAnimationUpdate(ValueAnimator animation) {
                int currentValue = (int) animation.getAnimatedValue();
                Log.i("ValueAnimator:" , currentValue +"");
                //todo 將值賦值給View的某個繪製屬性,並重新繪製View。
            }
        });
        valueAnimator.start();
    }
複製程式碼

結果為:

05-10 22:06:44.078 4618-4618/com.aoyj.animaiton.valueanimationmaster I/ValueAnimator:: 0
05-10 22:06:44.094 4618-4618/com.aoyj.animaiton.valueanimationmaster I/ValueAnimator:: 0
05-10 22:06:44.115 4618-4618/com.aoyj.animaiton.valueanimationmaster I/ValueAnimator:: 0
05-10 22:06:44.133 4618-4618/com.aoyj.animaiton.valueanimationmaster I/ValueAnimator:: 0
05-10 22:06:44.151 4618-4618/com.aoyj.animaiton.valueanimationmaster I/ValueAnimator:: 0
05-10 22:06:44.169 4618-4618/com.aoyj.animaiton.valueanimationmaster I/ValueAnimator:: 0
05-10 22:06:44.187 4618-4618/com.aoyj.animaiton.valueanimationmaster I/ValueAnimator:: 0
05-10 22:06:44.204 4618-4618/com.aoyj.animaiton.valueanimationmaster I/ValueAnimator:: 0
05-10 22:06:44.224 4618-4618/com.aoyj.animaiton.valueanimationmaster I/ValueAnimator:: 0
05-10 22:06:44.241 4618-4618/com.aoyj.animaiton.valueanimationmaster I/ValueAnimator:: 0
05-10 22:06:44.258 4618-4618/com.aoyj.animaiton.valueanimationmaster I/ValueAnimator:: 1
05-10 22:06:44.276 4618-4618/com.aoyj.animaiton.valueanimationmaster I/ValueAnimator:: 1
05-10 22:06:44.294 4618-4618/com.aoyj.animaiton.valueanimationmaster I/ValueAnimator:: 1
05-10 22:06:44.312 4618-4618/com.aoyj.animaiton.valueanimationmaster I/ValueAnimator:: 1
05-10 22:06:44.331 4618-4618/com.aoyj.animaiton.valueanimationmaster I/ValueAnimator:: 1
05-10 22:06:44.347 4618-4618/com.aoyj.animaiton.valueanimationmaster I/ValueAnimator:: 1
05-10 22:06:44.366 4618-4618/com.aoyj.animaiton.valueanimationmaster I/ValueAnimator:: 1
05-10 22:06:44.386 4618-4618/com.aoyj.animaiton.valueanimationmaster I/ValueAnimator:: 2
05-10 22:06:44.405 4618-4618/com.aoyj.animaiton.valueanimationmaster I/ValueAnimator:: 2
05-10 22:06:44.423 4618-4618/com.aoyj.animaiton.valueanimationmaster I/ValueAnimator:: 2
05-10 22:06:44.440 4618-4618/com.aoyj.animaiton.valueanimationmaster I/ValueAnimator:: 2
05-10 22:06:44.459 4618-4618/com.aoyj.animaiton.valueanimationmaster I/ValueAnimator:: 2
05-10 22:06:44.476 4618-4618/com.aoyj.animaiton.valueanimationmaster I/ValueAnimator:: 2
05-10 22:06:44.493 4618-4618/com.aoyj.animaiton.valueanimationmaster I/ValueAnimator:: 2
05-10 22:06:44.511 4618-4618/com.aoyj.animaiton.valueanimationmaster I/ValueAnimator:: 2
05-10 22:06:44.530 4618-4618/com.aoyj.animaiton.valueanimationmaster I/ValueAnimator:: 2
05-10 22:06:44.548 4618-4618/com.aoyj.animaiton.valueanimationmaster I/ValueAnimator:: 2
05-10 22:06:44.567 4618-4618/com.aoyj.animaiton.valueanimationmaster I/ValueAnimator:: 3
複製程式碼

可以將動畫寫在在xml中,但是這樣子value的初始值和結束值都時事先固定的。

//set_anim.xml
<animator xmlns:android="http://schemas.android.com/apk/res/android"  
    android:valueFrom="0"   // 初始值
    android:valueTo="100"  // 結束值
    android:valueType="intType" // 變化值型別 :floatType & intType

    android:duration="3000" // 動畫持續時間(ms),必須設定,動畫才有效果
    android:startOffset ="1000" // 動畫延遲開始時間(ms)
    android:fillBefore = “true” // 動畫播放完後,檢視是否會停留在動畫開始的狀態,預設為true
    android:fillAfter = “false” // 動畫播放完後,檢視是否會停留在動畫結束的狀態,優先於fillBefore值,預設為false
    android:fillEnabled= “true” // 是否應用fillBefore值,對fillAfter值無影響,預設為true
    android:repeatMode= “restart” // 選擇重複播放動畫模式,restart代表正序重放,reverse代表倒序回放,預設為restart|
    android:repeatCount = “0” // 重放次數(所以動畫的播放次數=重放次數+1),為infinite時無限重複
    android:interpolator = @[package:]anim/interpolator_resource // 插值器,即影響動畫的播放速度,下面會詳細講
/>

//在java程式碼中使用
ValueAnimator valueAnimator = ValueAnimatorInflater.loadAnimator(context,R.anim.set_anim);
valueAnimator.start();

作者:Carson_Ho
連結:https://www.jianshu.com/p/2412d00a0ce4
來源:簡書
複製程式碼

***ValueAnimator.ofFloat()***
  與ValueAnimator.ofiInt()類似

ValueAnimator.ofObject()
  ValueAnimator.ofInt()與ValueAnimator.ofFloat()都有內建的估值器,ValueAnimator.ofFloat()的估值器FloatEvaluetor實現為:

public class FloatEvaluator implements TypeEvaluator {  
// FloatEvaluator實現了TypeEvaluator介面

// 重寫evaluate()
    public Object evaluate(float fraction, Object startValue, Object endValue) {  
// 引數說明
// fraction:表示動畫完成度(根據它來計算當前動畫的值)
// startValue、endValue:動畫的初始值和結束值
        float startFloat = ((Number) startValue).floatValue();  
        
        return startFloat + fraction * (((Number) endValue).floatValue() - startFloat);  
        // 初始值 過渡 到結束值 的演算法是:
        // 1. 用結束值減去初始值,算出它們之間的差值
        // 2. 用上述差值乘以fraction係數
        // 3. 再加上初始值,就得到當前動畫的值
    }  
}
複製程式碼

對於ValueAnimator.ofObject(),我自定義Evaluetor

public class ObjectEvaluetor implements TypeEvaluetor{
    @Override
    public Object evaluetor(float fraction,Object startValue,Object endValue){
        //fraction 為執行動畫的完成度
        //startValue endValue為初始值和結束值
        ... //計算物件動畫的值
        return value;
    }
}
複製程式碼

ValueAnimator.ofObject()總結:
  ValueAnimator.ofObject()本質還是改變值,只是其可以同時改變一個物件的多個屬性值。而ValueAnimator.ofInt()和ValueAnimator.ofFloat()只能改變一個值。

ObjectAnimator

  ObjectAnimato和ValueAnimator本質都是通過不斷改變View的某個值達到動畫效果。不同的是 ValueAnimator是手動給View的某個屬性賦值,而ObjectAnimator是自動給View的屬性賦值。
  和ValueAnimator類似,ObjectAnimator也有ObjectAnimator.ofInt(),ObjectAnimator.ofFloat(),ObjectAnimator.ofObject()這些型別,具體使用哪種要根據設定的property決定。

具體使用
  java設定:

/**
  Object object:需要操作的物件
  String property:需要操作的物件的屬性
  float ....values:動畫初始值 & 結束值(不固定長度)
  若是兩個引數a,b,則動畫效果則是從屬性的a值到b值
  若是三個引數a,b,c,則則動畫效果則是從屬性的a值到b值再到c值
**/
ObjectAnimator animator = ObjectAnimator.ofFloat(Object object, String property, float ....values);

// 設定動畫執行的時長
anim.setDuration(500);
// 設定動畫延遲播放時間
 anim.setStartDelay(500);
 // 設定動畫重複播放次數 = 重放次數+1,動畫播放次數 = infinite時,動畫無限重複
 anim.setRepeatCount(0);
  // 設定重複播放動畫模式:RESTART(預設):正序重放,REVERSE:倒序回放
  anim.setRepeatMode(ValueAnimator.RESTART);
複製程式碼

縮放:

//縮放 java程式碼
fun initAnimator(){
      //作用物件是btn
      //作用的物件屬性是x軸縮放
      //動畫效果是放大到3倍,在縮小到初始值
      scaleAnimator = ObjectAnimator.ofFloat(btn,"scaleX",1f,3f,2f)
      scaleAnimator.duration = 2000
      scaleAnimator.start()
  }
  
  //xml scale_animator.xml
<?xml version="1.0" encoding="utf-8"?>
<objectAnimator xmlns:android="http://schemas.android.com/apk/res/android"
  android:valueFrom="1"
  android:valueType="floatType"
  android:propertyName="scaleX"
  android:valueTo="3"

  android:repeatCount="0"
  android:repeatMode="restart"
  android:startOffset="100"
  android:duration="500">
</objectAnimator>
//java程式碼中使用xml:
ObjectAniamtor scaleAnimator = ValueAnimatorInflater.loadAnimator(context,R.animtor.scale_animator) as ObjectAnimator
scaleAnimator.target = btn
scaleAnimator.start()
複製程式碼

透明度:

//java程式碼:
fun initAnimator(){
      alphaAnimator = ObjectAnimator.ofFloat(btn,"alpha",1f,0f,0.5f,1f)
      alphaAnimator.duration = 500
      alphaAnimator.repeatCount = 0
      alphaAnimator.repeatMode = ValueAnimator.RESTART
      alphaAniamtor.start()
  }
  
  //xml程式碼:alpha_animator.xml
<?xml version="1.0" encoding="utf-8"?>
<objectAnimator xmlns:android="http://schemas.android.com/apk/res/android"
  android:valueFrom="1"
  android:valueTo="0.5"
  android:valueType="floatType"
  android:propertyName="alpha"

  android:duration="500"
  android:startOffset="100"
  android:repeatMode="restart"
  android:repeatCount="0">

</objectAnimator>

//java 程式碼:
alphaAnimator = AnimatorInflater.loadAnimator(context,R.animator.alpha_animator) as ObjectAnimator
alphaAnimator.target = btn
alphaAnimator.start()
複製程式碼

旋轉

//java 程式碼
fun initAnimator(){
      rotationAnimator = ObjectAnimator.ofFloat(btn,"rotation",0f,360f)
      rotationAnimator.duration = 500
      rotationAnimator.startDelay = 100
      rotationAnimator.repeatMode = ValueAnimator.RESTART
      rotationAnimator.repeatCount = 0
      rotationAniamtor.start()
  }
  
//xml程式碼:rotation_animator.xml
<?xml version="1.0" encoding="utf-8"?>
<objectAnimator xmlns:android="http://schemas.android.com/apk/res/android"
  android:valueFrom="0"
  android:valueTo="360"
  android:valueType="floatType"
  android:propertyName="rotation"

  android:duration="500"
  android:startOffset="100"
  android:repeatCount="0"
  android:repeatMode="reverse">

</objectAnimator>

//java 應用xml程式碼
  rotationAnimator = AnimatorInflater.loadAnimator(context,R.animator.rotation_animator) as ObjectAnimator
  rotationAnimator.target = btn
  rotationAnimator.start()
複製程式碼

平移:平移的座標系都是以執行動畫的View的左上角座標點為起始點座標

//java程式碼:
 fun initAnimator(){
      translateAnimator = ObjectAnimator.ofFloat(btn,"translationX",100F,200F)
      translateAnimator.duration = 500
      translateAnimator.interpolator = BounceInterpolator()
      translationAnimator.start()
  }
  
  //xml 程式碼
<?xml version="1.0" encoding="utf-8"?>
<objectAnimator xmlns:android="http://schemas.android.com/apk/res/android"
  android:valueFrom="0"
  android:valueTo="500"
  android:valueType="floatType"
  android:propertyName="translationX"
  android:interpolator="@android:anim/bounce_interpolator"

  android:duration="500"
  android:startOffset="100"
  android:repeatMode="restart"
  android:repeatCount="0">
</objectAnimator>
//java 應用xml程式碼
  fun initAniamtorFromXml(){
      translateAnimator = AnimatorInflater.loadAnimator(this,R.animator.translation_animator) as ObjectAnimator
      translateAnimator.target = btn
      translateAnimator.start()
  }
複製程式碼

ObjectAnimator在一般View上起作用的集中屬性:

View屬性值 效果 數值型別
alpha 控制透明度 float
translationX 控制x方向上位移
(以執行動畫的View的左上角為座標原點)
float(例如:0到50)
translationY 控制y方向上位移
(以執行動畫的View的左上角為座標原點)
float(例:如0到500)
scaleX 控制x方向的縮放倍數
(個人認為以View的中心左邊點為縮放點)
float(例如:1到3)
scaleY 控制y方向的縮放倍數
(個人認為以View的中心左邊點為縮放點)
float(例如:1到3)
rotation 以螢幕方向為軸的旋轉 float(例如:0到360)
rotationX 以x軸方向旋轉 float(例如:0到360)
rotationY 以y軸方向旋轉 float(例如:0到360)

AnimatorSet組合動畫

AnimatorSet.play(Animator anim)   :播放當前動畫
AnimatorSet.after(long delay)   :將現有動畫延遲x毫秒後執行
AnimatorSet.with(Animator anim)   :將現有動畫和傳入的動畫同時執行
AnimatorSet.after(Animator anim)   :將現有動畫插入到傳入的動畫之後執行
AnimatorSet.before(Animator anim) :  將現有動畫插入到傳入的動畫之前執行
複製程式碼

xml:

//set_animator.xml
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android"
   android:ordering="sequentially" >
   // 表示Set集合內的動畫按順序進行
   // ordering的屬性值:sequentially & together
   // sequentially:表示set中的動畫,按照先後順序逐步進行(a 完成之後進行 b )
   // together:表示set中的動畫,在同一時間同時進行,為預設值

   <set android:ordering="together" >
       // 下面的動畫同時進行
       <objectAnimator
           android:duration="2000"
           android:propertyName="translationX"
           android:valueFrom="0"
           android:valueTo="300"
           android:valueType="floatType" >
       </objectAnimator>
       
       <objectAnimator
           android:duration="3000"
           android:propertyName="rotation"
           android:valueFrom="0"
           android:valueTo="360"
           android:valueType="floatType" >
       </objectAnimator>
   </set>

       <set android:ordering="sequentially" >
           // 下面的動畫按序進行
           <objectAnimator
               android:duration="1500"
               android:propertyName="alpha"
               android:valueFrom="1"
               android:valueTo="0"
               android:valueType="floatType" >
           </objectAnimator>
           <objectAnimator
               android:duration="1500"
               android:propertyName="alpha"
               android:valueFrom="0"
               android:valueTo="1"
               android:valueType="floatType" >
           </objectAnimator>
       </set>

</set>
複製程式碼

android 動畫框架

LayoutAnimation

  LayoutAnimation是應用於ViewGroup的動畫框架。它可以使VeiwGroup中的childView按照繪製先後,順序執行動畫。
java程式碼設定

//具體執行的animation:
//animation_layout_scale.xml
<?xml version="1.0" encoding="utf-8"?>
<scale xmlns:android="http://schemas.android.com/apk/res/android"
   android:duration="300"
   android:pivotY="50%"
   android:pivotX="50%"
   android:fromYScale="0.1"
   android:fromXScale="0.1"
   android:toXScale="1"
   android:toYScale="1">
</scale>

//初始化LayoutAnimationControl
Animation animation = AnimationUtils.loadAnimation(mContext,R.anim.animation_layout_scale);
//第一個引數是具體執行的動畫,第二個引數是layoutAnimation的延時百分比
LayoutAnimationController controller = new LayoutAnimationControl(animation,0.3f);
//設定動畫執行順序
controller.setOrder(LayoutAnimationController.ORDER_NORMAL);
listVeiw.setlayoutAnimation(controller);
複製程式碼

xml實現:

//layout_animation.xml
<?xml version="1.0" encoding="utf-8"?>
<layoutAnimation xmlns:android="http://schemas.android.com/apk/res/android"
   android:delay="0.3"
   android:animationOrder="normal"
   android:animation="@anim/animation_layout_scale">
</layoutAnimation>

//Viewgroup設定LayoutAnimation屬性
<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout
   xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent"
   android:layout_height="match_parent">
   <ListView
       android:id="@+id/list_view"
       android:layout_width="match_parent"
       android:layoutAnimation="@anim/layout_animation"
       android:layout_height="match_parent"/>
</android.support.constraint.ConstraintLayout>
複製程式碼

delay:指的是child view相對於上一個childView動畫的延時時間。取值是具體執行的animation的動畫時間的倍數;
animationOrder:指的是ViewGroup中child view動畫開始的順序。normal(按照正常的繪製順序執行),reverse(按照繪製順序逆序執行),random(隨機執行);
animation:child view具體執行的動畫,只能是補間動畫;

ViewAnimationUtils

  android 5.0以上的生成一個圓形動畫的animator;

 private void startViewAniamtionUtils(){
        int centreX = btn.getWidth();
        int centreY = btn.getHeight();
        float hypot = (float) Math.hypot(btn.getHeight(), btn.getWidth());

        //第一個引數是執行圓形動畫的view,第二,第三個引數是圓心,第四,第五個引數是圓的半徑取值範圍
        Animator animator = ViewAnimationUtils.createCircularReveal(btn,centreX,centreY,0,hypot);
        animator.setDuration(600);
        animator.setStartDelay(10);
    //    animator.setInterpolator(new LinearInterpolator());
        AnimatorSet set = new AnimatorSet();
        set.play(animator)
        .with(getAlphAnimator());
        set.setDuration(600);
        set.setInterpolator(new AccelerateInterpolator());
        set.start();
    }
     private ObjectAnimator getAlphAnimator(){
        ObjectAnimator objectAnimator = ObjectAnimator.ofFloat(btn,"alpha",0f,1f);
        objectAnimator.setDuration(600);
        objectAnimator.setTarget(btn);
    //    objectAnimator.setInterpolator(new LinearInterpolator());
        return objectAnimator;
    }
複製程式碼

overridePendingTransition

指定Activity的退出和進入動畫,它包括兩個部分
一部分是第一個activity退出時的動畫,
另外一個部分是第二個activity進入時的動畫。
需要注意兩個部分:

  • 在android2.0以上呼叫,
  • 要在startActivity或者finished的後面呼叫。
  @OnClick(R.id.button)
    public void onViewClicked() {
        finish();
        overridePendingTransition(R.anim.enter_anim,R.anim.exit_anim);
    }

//enter_anim:
<?xml version="1.0" encoding="utf-8"?>
<translate xmlns:android="http://schemas.android.com/apk/res/android"
    android:duration="500"
    android:fromXDelta="-30%"
    android:toXDelta="0">
</translate>

//exit_anim.xml
<?xml version="1.0" encoding="utf-8"?>
<translate xmlns:android="http://schemas.android.com/apk/res/android"
    android:duration="500"
    android:fromXDelta="0"
    android:toXDelta="100%">
</translate>

複製程式碼

ViewPropertyAnimator

  本質上和ValueAniamtor和ObjectAnimator相同,能夠很方便的為view提供動畫。

    button2.animate()
                .translationXBy(200)
                //.translationX(200)
                .setDuration(500);
複製程式碼

ViewProperty中帶by的方法含義是,相對於執行動畫View的現有狀態進行動畫,不帶by的方法含義是相對於View最初始狀態進行動畫。translationXBy(200)每次執行動畫,button2的位置都會相對於現有位置平移200px.translationX(200):不管執行多少次動畫,button2的位置都是相對於初始位置平移200px,換句話說button2會在第一次執行動畫時平移200px,後面執行動畫,button2的位置不會發生變化。

SpringAniamtion

  這是彈簧動畫;

  SpringForce spring = new SpringForce(0)
                .setDampingRatio(SpringForce.DAMPING_RATIO_HIGH_BOUNCY)
                .setStiffness(SpringForce.STIFFNESS_LOW);

        new SpringAnimation(rootLayout, DynamicAnimation.TRANSLATION_Y)
                .setSpring(spring)
                .setStartValue(-height)
                .setStartVelocity(-200)
                .start();
複製程式碼

SpringAniamtion可以實現旋轉,平移,縮放,透明度等的動畫。

  • setDampingRatio():設定阻尼係數,取值範圍在0 ~ 1之間,值越大彈簧效果越明顯。
  • setStiffness(): 設定剛性,取值範圍在0 ~ 1之間。值越小,彈簧震動次數也多。

相關文章