Android教程網
  1. 首頁
  2. Android 技術
  3. Android 手機
  4. Android 系統教程
  5. Android 游戲
 Android教程網 >> Android技術 >> 關於Android編程 >> Android動畫之視圖動畫和屬性動畫

Android動畫之視圖動畫和屬性動畫

編輯:關於Android編程

Android 動畫分為兩大類,分別是視圖動畫(View Animation)和屬性動畫(Property Animation)。對於這兩種動畫,都能夠使用xml和代碼的形式定義動畫。

View Animation

視圖動畫是Android最基礎的動畫,在API 1中就已經加入,不需考慮兼容性,但由於其動畫只是作用於視圖上,而不會由該控件的屬性,所以有很多的局限性。

視圖動畫的基類是Animation其下包含了四個直接的子類

AlphaAnimation: 透明度動畫 TranslateAnimation:平移動畫 ScaleAnimation:縮放動畫 RotateAnimation:旋轉動畫 AnimationSet:動畫集合

Animation 公共常用方法

xml屬性 java 方法 解釋 android:duration setDuration(long) 設置動畫執行的時間 android:fillAfter setFillAfter(boolean) 設置動畫是否保持其結束時的狀態,默認false,不保存 android:fillBefore setFillBefore(boolean) 設置動畫結束時是否回到其動畫初始之前的狀態,默認為true。當設置為false時,需要fillEnabled屬性為true android:fillEnabled setFillEnable(boolean) 當該屬性設置為true時,fillBefore(false)屬性才能生效。 android:interpolator setInterpolator(Interpolator) 設置插值器,及動畫執行的變化的速率。及一直勻速,或前快後慢等 android:repeatCount setRepeatCount(int) 設置動畫重復執行的次數,默認為0,及不重復執行 android:repeatMode setRepeatMode(int) 設置動畫重復執行的模式,可取值REVERSE:重復執行時,按照倒序。RESTART:從頭開始 android:startOffset setStartOffset(long) 設置動畫延遲執行的時間

View Animation 通過xml文件構造動畫時,其資源文件存放在 res-》anim。 這個需要我們手動創建anim文件夾。

我們將實現如下例子,用以學習View Animation
這裡寫圖片描述

AlphaAnimation

java代碼定義動畫

//初始透明度,結束時的透明度  取值范圍1.0~0.0
        AlphaAnimation anim= new AlphaAnimation(1,0);
        //RepeatCount ,動畫執行結束後的重復次數,如果大於0,則重復次數。默認是0
        //如果小於0,默認是Animation.INFINITE
        anim.setRepeatCount(1); //重復1次
        //Animation.RESTART  從頭開始。  Animation.REVERSE :反轉
        anim.setRepeatMode(Animation.REVERSE);  
        anim.setDuration(1000);


        img.startAnimation(anim);
xml定義動畫
創建 res-》anim-》view_alpha.xml 文件。
<code class="language-xml hljs "><alpha xmlns:android="http://schemas.android.com/apk/res/android" android:duration="1000" android:repeatmode="reverse" android:repeatcount="1" android:fromalpha="1" android:toalpha="0">
</alpha>
</code>

在java代碼中通過AnimationUtils加載xml文件,構造動畫對象。對於View Aniamtion,都是通過該方法加載xml文件。

Animation animation = AnimationUtils.loadAnimation(getApplicationContext(), R.anim.view_alpha);
img.startAnimation(animation);

RotateAnimation 旋轉動畫

java 代碼創建

        RotateAnimation anim = new RotateAnimation(0f,180f,Animation.RELATIVE_TO_SELF,0.5f,Animation.RELATIVE_TO_SELF,0.5f);
        anim.setDuration(500);
        //設置為true ,則保持動畫結束後的狀態,默認false
        anim.setFillAfter(true); 

        img.startAnimation(anim);

在RotateAnimation中最全參數的構造方法如下RotateAnimation(float fromDegrees, float toDegrees, int pivotXType, float pivotXValue, int pivotYType, float pivotYValue)參數解釋如下:

fromDegrees:起始的度數 toDegrees:結束時的度數 pivotXTypepivotYType:旋轉時參照的動畫中心點的位置類型。可選值:RELATIVE_TO_SELF依據自身為參照。RELATIVE_TO_PARENT 依據其所在的父控件為參照

pivotXValuepivotYValue:百分比值。與上面的參數配合使用。例如對於X軸來說,如果類型是RELATIVE_TO_SELF,值是0.5f,則就是位於當前控件x軸的中心。

