Android視圖動畫(補間動畫| 逐幀動畫)

本文章源碼

視圖動畫

視圖動畫可分爲:補間動畫逐幀動畫

一、補間動畫(Tweened Animation)

分類

補間動畫:

  • 平移動畫(TranslateAnimation)
  • 縮放動畫(ScaleAnimation)
  • 旋轉動畫(RotateAnimation)
  • 透明度動畫(AlphaAnimation)

如下圖,
在這裏插入圖片描述
可以看到途中幾個類都是Animation的子類。這4種動畫既能分開獨立實現,也可以組合實現複合動畫AnimationSet

缺點

  • 只能實現移動、縮放、旋轉和淡入淡出這四種動畫。
  • 只能改變View的顯示效果,不會改變View的屬性。

屬性動畫可以完美避免這兩缺點

優點

  • 簡單易用

使用

視圖(View)動畫的實現可以通過xml來定義,也可以通過Java代碼來動態設置。對於視圖動畫,建議使用xml來定義動畫,刻度性好,而且能夠複用。

資源建立步驟:

  1. 在res文件下右擊New->Directory新建anim文件夾
  2. anim文件下右擊New->Animation Resource File然後彈出彈窗 ;
    File name:文件名
    Root element:根節點類型(set、alpha、scale、translate、rotate…)

如下,使用xml來定義:
文件目錄:res/anim/animation_test.xml

<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android"
    android:interpolator="@[package:]anim/interpolator_resource"
    android:shareInterpolator=["true" | "false"] >
     <!--透明度動畫-->
    <alpha
        android:fromAlpha="float"
        android:toAlpha="float" />
    <!--縮放動畫-->
    <scale
        android:fromXScale="float"
        android:toXScale="float"
        android:fromYScale="float"
        android:toYScale="float"
        android:pivotX="float"
        android:pivotY="float" />
    <!--平移動畫-->
    <translate
        android:fromXDelta="float"
        android:toXDelta="float"
        android:fromYDelta="float"
        android:toYDelta="float" />
    <!--旋轉動畫-->    
    <rotate
        android:fromDegrees="float"
        android:toDegrees="float"
        android:pivotX="float"
        android:pivotY="float" />
    <set>
        ...
    </set>
</set>

公共屬性介紹:

動畫持續時間

  • xml屬性: android:duration="100"
  • Java方法:setDuration(100L)
  • 說明: 默認值是0 (單位ms)

動畫結束後是否保留動畫前的狀態

  • xml屬 性:android:fillAfter="true"
  • Java方法:setFillAfter(boolean)
  • 說明:動畫結束後是否保留動畫後的狀態,true保留動畫後狀態,false恢復原來狀態,默認值是false

動畫結束後是否保留動畫前的狀態

  • xml屬性:android:fillBefore="true"
  • Java方法:setFillBefore(boolean)
  • 說明:動畫結束後是否保留動畫前的狀態,true恢復原來狀態,false保留動畫後狀態,默認值是true

動畫的變化速率 即插值器

  • xml屬性:android:interpolator="@android:anim/accelerate_decelerate_interpolator"
  • Java方法:setInterpolator(Interpolator)
  • 說明:設置動畫的變化速率 即插值器,改變動畫變換的速度,默認值是@android:anim/accelerate_decelerate_interpolator,即加速減速插值器,在動畫開始和結束的時速度較慢,中間時候加速

動畫重複執行的次數

  • xml屬性:android:repeatCount="9"
  • Java方法:setRepeatCount(int)
  • 說明:設置動畫重複執行的次數,默認值是0

動畫重複的模式

  • xml屬性:android:repeatMode="reverse"
  • Java方法:setRepeatMode(int)
  • 說明:設置動畫重複模式,其值有restart(1):順序播放,reverse(2):重複的時候逆向播放

開始的延遲的時間

  • xml屬性:android:startOffset="0"
  • Java方法:setStartOffset(long)
  • 說明:設置開始的延遲的時間(單位ms),默認值是0

加載資源文件動畫

Animation animation = AnimationUtils.loadAnimation(this, R.anim.test_alpha);

View添加動畫

view.setAnimation(animation);

設置動畫監聽

animation.setAnimationListener(new Animation.AnimationListener() {
            @Override
            public void onAnimationStart(Animation animation) {
                //動畫開始時回掉
            }

            @Override
            public void onAnimationEnd(Animation animation) {
                //動畫結束時回掉(動畫最終結束)
            }

            @Override
            public void onAnimationRepeat(Animation animation) {
                 //動畫重複時回掉
            }
        });

啓動動畫

animation.start();
//或
view.startAnimation(animation);

結束動畫

animation.cancel();

詳細講解各動畫屬性

AlphaAnimation

作用:透明度動畫,改變視圖整體透明度,透明度值由1~0,從可見到不可見的變化。
xml實現
步驟:在anim文件,右擊new->Android Resource File ,文件名:alpha_test,根節點:alpha

<?xml version="1.0" encoding="utf-8"?>
<alpha xmlns:android="http://schemas.android.com/apk/res/android"
    android:fromAlpha="0.0"
    android:toAlpha="1.0"
    android:duration="2000">
</alpha>

各屬性含義:

  • android:fromAlpha: 表示透明度的起始值,這裏設置爲0.0,表示完全透明,取值範圍0~1;
  • android:toAlpha:表示透明度的結束值,這裏設置爲1.0,表示完全不透明,取值範圍0~1;
  • android:duration:表示動畫持續的時間,這裏設置爲2000,單位是毫秒;

Java代碼中使用xml:使用AnimationUtils類的靜態方法loadAnimation()來加載XML文件,得到一個Animation對象,如下:

Animation animation = AnimationUtils.loadAnimation(this, R.anim.alpha);
mImage.startAnimation(animation);

Java實現

AlphaAnimation alphaAnimation = new AlphaAnimation(0f, 1f);
alphaAnimation.setDuration(3000);
mImage.startAnimation(alphaAnimation);

構造方法:

  1. 通過加載資源文件
    /**
     * Constructor used when an AlphaAnimation is loaded from a resource. 
     * 
     * @param context Application context to use
     * @param attrs Attribute set from which to read values
     */
    public AlphaAnimation(Context context, AttributeSet attrs) {
        super(context, attrs);
    }
    
  2. 通過代碼構建動畫
     /**
      * Constructor to use when building an AlphaAnimation from code
      * 
      * @param fromAlpha Starting alpha value for the animation, where 1.0 means
      *        fully opaque and 0.0 means fully transparent.
      * @param toAlpha Ending alpha value for the animation.
      */
     public AlphaAnimation(float fromAlpha, float toAlpha) {
         mFromAlpha = fromAlpha;
         mToAlpha = toAlpha;
     }
    

ScaleAnimation

縮放動畫,需要一個座標點來,即軸點,實現以不同的軸點縮放效果,因此需要先指定pivotXpivotY確定軸座標。默認情況下,從對象View的左上角開始縮放。
xml實現
該動畫通過標籤<scale/>實現的,如下:

<?xml version="1.0" encoding="utf-8"?>
<scale xmlns:android="http://schemas.android.com/apk/res/android"
       android:duration="3000"
       android:fromXScale="0.0"
       android:fromYScale="0.0"
       android:pivotX="50%"
       android:pivotY="50%"
       android:toXScale="1.0"
       android:toYScale="1.0">
</scale>

各屬性如下:

  • android:fromXScale: 動畫開始時,水平方向縮放係數。
  • android:fromYScale: 動畫開始時,垂直方向縮放係數。
  • android:toXScale: 動畫結束時,水平方向縮放係數。
  • android:toYScale:動畫結束時,垂直方向縮放係數。
  • android:pivotX:縮放軸點的X座標(其值可以爲:數值、百分數、百分數p),例如:如50表示以當前View左上角座標加50px爲初始點、50%表示以當前View的左上角加上當前View寬高的50%做爲初始點、50%p表示以當前View的左上角加上父控件寬高的50%做爲初始點)。
  • android:pivotY:縮放軸點的Y座標,規律同pivotX。