xml創建動畫

<code class="language-xml hljs "><rotate xmlns:android="http://schemas.android.com/apk/res/android" android:duration="500" android:fillafter="true" android:fromdegrees="0" android:todegrees="180" android:pivotx="50%" android:pivoty="50%">
</rotate>
</code>

ScaleAnimation 縮放動畫

java 代碼實現

        ScaleAnimation anim = new ScaleAnimation(1f,0.5f,1f,0.5f,0.5f,0.f);
        anim.setDuration(500);
        img.startAnimation(anim);

對於ScaleAnimation,仍然看他構造方法中參數最多的。

ScaleAnimation(float fromX, float toX, float fromY, float toY, int pivotXType, float pivotXValue, int pivotYType, float pivotYValue)

fromX:動畫開始時x軸方向控件縮放的比例。 toX:動畫結束時x軸方向控件縮放的比例。 fromY:動畫開始時y軸方向控件縮放的比例。 toY:動畫結束時y軸方向控件縮放的比例。 pivotXType,pivotYType:縮放時中心點的參照物。類比旋轉

pivotXValue,pivotYValue:縮放時中心點相對於其參照物的位置。類比旋轉。

xml實現

<code class="language-xml hljs "><scale xmlns:android="http://schemas.android.com/apk/res/android" android:duration="1000" android:fromxscale="1" android:toxscale="0.5" android:fromyscale="1" android:toyscale="0.5" android:pivotx="50%" android:pivoty="50%">

TraslateAnimation 位移動畫

java代碼實現

 TranslateAnimation anim = new TranslateAnimation(Animation.RELATIVE_TO_SELF,0f,Animation.RELATIVE_TO_SELF,1f,
                Animation.RELATIVE_TO_SELF,0f,Animation.RELATIVE_TO_SELF,1f);

        anim.setDuration(500);

        img.startAnimation(anim);

TranslateAnimation(int fromXType, float fromXValue, int toXType, float toXValue,int fromYType, float fromYValue, int toYType, float toYValue)

其構造函數是類型和值是成對出現的。
- type表示當前值是相對於父控件還是其本身。
- value:偏移量的百分比。取值0.0~1.0;

xml 代碼實現

<code class="language-xml hljs "><translate xmlns:android="http://schemas.android.com/apk/res/android" android:duration="500" android:fromxdelta="0%" android:toxdelta="100%" android:fromydelta="0%" android:toydelta="100%">

AnimationSet 動畫集合

動畫集合相當於是把單一動畫整合一起之後同時執行。

java 代碼實現

        //shareInterpolator  true 使用set的差值器 ,false :使用自身的差值器
        AnimationSet set = new AnimationSet(true);


        ScaleAnimation anim = new ScaleAnimation(1f,0.5f,1f,0.5f,0.5f,0.f);
        anim.setDuration(500);

        RotateAnimation anim1 = new RotateAnimation(0f,180f,Animation.RELATIVE_TO_SELF,0.5f,Animation.RELATIVE_TO_SELF,0.5f);
        anim.setDuration(500);

        set.addAnimation(anim);
        set.addAnimation(anim1);

        set.setDuration(500); //設置動畫時間,不然動畫執行時間有問題,和想象中的各自執行疊加不同

        img.startAnimation(set);

AnimationSet中有幾個關鍵點。

AnimationSet的構造方法,會傳入一個布爾值,當為true時,表示其所加入的動畫的插值器使用AnimationSet所設置的插值器。false:標識其所加入的動畫使用他們自己所設置的插值器。

通過addAniamtion(anim)添加動畫。

需要設置動畫時間。

xml 代碼實現

<code class="language-xml hljs "><set xmlns:android="http://schemas.android.com/apk/res/android" android:duration="500">

    <translate android:fromxdelta="0%" android:toxdelta="100%" android:fromydelta="0%" android:toydelta="100%">


    <rotate android:fromdegrees="0" android:todegrees="180" android:pivoty="50%" android:pivotx="50%">


</rotate></translate></set></code>

總結:視圖動畫改變的是動畫的顯示效果,但實際,其本身包含的屬性,寬,高,所處位置等等並沒有改變。

Property Aniamtion

屬性動畫是Android 3.0 之後引入的新的動畫。從其定義的名稱就可以看出,他和視圖動畫的區別就在於,他是通過改變控件的屬性已達到動畫的效果的。但因為其從Android3.0加入,所以我們的app最小sdk必須11以上。這個在現在應該不是問題。3.0一下的市場占有率已經很少了。