java實現
需要使用Animation的子類ScaleAnimation來實現,代碼如下:

        ScaleAnimation scaleAnimation = new ScaleAnimation(0, 1, 0, 1, 
             Animation.RELATIVE_TO_SELF, 0.5f, Animation.RELATIVE_TO_SELF, 0.5f);
        scaleAnimation.setDuration(3000);
        mImage.startAnimation(scaleAnimation);

構造方法:

    // 1. 
    /**
     * Constructor used when a ScaleAnimation is loaded from a resource.
     * 
     * @param context Application context to use
     * @param attrs Attribute set from which to read values
     */
    public ScaleAnimation(Context context, AttributeSet attrs) {
        super(context, attrs);
  }

    // 2. 
    /**
     * Constructor to use when building a ScaleAnimation from code
     * 
     * @param fromX Horizontal scaling factor to apply at the start of the
     *        animation
     * @param toX Horizontal scaling factor to apply at the end of the animation
     * @param fromY Vertical scaling factor to apply at the start of the
     *        animation
     * @param toY Vertical scaling factor to apply at the end of the animation
     */
    public ScaleAnimation(float fromX, float toX, float fromY, float toY) {
        mResources = null;
        mFromX = fromX;
        mToX = toX;
        mFromY = fromY;
        mToY = toY;
        mPivotX = 0;
        mPivotY = 0;
    }

    //3. 
    /**
     * Constructor to use when building a ScaleAnimation from code
     * 
     * @param fromX Horizontal scaling factor to apply at the start of the
     *        animation
     * @param toX Horizontal scaling factor to apply at the end of the animation
     * @param fromY Vertical scaling factor to apply at the start of the
     *        animation
     * @param toY Vertical scaling factor to apply at the end of the animation
     * @param pivotX The X coordinate of the point about which the object is
     *        being scaled, specified as an absolute number where 0 is the left
     *        edge. (This point remains fixed while the object changes size.)
     * @param pivotY The Y coordinate of the point about which the object is
     *        being scaled, specified as an absolute number where 0 is the top
     *        edge. (This point remains fixed while the object changes size.)
     */
    public ScaleAnimation(float fromX, float toX, float fromY, float toY,
            float pivotX, float pivotY) {

      }
    
    // 4.
    /**
     * Constructor to use when building a ScaleAnimation from code
     * 
     * @param fromX Horizontal scaling factor to apply at the start of the
     *        animation
     * @param toX Horizontal scaling factor to apply at the end of the animation
     * @param fromY Vertical scaling factor to apply at the start of the
     *        animation
     * @param toY Vertical scaling factor to apply at the end of the animation
     * @param pivotXType Specifies how pivotXValue should be interpreted. One of
     *        Animation.ABSOLUTE, Animation.RELATIVE_TO_SELF, or
     *        Animation.RELATIVE_TO_PARENT.
     * @param pivotXValue The X coordinate of the point about which the object
     *        is being scaled, specified as an absolute number where 0 is the
     *        left edge. (This point remains fixed while the object changes
     *        size.) This value can either be an absolute number if pivotXType
     *        is ABSOLUTE, or a percentage (where 1.0 is 100%) otherwise.
     * @param pivotYType Specifies how pivotYValue should be interpreted. One of
     *        Animation.ABSOLUTE, Animation.RELATIVE_TO_SELF, or
     *        Animation.RELATIVE_TO_PARENT.
     * @param pivotYValue The Y coordinate of the point about which the object
     *        is being scaled, specified as an absolute number where 0 is the
     *        top edge. (This point remains fixed while the object changes
     *        size.) This value can either be an absolute number if pivotYType
     *        is ABSOLUTE, or a percentage (where 1.0 is 100%) otherwise.
     */
    public ScaleAnimation(float fromX, float toX, float fromY, float toY,
            int pivotXType, float pivotXValue, int pivotYType, float pivotYValue) {

     }