視圖動畫的基類是Animation,而屬性動畫的基類是Animator

在Animator中同樣有一些公用的方法,下面列舉一些常用的方法

pause():暫停一個正在運行的動畫 resume():恢復一個暫停的動畫 setDuration(): 設置動畫執行的時間 setInterpolator(): 設置動畫的插值器 setStartDelay(): 設置動畫延遲執行的時間 setTarget(): 設置動畫將要作用的對象 start():啟動動畫

通過google的文檔可以看到,Animator的結構圖如下

這裡寫圖片描述
可以看到其下分為兩個子類ValueAnimator,單一動畫的基類。AniamtorSet動畫集合。<喎?/kf/ware/vc/" target="_blank" class="keylink">vcD4NCjxwPsTHw7TO0sPHvs2/qsq80ru49tK7uPa1xLfWzvbL+8PHtcTKudPDoaO/tNK7z8LA/dfTPC9wPg0KPHA+PGltZyBhbHQ9"這裡寫圖片描述" src="/uploadfile/Collfiles/20160514/20160514090903201.gif" title="\" />

將會首先按照代碼的方式分析,xml文件的格式構造動畫的放在最後。

ValueAnimator

該類是屬性動畫中單一動畫的基類。該類總結性的說,他可以定義初始值,結束值,時間。然後會這個時間段中,按照一定的規則,從初始值開始逐漸向結束值過渡,通過產生的一系列過渡值設置控件的屬性形成了動畫效果。

通過以上的總結,我們明確了幾個關鍵字,初始值,結束值,時間,產生的過渡值。對於時間,我們知道在其父類Animator中有設置時間的方法。那麼ValueAnimator是如何定義初始值和結束值的呢?

在google的文檔中,有如下方法

這裡寫圖片描述

他們的參數都是可變參數,意思是,我們可以傳入一系列值,按照這一系列值進行變換。

ofArgb: ARGB,色值嗎。 按照顏色的格式進行過渡。 ofFloat:浮點類型進行過渡。 ofInt:整形。 ofObject:不知道什麼意思。通過對象來過渡。後面在說吧。 ofPropertyValueHolder:通過PropertyValueHolder構造。下面會說。

ok,現在我們設置了初始值,結束值,事件,那麼我們如何獲取這個過渡值呢,很明顯,他肯定有監聽的回調方法。

addUpdateListener:該方法回監聽每次動畫過渡值得修改並回調。那麼我們看一下例子

ValueAnimator anim = ValueAnimator.ofFloat(1f, 0f,1f)
                .setDuration(1000);

 anim.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
            @Override
            public void onAnimationUpdate(ValueAnimator animation) {
                //根據動畫的過渡產生數量值,通過getAnimatedValue獲取變化的值
                float offset = (float) animation.getAnimatedValue();
                //設置透明度
                img.setAlpha(offset);
                //設置縮放
                img.setScaleX(offset);
                img.setScaleY(offset);

            }
        });

        anim.start();

那麼動畫,會先是縮小的同時慢慢的透明,然後又慢慢的放大並顯現。

ObjectAnimation

ObjectAniamtorValueAnimator的子類,從編程思想上分析,他肯定是對他的父類做了一些封裝,添加了一些新的功能。及更加的細致。那麼,他的細致在哪買呢?

我們在用ValueAnimator時,還需要設置監聽,就不能添加一些,比如旋轉,縮放等之類的常用的屬性讓我設置,省得設置監聽回調了。ok,ObjectAnimator就干了這件事。

仍然根據我們的關鍵字,來分析。由於其繼承ValueAnimator,那麼肯定有of..方法。不過他在此基礎上,添加了一些參數。因為原理相同,只分析ofFloat(其實只是懶)。

ofFloat(Object target, String propertyName, float... values),多了兩個參數。起始很好理解。如果讓我們對ValueAnimator進行二次封裝,需要的無非就是,我要改變的屬性,以及我要作用的對象。ok,就是這兩個參數。

target:作用的對象。 proepertyName:作用對象的屬性。 values:可變參數,你猜他是什麼意思。

那麼用法也非常簡單

ObjectAnimator anim = ObjectAnimator.ofFloat(img, "rotation", 0f, 360f)
                .setDuration(1000);

        anim.start();

可見,大大的節省了代碼量。

那麼對於propertyName,我們都可以設置那些值呢。

translationXtranslationY :相對於控件本身先x,y軸的偏移量。與x,y類比。 xy:相對於其所在父控件的x,y軸的偏移量。其與上面的屬性,都是按照像素進行偏移。 rotationrotationXrotationY:旋轉,分別是繞中心點的2d旋轉和繞先x,y軸的3D旋轉。 scaleXscaleY:縮放,x,y軸的縮放。 pivotXpivotY:旋轉和縮放相對於某一點的設置。默認是中心點。 alpha:透明度

那麼,我們能夠自己定義屬性嗎,當然可以。其實,他裡面的邏輯是通過該屬性值查找動畫目標中是否有setXXX方法,如果有,將會調用。而以上列舉的屬性,Android已經在View中默認實現了set方法。

那麼下面我們就通過動畫實現比較常見的獲取驗證碼倒計時的功能。

首先在布局文件中添加控件

  

我們明白他是通過是否有setXXX方法,來修改對應屬性值的。那麼我們對Button進行封裝TimerBtnWrapper

/**
 * Button按鈕的包裝類,實現倒計時
 * Created by Alex_MaHao on 2016/5/13.
 */
public class TimerBtnWrapper {

    private Button btn;

    public TimerBtnWrapper(Button btn) {
        this.btn = btn;
    }


    /**
     * 關鍵方法,動畫調用此方法,修改屬性值
     * @param time
     */
    public void setTimer(int time){

        btn.setText(time+"s");
    }


    /**
     * 設值動畫結束後的值
     * @param text
     */
    public void setTimeEndText(String text){
        btn.setText(text);
    }

    /**
     * 設置按鈕是否可以點擊
     * @param isClick
     */
    public void setIsClick(boolean isClick){
        btn.setClickable(isClick);
    }
}

main中創建動畫:

 mTimeAnim = ObjectAnimator.ofInt(new TimerBtnWrapper(mTimerBtn),"timer",60,0).setDuration(60*1000);

        //修改插值器,即數值改變速率平均
        mTimeAnim.setInterpolator(new LinearInterpolator());

        //設置動畫監聽
        mTimeAnim.addListener(new AnimatorListenerAdapter() {
            @Override
            public void onAnimationEnd(Animator animation) {
                //動畫結束,設置按鈕可以點擊,同時設置重新獲取驗證碼

                //獲取動畫的目標控件
                TimerBtnWrapper target = (TimerBtnWrapper) ((ObjectAnimator) animation).getTarget();

                target.setIsClick(true);
                target.setTimeEndText("重新獲取");
            }

            @Override
            public void onAnimationStart(Animator animation) {
                //動畫開始時,設置按鈕不可點擊

                //獲取動畫的目標控件
                TimerBtnWrapper target = (TimerBtnWrapper) ((ObjectAnimator) animation).getTarget();

                target.setIsClick(false);
            }
        });

實現按鈕的點擊事件

 public void startTime(View view){
        mTimeAnim.start();
    }

TimeAniamtor

This class provides a simple callback mechanism to listeners that is synchronized with all other animators in the system. There is no duration, interpolation, or object value-setting with this Animator. Instead, it is simply started, after which it proceeds to send out events on every animation frame to its TimeListener (if set), with information about this animator, the total elapsed time, and the elapsed time since the previous animation frame.

為什麼在這貼一大段英文呢,因為我也不知道這個對象是干啥的。以上是google的API介紹。

PropertyValuesHolder

ValueAniamtor的構造初始默認值時,有ofPropertyValuesHolder(PropertyValuesHolder... values)方法,而其傳入的參數即為PropertyValuesHolder對象。

那麼,他到底是什麼意思。如果我們有這種需求,如果我們想讓一個控件從不透明逐漸透明的動畫,那麼很好實現,

    ObjectAnimator anim = ObjectAnimator.ofFloat(imageView,"alpha",1f,0f);

現在,我們的需求改了,想讓他在逐漸透明的時候,逐漸縮小。很尴尬,怎麼實現呢,我們要啟動兩個動畫嗎,或者整一個動畫集合,都不用,這時候就顯示出了PropertyValuesHolder的作用。我們可以通過如下代碼實現我們的要求:


        PropertyValuesHolder pvhX = PropertyValuesHolder.ofFloat("scaleX",1f,0f);

        PropertyValuesHolder pvhY = PropertyValuesHolder.ofFloat("scaleY",1f,0f);

        PropertyValuesHolder pvhAlhpa = PropertyValuesHolder.ofFloat("alpha",1f,0f);

        ObjectAnimator anim = ObjectAnimator.ofPropertyValuesHolder(img,pvhX,pvhY,pvhAlhpa);