RotateAnimation

旋轉動畫,與縮放動畫較爲相似,也需要一個軸點來實現旋轉。默認情況下,從對象view的左上角開始旋轉,也即是相對於當前view座標爲(0,0)位置。
在xml實現
該動畫是通過標籤實現的,實現代碼如下:

<?xml version="1.0" encoding="utf-8"?>
<rotate xmlns:android="http://schemas.android.com/apk/res/android"
        android:duration="3000"
        android:pivotX="50%"
        android:pivotY="50%"
        android:fromDegrees="0"
        android:toDegrees="90">
 
</rotate>

各屬性含義:

  • android:pivotX:旋轉軸點的X座標(其值可以爲:數值、百分數、百分數p),例如:如50表示以當前View左上角座標加50px爲初始點、50%表示以當前View的左上角加上當前View寬高的50%做爲初始點、50%p表示以當前View的左上角加上父控件寬高的50%做爲初始點)。
  • android:pivotY:旋轉軸點的Y座標,規律同android:pivotX
  • android:fromDegrees:旋轉開始的角度,其值可以爲正負。
  • android:toDegrees: 旋轉結束的角度,其值可以爲正負。
  • ps:toDegrees-fromDegrees> 0,則順時針旋轉;否則,逆時針旋轉。

java實現
需要使用Animation的子類RotateAnimation 來實現,代碼如下:

	    RotateAnimation rotateAnimation = new RotateAnimation(0,180);
        rotateAnimation.setDuration(3000);
        mImage.startAnimation(rotateAnimation);

構造方法:

    // 1.
    /**
     * Constructor used when a RotateAnimation is loaded from a resource.
     * 
     * @param context Application context to use
     * @param attrs Attribute set from which to read values
     */
    public RotateAnimation(Context context, AttributeSet attrs) {
        super(context, attrs);
    }

    // 2.
    /**
     * Constructor to use when building a RotateAnimation from code.
     * Default pivotX/pivotY point is (0,0).
     * 
     * @param fromDegrees Rotation offset to apply at the start of the
     *        animation.
     * 
     * @param toDegrees Rotation offset to apply at the end of the animation.
     */
    public RotateAnimation(float fromDegrees, float toDegrees) {
       
    }

    // 3. 
    /**
     * Constructor to use when building a RotateAnimation from code
     * 
     * @param fromDegrees Rotation offset to apply at the start of the
     *        animation.
     * 
     * @param toDegrees Rotation offset to apply at the end of the animation.
     * 
     * @param pivotX The X coordinate of the point about which the object is
     *        being rotated, specified as an absolute number where 0 is the left
     *        edge.
     * @param pivotY The Y coordinate of the point about which the object is
     *        being rotated, specified as an absolute number where 0 is the top
     *        edge.
     */
    public RotateAnimation(float fromDegrees, float toDegrees, float pivotX, float pivotY) {
        mFromDegrees = fromDegrees;
        mToDegrees = toDegrees;

        mPivotXType = ABSOLUTE;
        mPivotYType = ABSOLUTE;
        mPivotXValue = pivotX;
        mPivotYValue = pivotY;
        initializePivotPoint();
    }

    //4. 
    /**
     * Constructor to use when building a RotateAnimation from code
     * 
     * @param fromDegrees Rotation offset to apply at the start of the
     *        animation.
     * 
     * @param toDegrees Rotation offset to apply at the end of the animation.
     * 
     * @param pivotXType Specifies how pivotXValue should be interpreted. One of
     *        Animation.ABSOLUTE, Animation.RELATIVE_TO_SELF, or
     *        Animation.RELATIVE_TO_PARENT.
     * @param pivotXValue The X coordinate of the point about which the object
     *        is being rotated, specified as an absolute number where 0 is the
     *        left edge. This value can either be an absolute number if
     *        pivotXType is ABSOLUTE, or a percentage (where 1.0 is 100%)
     *        otherwise.
     * @param pivotYType Specifies how pivotYValue should be interpreted. One of
     *        Animation.ABSOLUTE, Animation.RELATIVE_TO_SELF, or
     *        Animation.RELATIVE_TO_PARENT.
     * @param pivotYValue The Y coordinate of the point about which the object
     *        is being rotated, specified as an absolute number where 0 is the
     *        top edge. This value can either be an absolute number if
     *        pivotYType is ABSOLUTE, or a percentage (where 1.0 is 100%)
     *        otherwise.
     */
    public RotateAnimation(float fromDegrees, float toDegrees, int pivotXType, float pivotXValue,
            int pivotYType, float pivotYValue) {
        mFromDegrees = fromDegrees;
        mToDegrees = toDegrees;

        mPivotXValue = pivotXValue;
        mPivotXType = pivotXType;
        mPivotYValue = pivotYValue;
        mPivotYType = pivotYType;
        initializePivotPoint();
    }