Keyframe

在上一段中,我們知道通過PropertyValuesHolder可以對一個控件的不同屬性定義動畫,可以定義為擴大了動畫的范圍。而keyframe則是提高動畫的精度。frame是幀的意思。我們可以定義一個動畫中某一幀是什麼狀態。

    Keyframe kf0 = Keyframe.ofFloat(0f, 0f);
    Keyframe kf1 = Keyframe.ofFloat(0.5f, 360f);
    Keyframe kf2 = Keyframe.ofFloat(1f, 0f);
    PropertyValuesHolder pvhRotation = PropertyValuesHolder.ofKeyframe("rotation", kf0, kf1, kf2);
    ObjectAnimator rotationAnim = ObjectAnimator.ofPropertyValuesHolder(target, pvhRotation)
    rotationAnim.setDuration(5000ms);

這是google 官方的例子,我們分析一下即可。該例子中定義了一個旋轉動畫。其中創建了三個keyframe對象,通過ofFloat(fraction,value),fraction表示動畫所處在那一幀,value代表所對應的值。分別對應狀態是

在動畫執行初始時,值是0;在這裡即旋轉的度數0°。 在動畫執行到1/2時,值是360。 在動畫執行到1時,及結束,值是0.

同時Keyframe中有setInterpolator方法,即可以設置不同幀之間的插值器。

AnimatorSet 屬性動畫集合

相比較視圖動畫的AnimationSet不同,AnimatorSet不進可以定義動畫的同時執行,還可定義動畫的執行先後順,因為比較簡單,直接一個例子搞定。

 //============使用代碼實現AnimatorSet ==============
        ObjectAnimator rotateAnim = ObjectAnimator.ofFloat(img, "rotation", 0f, 360f)
                .setDuration(1000);
        // 使用PropertyValuesHolder實現縮放動畫
        PropertyValuesHolder pvhX = PropertyValuesHolder.ofFloat("scaleX",1,0);

        PropertyValuesHolder pvhY = PropertyValuesHolder.ofFloat("scaleY",1,0);

        ObjectAnimator scaleAnim = ObjectAnimator.ofPropertyValuesHolder(img, pvhX, pvhY);
        scaleAnim.setDuration(1000);


        AnimatorSet animSet = new AnimatorSet();

        //兩個動畫同時執行
        //animSet.play(rotateAnim).with(scaleAnim);

        //先縮放在旋轉
//      animSet.play(rotateAnim).after(scaleAnim);

        //先旋轉 再縮放
        animSet.play(rotateAnim).before(scaleAnim);
        animSet.start();

代碼都有注釋,應該難度不大。

使用xml創建屬性動畫

ValueAnimator

<code class="language-xml hljs "><animator xmlns:android="http://schemas.android.com/apk/res/android" android:duration="1000" android:valuefrom="1f" android:valueto="0f" android:valuetype="floatType">

注意,根節點是

ObjectAnimator

<code class="language-xml hljs "><cke:objectanimator xmlns:android="http://schemas.android.com/apk/res/android" android:duration="1000" android:valueto="360" android:valuefrom="0" android:propertyname="rotation" android:valuetype="floatType">

注意根節點是

AnimatorSet

<set xmlns:android="http://schemas.android.com/apk/res/android" android:ordering="sequentially">

    <cke:objectanimator android:propertyname="rotation" android:valueto="360" android:valuefrom="0" android:valuetype="floatType" android:duration="1000">



    <set android:ordering="together">

        <cke:objectanimator android:propertyname="scaleY" android:valuefrom="1" android:valueto="0" android:valuetype="floatType" android:duration="1000">

        <cke:objectanimator android:propertyname="scaleX" android:valuefrom="1" android:valueto="0" android:valuetype="floatType" android:duration="1000">

    </cke:objectanimator></cke:objectanimator></set>


</cke:objectanimator></set>
</code>

注意,set可以嵌套使用以及ordering關鍵字。

使用方式

和視圖動畫使用AnimationUtils相比,其使用的是AnimatorInflater。具體使用方式如下:

        Animator anim = AnimatorInflater.loadAnimator(getApplicationContext(), R.animator.property_set);

        anim.setTarget(img);

        anim.start();

對於ValueAnimator要注意設置監聽。

源碼已更新到我的github,在animationdemo文件中。

  1. 上一頁:
  2. 下一頁:
熱門文章
閱讀排行版
Copyright © Android教程網 All Rights Reserved