TranslateAnimation
平移動畫,實現視圖垂直/水平方向位移變化,指定開始的位置,和結束的位置即可。
xml實現:

<?xml version="1.0" encoding="utf-8"?>
<translate xmlns:android="http://schemas.android.com/apk/res/android"
           android:fillAfter="true"
           android:duration="3000"
           android:fromXDelta="50%"
           android:fromYDelta="50%"
           android:toXDelta="50%p"
           android:toYDelta="50%p">
</translate>

各屬性含義:

  • android:fromXDelta: 平移開始X方向座標(其值可以爲:數值、百分數、百分數p,且多可以爲正負),其值含義與android:pivotX類似。
  • android:fromYDelta:平移開始Y方向座標(其值可以爲:數值、百分數、百分數p,且多可以爲正負),其值含義與android:pivotY類似。
  • android:toXDelta:平移結束X方向座標(其值可以爲:數值、百分數、百分數p,且多可以爲正負),其值含義與android:pivotX類似。
  • android:toYDelta:平移結束Y方向座標(其值可以爲:數值、百分數、百分數p,且多可以爲正負),其值含義與android:pivotY類似。

java實現
需要使用Animation的子類TranslateAnimation來實現,代碼如下:

    	TranslateAnimation translateAnimation = new TranslateAnimation(Animation.RELATIVE_TO_SELF,0,Animation.RELATIVE_TO_SELF,0,Animation.RELATIVE_TO_PARENT,0,Animation.RELATIVE_TO_PARENT,0.5f);
        translateAnimation.setDuration(3000);
        translateAnimation.setFillAfter(true);
        mImage.startAnimation(translateAnimation);

構造函數:

    // 1.
    /**
     * Constructor used when a TranslateAnimation is loaded from a resource.
     *
     * @param context Application context to use
     * @param attrs Attribute set from which to read values
     */
    public TranslateAnimation(Context context, AttributeSet attrs) {
        super(context, attrs);
    }

     // 2. 
     /**
     * Constructor to use when building a TranslateAnimation from code
     *
     * @param fromXDelta Change in X coordinate to apply at the start of the
     *        animation
     * @param toXDelta Change in X coordinate to apply at the end of the
     *        animation
     * @param fromYDelta Change in Y coordinate to apply at the start of the
     *        animation
     * @param toYDelta Change in Y coordinate to apply at the end of the
     *        animation
     */
    public TranslateAnimation(float fromXDelta, float toXDelta, float fromYDelta, float toYDelta) {
        mFromXValue = fromXDelta;
        mToXValue = toXDelta;
        mFromYValue = fromYDelta;
        mToYValue = toYDelta;

        mFromXType = ABSOLUTE;
        mToXType = ABSOLUTE;
        mFromYType = ABSOLUTE;
        mToYType = ABSOLUTE;
    }

     // 3. 
     /**
     * Constructor to use when building a TranslateAnimation from code
     * 
     * @param fromXType Specifies how fromXValue should be interpreted. One of
     *        Animation.ABSOLUTE, Animation.RELATIVE_TO_SELF, or
     *        Animation.RELATIVE_TO_PARENT.
     * @param fromXValue Change in X coordinate to apply at the start of the
     *        animation. This value can either be an absolute number if fromXType
     *        is ABSOLUTE, or a percentage (where 1.0 is 100%) otherwise.
     * @param toXType Specifies how toXValue should be interpreted. One of
     *        Animation.ABSOLUTE, Animation.RELATIVE_TO_SELF, or
     *        Animation.RELATIVE_TO_PARENT.
     * @param toXValue Change in X coordinate to apply at the end of the
     *        animation. This value can either be an absolute number if toXType
     *        is ABSOLUTE, or a percentage (where 1.0 is 100%) otherwise.
     * @param fromYType Specifies how fromYValue should be interpreted. One of
     *        Animation.ABSOLUTE, Animation.RELATIVE_TO_SELF, or
     *        Animation.RELATIVE_TO_PARENT.
     * @param fromYValue Change in Y coordinate to apply at the start of the
     *        animation. This value can either be an absolute number if fromYType
     *        is ABSOLUTE, or a percentage (where 1.0 is 100%) otherwise.
     * @param toYType Specifies how toYValue should be interpreted. One of
     *        Animation.ABSOLUTE, Animation.RELATIVE_TO_SELF, or
     *        Animation.RELATIVE_TO_PARENT.
     * @param toYValue Change in Y coordinate to apply at the end of the
     *        animation. This value can either be an absolute number if toYType
     *        is ABSOLUTE, or a percentage (where 1.0 is 100%) otherwise.
     */
    public TranslateAnimation(int fromXType, float fromXValue, int toXType, float toXValue,
            int fromYType, float fromYValue, int toYType, float toYValue) {

        mFromXValue = fromXValue;
        mToXValue = toXValue;
        mFromYValue = fromYValue;
        mToYValue = toYValue;

        mFromXType = fromXType;
        mToXType = toXType;
        mFromYType = fromYType;
        mToYType = toYType;
    }
 

AnimationSet
集合動畫,如果單一的動畫太過於單調,那麼就可以將這些單一的動畫組合成個性酷炫的動畫,同時指定播放的順序,並且集合裏面可以再包含集合。但注意的是,在集合設置的屬性對該標籤下的所有子控件都產生影響。
xml實現

<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android"
     android:shareInterpolator="false">
    <scale
        android:duration="2000"
        android:fromXScale="1.0"
        android:fromYScale="1.0"
        android:interpolator="@android:anim/linear_interpolator"
        android:pivotX="50%"
        android:pivotY="50%"
        android:toXScale="0"
        android:toYScale="0"/>
 
    <set
        android:duration="2000"
        android:interpolator="@android:anim/decelerate_interpolator"
        android:shareInterpolator="true"
        android:startOffset="2000">
        <scale
            android:fromXScale="0"
            android:fromYScale="0"
            android:pivotX="50%"
            android:pivotY="50%"
            android:toXScale="1"
            android:toYScale="1"/>
        <rotate
            android:fromDegrees="0"
            android:pivotX="50%"
            android:pivotY="50%"
            android:toDegrees="180"/>
    </set>
</set>

屬性含義:

  • android:shareInterpolator:子元素是否共享插值器,值爲true,表示共同使用;值爲false,表示不共享
    其餘屬性多和其他類似,
  • android:startOffset:設置需要設置播放的順序。
    java實現
	    AnimationSet animationSet1 = new AnimationSet(false);//一級集合
        ScaleAnimation scaleAnimation1 = new ScaleAnimation(1, 1.4f, 1, 1.4f, Animation.RELATIVE_TO_SELF, 0.5f,Animation.RELATIVE_TO_SELF, 0.5f);
 
        AnimationSet animationSet2 = new AnimationSet(true);//二級集合
        ScaleAnimation scaleAnimation2 = new ScaleAnimation(1.4f, 0, 1.4f, 0, Animation.RELATIVE_TO_SELF, 0.5f,Animation.RELATIVE_TO_SELF, 0.5f);
        RotateAnimation rotateAnimation = new RotateAnimation(0, 180, Animation.RELATIVE_TO_SELF, 0.5f,Animation.RELATIVE_TO_SELF, 0.5f);
 
        animationSet2.addAnimation(scaleAnimation2);
        animationSet2.addAnimation(rotateAnimation);
        animationSet2.setInterpolator(new DecelerateInterpolator());
        animationSet2.setDuration(2000);
        animationSet2.setStartOffset(2000);
 
        animationSet1.addAnimation(scaleAnimation1);
        animationSet1.addAnimation(animationSet2);
        animationSet1.setInterpolator(new AccelerateDecelerateInterpolator());
        animationSet1.setDuration(2000);
 
        mImage.startAnimation(animationSet1);

構造函數:

    // 1.
    /**
     * Constructor used when an AnimationSet is loaded from a resource.
     *
     * @param context Application context to use
     * @param attrs Attribute set from which to read values
     */
    public AnimationSet(Context context, AttributeSet attrs) {
        super(context, attrs);

        TypedArray a =
            context.obtainStyledAttributes(attrs, com.android.internal.R.styleable.AnimationSet);

        setFlag(PROPERTY_SHARE_INTERPOLATOR_MASK,
                a.getBoolean(com.android.internal.R.styleable.AnimationSet_shareInterpolator, true));
        init();

        if (context.getApplicationInfo().targetSdkVersion >=
                Build.VERSION_CODES.ICE_CREAM_SANDWICH) {
            if (a.hasValue(com.android.internal.R.styleable.AnimationSet_duration)) {
                mFlags |= PROPERTY_DURATION_MASK;
            }
            if (a.hasValue(com.android.internal.R.styleable.AnimationSet_fillBefore)) {
                mFlags |= PROPERTY_FILL_BEFORE_MASK;
            }
            if (a.hasValue(com.android.internal.R.styleable.AnimationSet_fillAfter)) {
                mFlags |= PROPERTY_FILL_AFTER_MASK;
            }
            if (a.hasValue(com.android.internal.R.styleable.AnimationSet_repeatMode)) {
                mFlags |= PROPERTY_REPEAT_MODE_MASK;
            }
            if (a.hasValue(com.android.internal.R.styleable.AnimationSet_startOffset)) {
                mFlags |= PROPERTY_START_OFFSET_MASK;
            }
        }

        a.recycle();
    }
 
    // 2. 
    /**
     * Constructor to use when building an AnimationSet from code
     *
     * @param shareInterpolator Pass true if all of the animations in this set
     *        should use the interpolator associated with this AnimationSet.
     *        Pass false if each animation should use its own interpolator.
     */
    public AnimationSet(boolean shareInterpolator) {
        setFlag(PROPERTY_SHARE_INTERPOLATOR_MASK, shareInterpolator);
        init();
    }

問題

你是否真正的明白 pivotX 的含義?

軸點座標值pivotX,pivotY,有三種表達方式:在xml文件,其值有3種類型:數值、百分數、百分數p;在java代碼中,其值要根據,三種座標類型(前方有介紹)來確定。
一般,對於表達方式的第一種、第二種,應該是比較常用的,而且也是比較好理解的,也比較直觀。那麼問題來了:

提出問題
如果是使用第三種,相對於父控件定位,你是否能夠準確找到軸點位置?是否知道其真正的含義?

猜想
pivotX = 50%,那麼軸點就在該控件(沒有覆蓋整個屏幕)的中間位置;pivotX = 50%p,那麼中心點相對於父控件(覆蓋了整個屏幕)就是屏幕的中間點。
對於這個想法,我…我…我…剛開始是這樣子想的…

實踐
我們用平移動畫來實踐,保留動畫結束的幀,將其參數設置爲:

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

從相當於父控件的(0,0) 移動到 父控件的(50%,50%),但實際效果是這樣子的,與猜想不符:
具體效果請看

探索
我們可以點進去看TranslateAnimation ,可以發現:

    @Override
    public void initialize(int width, int height, int parentWidth, int parentHeight) {
        super.initialize(width, height, parentWidth, parentHeight);
        mFromXDelta = resolveSize(mFromXType, mFromXValue, width, parentWidth);
        mToXDelta = resolveSize(mToXType, mToXValue, width, parentWidth);
        mFromYDelta = resolveSize(mFromYType, mFromYValue, height, parentHeight);
        mToYDelta = resolveSize(mToYType, mToYValue, height, parentHeight);
    }

   // 然後再看resolveSize()方法
   protected float resolveSize(int type, float value, int size, int parentSize) {
        switch (type) {
            case ABSOLUTE:
                return value;
            case RELATIVE_TO_SELF:
                return size * value;
            case RELATIVE_TO_PARENT:
                return parentSize * value;
            default:
                return value;
        }
    }

// 也許,看到這裏,反而覺得猜想沒有錯。其實動畫真正的實現是在這裏:

    @Override
    protected void applyTransformation(float interpolatedTime, Transformation t) {
        float dx = mFromXDelta;
        float dy = mFromYDelta;
        if (mFromXDelta != mToXDelta) {
            dx = mFromXDelta + ((mToXDelta - mFromXDelta) * interpolatedTime);
        }
        if (mFromYDelta != mToYDelta) {
            dy = mFromYDelta + ((mToYDelta - mFromYDelta) * interpolatedTime);
        }
        t.getMatrix().setTranslate(dx, dy);
    }

這裏,我們發現,動畫需要繪製的軌跡是dx = mToXDelta ,dy = mToYDelta ,這個值是相對於該控件 需要變化的距離,而不是最終的位置,那麼最終猜想:
如果該控件剛好位於屏幕的左上角,則mToXValue就是動畫結束的位置;
如果該控件不在屏幕的左上角,則最終動畫後的座標需要加上該控件這個座標;
最後用表達式表示:
toXValue = fromXType + dx;
toYType = fromYValue + dy;

二、幀動畫(Frame Animation)

實現

  1. 在res文件下右擊New->Directory新建drawable文件夾
  2. anim文件下右擊New->Drawable Resource File然後彈出彈窗 ;
    File name:文件名
    Root element:根節點類型(選擇 animation-list)

創建資源xml代碼(res/drawable/frame_view.xml)

   <?xml version="1.0" encoding="utf-8"?>
   <animation-list xmlns:android="http://schemas.android.com/apk/res/android">

       <item
          android:drawable="@drawable/sign_icon_1"
          android:duration="50" />
       <item
          android:drawable="@drawable/sign_icon_2"
          android:duration="50" />
        <item
          android:drawable="@drawable/sign_icon_3"
          android:duration="50" />
        <item
          android:drawable="@drawable/sign_icon_4"
          android:duration="50" />

   </animation-list>

使用(res/layout/activity_frame_animation.xml)

 <?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:gravity="center">

    <ImageView
        android:id="@+id/image"
        android:layout_width="100dp"
        android:layout_height="100dp"
        android:src="@drawable/frame_view" />
</LinearLayout>

開啓動畫:

        ImageView imageView = findViewById(R.id.image);
        AnimationDrawable animationDrawable = (AnimationDrawable) imageView.getDrawable();
        if (animationDrawable != null) {
            animationDrawable.start();
        }

三、資源

本文章源碼

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章