Android教程網
  1. 首頁
  2. Android 技術
  3. Android 手機
  4. Android 系統教程
  5. Android 游戲
 Android教程網 >> Android技術 >> 關於Android編程 >> Android動畫總結系列(4)——屬性動畫集成

Android動畫總結系列(4)——屬性動畫集成

編輯:關於Android編程

一、概述 1.1 簡述 Android框架提供兩大動畫方案:屬性動畫與補間動畫。這兩者都非常有用,而且從谷歌文檔來看,都會持續支持。但官方文檔建議我們應優先考慮使用屬性動畫,因為屬性動畫更加靈活而且提供更多的可用特性。這兩大動畫方案之外Android還支持Drawable Animation(幀動畫),通過逐幀播放來形成動畫視覺效果。   屬性動畫引入自Android 3.0(API 11),其原理是給定對象的一個或多個屬性,指定其開始與結束時的值,通過時間插值生成不同的屬性值,並調用更新方法將屬性值設置到對象內,引起對象重繪,從而形成動畫效果。比如,通過不斷的設置View的寬高來更新View的展示,形成縮放效果等。   1.2 屬性動畫相關概念 屬性動畫作用的對象,可以是沒有渲染到界面的對象,當然這樣,動畫效果就看不到了,我們能得到的,是一段時間內不斷改變屬性的對象。同時,屬性動畫作用的對象屬性,也可以是與界面展示無關的屬性。而且,屬性動畫還支持自定義的屬性,從而提高擴展性。簡而言之:屬性動畫可以作用任何對象的任何屬性上。   一個屬性動畫執行需要的基本要素包括:承載動畫執行的對象屬性、動畫持續時間和屬性的變化區間。 屬性動畫支持定義動畫的以下特性: Duration:指定動畫的執行時間,默認300ms。Time interpolation:官方解釋比較拗口,大概意思就是說這是一個輸入為動畫真實時間的函數,以此函數來計算動畫屬性;其實重點在於函數上,這個函數定義的是動畫的變化速率,舉個例子來看:假如有個函數y=x,x是動畫的真實執行時間,y是映射後的執行時間,則這個動畫是恆速執行的;假如映射函數是y=x*x,這個動畫是就是不斷加速運行的,因為y的變化速率在不斷的增大。Repeat count and behavior:動畫重復次數表示動畫需要被執行的次數,動畫重復時的行為有兩種:從頭開始或者反轉執行;在動畫執行結束時,如果沒有執行完指定次數,則繼續執行;假設執行次數為3,模式設為Restart從頭執行,則執行順序為“初始幀--插值-->結束幀-->初始幀--插值-->結束幀-->初始幀--插值-->結束幀”,模式設為Reverse,則執行順序為“初始幀--插值-->結束幀--插值-->初始幀--插值-->結束幀”。Animator sets:將多個動畫效果組成動畫集合並設置彼此間的執行順序,可設三種執行順序:一起執行、順序執行和在指定時間執行。Frame refresh delay:指定多長時間刷新一次動畫的幀,默認值是10ms一次,但最終取決於當前系統的繁忙程度和系統多快能相應定時器,基本上我們可以不用考慮。   1.3 屬性動畫的過程描述 Android Developers上有完整的動畫工作示例,這裡簡單的描述一下,並盜個圖來做個生動的解釋(此圖來源於android官網): 假設有一個長方體(對象),基於其屬性x(x是長方體在水平方向上的位置,單位px)做動畫,動畫持續時間是40ms,長方體在40ms內從位置x=0px移動到x=40px,幀刷新延遲是10ms,也就是每10ms移動一下長方體的位置: 如果長方體的時間插值是均勻的,也就是勻速運動,那麼動畫的效果是長方體在位置0停留10ms,位置10px停留10ms,位置20px停留10ms,位置30px停留10ms,最終到達位置40px,停下,動畫結束,效果為:   \ 如果我們想要先加速再減速的效果,那麼我們調整時間插值器,可以形成加減速效果,長方體在位置0停留10ms,第10ms時計算出位移6px,在位置6px停留10ms,在第20ms時計算出位移20px,在位置20px停留10ms,在第30ms時計算出位移34px,停留在34px位置10ms,最終在第40ms時移動到位置40px,動畫結束。這樣視覺效果裡,我們覺得長方體的移動速率在變化,先加速到中間位置,再減速到最終位置。 \   好了,這樣說下來,應該對屬性動畫有點認識了吧,我們繼續往下,看看屬性動畫和補間動畫的區別。   1.4 屬性動畫與補間動畫的區別 1) 補間動畫的應用對象只能是View,不能用於非View對象,屬性動畫支持任意對象; 2) 補間動畫的本質是對View做Transformation,並不能影響View的布局位置,只能影響View的可視位置。如果View從屏幕左邊移動到右邊,則其展示在右邊了,但是這時候View相應點擊事件還是在左邊的位置,因為View並沒有真的移動到右邊,只是被繪制到右邊了; 3)及時動畫對象是View,補間動畫能做的也比較有限,只能做平移/旋轉/縮放/透明度四種變化效果,假如我們要不斷改變View背景色,就搞不定了,屬性動畫表示毫無壓力; 4)屬性動畫比補間動畫更靈活,可以同時支持多個屬性的動畫,每個屬性都可以獨立定義插值器,各動畫之間還可以做動畫同步控制。   二、屬性動畫使用   2.1 結構概覽 屬性動畫的每次插值執行過程可以分為兩步:1)計算插值的屬性值,2)將屬性值設置到對象的屬性上,也就是更新屬性值。 \   Animator:所有屬性動畫的基類;注意和補間動畫不同,補間動畫所有類都繼承自Animation; ValueAnimator:屬性動畫最核心的插值邏輯管理類,包含最核心的屬性值插值計算以及屬性動畫相關的控制策略(動畫重復、屬性值變化通知、處理自定義的屬性值插值等)。前文說到的屬性動畫執行過程有兩步,ValueAnimator只專注於完成第一步插值計算的操作,不負責第二步具體的屬性刷新,它借助AnimatorUpdateListener.onAnimationUpdate()設置屬性值,或進一步刷新界面; ObjectAnimator:繼承自ValueAnimator,專注於第二步操作,支持調用者指定對象和屬性,其通過反射來調用屬性的setter方法。通常情況下,我們都是用此類來做屬性動畫,因為其封裝了屬性設置操作,不用我們自己做更新;但有時候我們不得不使用ValueAnimator,比如說我要給某個View設置寬度,而View並沒有setWidth接口,這時候,我們只能在onAnimationUpdate中更新View的LayoutParams。 AnimatorSet:將多個Animator組合在一起執行,支持一起執行、順序執行和指定時間執行; TimeAnimator:作用不大,主要作用是把動畫已經執行的耗時和當前幀距離與上一幀的耗時回調到外面去。   2.2 屬性動畫的屬性值計算 屬性動畫系統內使用Evaluators來告知系統如何計算給定屬性的值。其輸入是動畫當前的執行時間(歸一化的值,且已經被插值器處理過)、動畫的開始值和結束值,輸出是給定的屬性開始值和結束值之間的插值。屬性動畫支持的Evalators包括: IntEvaluator:計算int型的屬性值插值; FloatEvaluator:計算float型的屬性值插值; ArgbEvaluator:計算顏色的屬性值插值; TypeEvaluator:這是一個接口,我們可以實現此接口來定義自己的Evaluator。如果我們需要操作的屬性不是int/float/color,就必須實現TypeEvaluator,告知如何計算屬性插值。如果我們需要為int/float/color提供不同於默認實現的插值計算方案,也可以通過重寫此接口實現。下面就是接口定義:
public interface TypeEvaluator< T> {
    public T evaluate( float fraction, T startValue, T endValue);
}
  2.3 屬性動畫的插值器 屬性動畫的插值器與補間動畫的插值器完全相同 如果覺得現有的插值器不滿足你的需求,就實現TimeInterpolator接口自己寫個插值器。基本上目前定義的插值器已經足夠了。   2.4 使用ValueAnimator實現屬性插值效果 前面我們說過,ValueAnimator不負責屬性動畫第二步,也就是對對象的屬性進行操作,所以下面兩個動作,都是集中在第一步,計算按時間變化的插值序列。   2.4.1 ValueAnimator支持int/float/color的插值動作,相應的接口是ofInt/ofFloat/ofArgb。一個簡單的例子如下:
ValueAnimator animation = ValueAnimator.ofFloat(0f, 1f);
animation.setDuration(1000 );
animation.start();
這段代碼表示ValueAnimator在start()執行後的1s內,不斷的生成介於0~1之間的插值。這個插值可以作為某個對象的某個屬性設置到對象裡去。   2.4.2 ValueAnimator支持Object的插值動作,相應接口是ofObject。例子如下: 假設我們有個屬性,類型為:
private static class TestData {
    float size = 0 ;

    TestData(float size) {
        this.size = size;
    }
}
我們需要為此對象定義一個TypeEvaluator,如下:
private static class MyTypeEvaluator implements TypeEvaluator {

    @Override
    public TestData evaluate(float fraction, TestData startValue, TestData endValue) {
        return new TestData(startValue.size + fraction * (endValue.size - startValue.size));
    }
}
然後我們就可以將其放入ValueAnimator使用了:
ValueAnimator valueAnimator = ValueAnimator.ofObject(new MyTypeEvaluator(),
        new TestData(0), new TestData( 1));
valueAnimator.setDuration(1000 );
valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
    @Override
    public void onAnimationUpdate(ValueAnimator animation) {
        TestData testData = (TestData) animation.getAnimatedValue();
        Log.d( "TEST_PROPERTY_ANIM", "data is " + testData.size);
    }
});
valueAnimator.start();
ValueAnimator通過MyTypeEvaluator類(自定義類型估值器)完成TestData(自定義屬性值)的插值工作,並通知到AnimatorUpdateListener接口,這個接口裡可以取到計算出的插值TestData,我們可以根據此值來刷新界面(當然,此Demo內我們只是把值打印出來了,沒有刷新界面)。   2.5 使用ObjectAnimator實現屬性動畫效果 ObjectAnimator繼承自ValueAnimator,ValueAnimator已經封裝了計算隨時間變化的插值屬性值序列的任務,剩下來任務就是將計算好的插值屬性值設置到對象的指定屬性上。ObjectAnimator的目標就是完成剩下來的任務了。 使用ObjectAnimator與使用ValueAnimator非常相似,差別在於,使用ObjectAnimator時需要指定對象和對象屬性的名字(也就是字符串): 比如說我們有一個View對象,對其float型的屬性alpha做透明度0到1的漸顯動畫:
View view = new View(context);
ObjectAnimator.ofFloat(view, "alpha", 0f, 1f)
        .setDuration(1000 )
        .start();
  ObjectAnimator需要依賴以下條件才能正常工作: 第一點,必須要確保指定的屬性在對象內存在setter方法(且是駝峰法命名),上例中View類需要存在setAlpha方法設置透明度值,很幸運,View本來就有此方法。如果我們很不幸的發現並不存在這樣的setter咋辦呢? 下面有幾種辦法: 1)如果我們有權限,就直接去改了對象類,加個setter方法,上例中,如果View沒有setAlpha,我們去View內加個setAlpha。好吧,我們是做不到的,但是google可以,setAlpha方法就是和屬性動畫在API 11一起添加的。 2)如果我們沒辦法改View,那就試著寫個類把它包裹起來。類似下面這樣的:
public class WrappedView extends View {
    public WrappedView(Context context) {
        super(context);
    }
   
    public void setAlpha(float alpha) {
        AlphaAnimation animation = new AlphaAnimation(alpha, alpha);
        animation.setDuration(0 );
        animation.setFillAfter(true);
        startAnimation(animation);
    }
}
API 10以下我們取不到View的TransformationInfo,只能通過動畫來間接實現。 3)如果連包裝都難以做到,就只能用ValueAnimator了。在ValueAnimator回調的onAnimationUpdate做處理。   第二點,如果我們交給接口的values...參數只有一個值,也這樣寫屬性動畫:ObjectAnimator. ofFloat(view, "alpha", 1f),這唯一的一個值1f被認為是動畫的結束值,那動畫的初始值是多少呢?這時候就得靠getter方法返回了。所以View得定義getAlpha方法,沒有getter方法,動畫就不執行。   第三點,getter方法和setter方法必須保持和ObjectAnimator指定的屬性值類型相同。假如有這樣的調用:ObjectAnimator .ofFloat(targetObject, "propName", 1f ),那麼targetObject對象必須存在兩個方法: void setPropName(float value); float getPropName(); 重點就是setter的參數是float,同時getter返回值也必須是float。   第四點,某些情況下我們需要強制調用invalidate/postInvalidate來強制刷新,保證動畫效果顯示在界面上。比如說我們對ImageView.getDrawable的drawable做屬性動畫,這些修改只能在View繪制時才會應用,所以我們要不斷的調用invalidate來重新繪制View;但如果我們調用是View.setAlpha(基本上是所有View的setter方法),此方法會自己刷新界面,就不需要我們調用invalidate了。如果需要調用invalidate,那就應該放在onAnimationUpdate的回調中進行。   2.6 使用動畫集合 在實際應用場景中,可能需要指定動畫與其他動畫一起執行、在其他動畫執行完成後執行或者在指定時間執行,屬性動畫提供了AnimatorSet來管理多個動畫以及他們之間的執行順序關系。可以指定多個動畫一起執行、一個接一個執行或者在指定時間執行,因為AnimatorSet內持有的是抽象Animator類,所以這裡也可以在動畫集合內再套動畫集合,形成復雜的動畫效果。 下面這個例子是google官網的,我就沒有加工了,假設有以下執行順序: 1.執行bounceAnim。 2.隨後同時執行squashAnim1/squashAnim2/stretchAnim1/stretchAnim2。 3.stretchAnim2執行完成後開始執行bounceBackAnim。 4.最後執行fadeAnim。
bouncer.play(bounceAnim).before(squashAnim1);
bouncer.play(squashAnim1).with(squashAnim2);
bouncer.play(squashAnim1).with(stretchAnim1);
bouncer.play(squashAnim1).with(stretchAnim2);
bouncer.play(bounceBackAnim).after(stretchAnim2);
ValueAnimator fadeAnim = ObjectAnimator.ofFloat(newBall, "alpha" , 1f , 0f);
fadeAnim.setDuration(250);
AnimatorSet animatorSet = new AnimatorSet();
//這裡是為了展示AnimationSet嵌套
animatorSet.play(bouncer).before(fadeAnim);
animatorSet.start();
  2.7 動畫事件監聽 2.7.1 監聽正常的動畫事件如開始/重復/結束/取消應使用Animator.AnimatorListener:
ObjectAnimator objectAnimator = ObjectAnimator.ofFloat(view, "alpha", 0f, 1f);
objectAnimator.addListener(new Animator.AnimatorListener() {
    @Override
    public void onAnimationStart(Animator animation) {
         //動畫開始
    }

    @Override
    public void onAnimationEnd(Animator animation) {
         //動畫結束
    }

    @Override
    public void onAnimationCancel(Animator animation) {
         //動畫取消,不論動畫如何結束,取消還是正常結束,都會回調onAnimationEnd
    }

    @Override
    public void onAnimationRepeat(Animator animation) {
         //動畫重復執行
    }
});
如果不想監聽所有的事件,可以使用AnimatorListenerAdapter,這個類實現了AnimatorListener,並提供空實現。     2.7.2 監聽屬性動畫每一次插值刷新界面的動作,使用ValueAnimator.AnimatorUpdateListener
objectAnimator.addUpdateListener( new ValueAnimator.AnimatorUpdateListener() {
    @Override
    public void onAnimationUpdate(ValueAnimator animation) {
        //屬性動畫開始了新的插值操作 ,動畫每刷新一幀則調用一次
       }
});
在此回調內,可以通過animation.getAnimatedValue()來取得插值的值。如果是使用ValueAnimator,一定需要實現此對象來實現界面刷新,形成動畫效果。   2.8 自定義TypeEvaluator 前面已經寫過一個簡單的TypeEvaluator了,TypeEvaluator的作用是對未知屬性類型的值的插值進行抽象,只有一個接口evaluate需要實現。其輸入是當前的動畫執行時間(經過歸一化和速率變化處理的時間)fraction、屬性開始值startValue和屬性結束值endValue,絕大部分情況下,這裡面的邏輯都是startValue+(endValue - startValue) * fraction; 需要注意一點,fraction已經由外面的插值器(TimeInterpolator)做過加速度變化處理,所以在TypeEvaluator內不需要再考慮速率變化。 舉個系統實現的Float插值的插值器做例子:
public class FloatEvaluator implements TypeEvaluator {
    public Float evaluate(float fraction, Number startValue, Number endValue) {
        float startFloat = startValue.floatValue();
        return startFloat + fraction * (endValue.floatValue() - startFloat);
    }
}
  2.9 使用關鍵幀來做屬性動畫 一個關鍵幀包含一個“時間/屬性值”對,可以此來指定一個動畫在特定時間(關鍵幀中的時間)處於的特殊狀態(關鍵幀 中的屬性值),每個關鍵幀可以包含自己的插值器,此插值器的影響范圍是上一個關鍵幀的時間到當前關鍵幀的時間內動畫的行為。 我們可以用KeyFrame的ofInt()、ofFloat()或者ofObject()來實例化一個關鍵幀對象(注意,沒有ofRgba)。然後通過PropertyValuesHolder.ofKeyframe來根據多個(至少兩個,一個就沒動畫效果了)關鍵幀生成一個PropertyValuesHolder,有了這個對象後,我們就可以通過ObjectAnimator.ofPropertyValuesHolder(target, pvhRotation)生成一個屬性動畫了。大概代碼如下:
Keyframe kf0 = Keyframe. ofFloat(0f , 0f );
Keyframe kf1 = Keyframe.ofFloat(.5f, 360f);
Keyframe kf2 = Keyframe.ofFloat(1f, 0f);
PropertyValuesHolder pvhRotation = PropertyValuesHolder.ofKeyframe("rotation", kf0, kf1, kf2);
ObjectAnimator rotationAnim = ObjectAnimator.ofPropertyValuesHolder(view, pvhRotation);
rotationAnim.setDuration(5000 );
  2.10 PropertyValuesHolder使用 前面已經有過一個PropertyValuesHolder的使用舉例了,其實PropertyValuesHolder的作用就是持有一個屬性和它的開始值結束值,一個ObjectAnimator可以同時對多個屬性進行操作,如果一個個寫代碼就太難看了,這時候我們可以通過PropertyValuesHolder來先枚舉所有的屬性和它們的開始結束值,然後將所有的PropertyValuesHolder一次性傳入ObjectAnimator構造中,生成一個屬性動畫。 PropertyValuesHolder支持的屬性類型包括:float/int/keyframe/Object,對應的接口是ofFloat/ofInt/ofKeyframe/ofObject等。 舉個例子看看其使用:
PropertyValuesHolder valuesHolderX = PropertyValuesHolder.ofFloat("translationX", view.getWidth() * 0.5f, view.getWidth() * 1.5f );
PropertyValuesHolder valuesHolderY = PropertyValuesHolder.ofFloat("translationY", view.getHeight() * 0.5f, view.getHeight() * 1.5f);
ObjectAnimator animator = ObjectAnimator.ofPropertyValuesHolder(view, valuesHolderX, valuesHolderY);
2.11ViewPropertyAnimator使用 ViewPropertyAnimator提供一種簡單的並行操作View的幾種屬性形成屬性動畫的方案。它在操作View屬性時比ObjectAnimator效率更高一點,代碼可讀性更高些。ViewPropertyAnimator雖然以Animator命名,但其不繼承Animator,而是調用ValueAnimator完成相關操作。其支持的操作有:translationX、translationY、translationZ、scaleX、scaleY、rotation、rotationX、rotationY、x、y、z、alpha。 下面是官網的一個例子對比,看一下就明白差別了: 同時操作屬性,改變View的位置: 1)多個ObjectAnimator
ObjectAnimator animX = ObjectAnimator.ofFloat(myView, "x", 50f );
ObjectAnimator animY = ObjectAnimator.ofFloat(myView, "y", 100f );
AnimatorSet animSetXY = new AnimatorSet();
animSetXY.playTogether(animX, animY);
animSetXY.start();
2)一個ObjectAnimator
PropertyValuesHolder pvhX = PropertyValuesHolder.ofFloat("x", 50f);
PropertyValuesHolder pvhY = PropertyValuesHolder.ofFloat("y", 100f);
ObjectAnimator.ofPropertyValuesHolder( myView, pvhX, pvhY).start();
  3)使用ViewPropertyAnimator
myView.animate().x(50f ).y(100f );
  三、屬性動畫實現補間動畫效果 之前我們已經討論過屬性動畫與補間動畫的區別,以及屬性動畫相對於補間動畫的優勢。我們再強調一遍,補間動畫改變的是View的繪制方式與位置,而不改變View的真實位置(影響draw過程而非layout過程),原因是相關的操作(平移旋轉縮放)都是由View的父元素完成的,View自身並無操作方法來完成這些動作。結果就是可能View已經發生了動畫變化,但自身並無改變,比如說,View在屏幕左邊繪制,經過動畫到屏幕右邊繪制,這是View布局位置並未變化,相應點擊的區域還在左邊區域。Android3.0(API11)增加了相應的新屬性和setter/getter方法來解決這個問題。 屬性動畫可以通過改變View的屬性來真正的改變View的位置,同時當View的屬性發生變化時,View會自動調用invalidate來刷新界面。View在3.0增加了以下屬性來支持屬性動畫: translationX/translationY:這兩個變量輔助控制View的位置,它們是真實位置與父元素設置布局位置的差值。假設View的左坐標是left,上坐標是top,這兩個值是View的容器設置的,在運行過程中不會發生改變,真實的View位置在left + translationX,top+translationY的位置。 rotation/rotationX/rotationY:這些屬性控制View繞中心點的2D和3D旋轉效果,其中2D效果由rotation表示。 scaleX/scaleY:控制View繞中心點的2D縮放效果。 pivotX/pivotY:控制View的中心點位置,縮放和旋轉動畫基於此位置來執行動畫,默認在View中心位置。 x/y:描述View最終在其容器內的位置,如上所述,x = left + translationX, y = top + translationY。 alpha:表示View的透明度,1不透明,0全透明(不可見)。 要想用屬性動畫實現補間動畫的效果,其實只需要創建屬性動畫,並指定上面這些屬性即可:   以下這些效果,如果希望啟動Activity就執行,應寫在Activity的onWindowFocusChanged內。同時,以下效果都是在3.0以上才能運行,因為這些屬性和屬性動畫本身都是3.0以上才有的。 3.1 平移效果 舉例:x軸從自身位置50%向右平移相對於自己寬度100%的距離,y軸從自身位置50%向下平移相對於自己100%高度的距離,時間1s,先加速再減速:
PropertyValuesHolder valuesHolderX = PropertyValuesHolder.ofFloat("translationX", view.getWidth() * 0.5f, view.getWidth() * 1.5f );
PropertyValuesHolder valuesHolderY = PropertyValuesHolder.ofFloat("translationY", view.getHeight() * 0.5f, view.getHeight() * 1.5f);
ObjectAnimator animator = ObjectAnimator.ofPropertyValuesHolder(view, valuesHolderX, valuesHolderY);
animator.setDuration(1000);
animator.setInterpolator(new AccelerateDecelerateInterpolator());
animator.start();
  3.2 縮放效果 舉例:x軸從自身50%縮放到自身200%,y軸從自身50%縮放到自身200%,中心點(10%,10%)時間1s,先加速再減速:
PropertyValuesHolder valuesHolderX = PropertyValuesHolder.ofFloat("scaleX", 0.5f, 1f);
PropertyValuesHolder valuesHolderY = PropertyValuesHolder.ofFloat("scaleY", 0.5f, 2f );
//兩個中心點其實可以用set方法直接設置,mView.setPivotX(pivotX)
float pivotX = mView.getWidth() * 0.1f;
float pivotY = mView .getHeight() * 0.1f;
PropertyValuesHolder valuesHolderPvX = PropertyValuesHolder.ofFloat("pivotX", pivotX, pivotX);
PropertyValuesHolder valuesHolderPvY = PropertyValuesHolder.ofFloat("pivotY", pivotY, pivotY);
ObjectAnimator animator = ObjectAnimator.ofPropertyValuesHolder( mView, valuesHolderX, valuesHolderY, valuesHolderPvX, valuesHolderPvY);
animator.setDuration(1000);
animator.setInterpolator(new AccelerateDecelerateInterpolator());
animator.start();
3.3 旋轉效果 舉例:View繞自身中心點(10%,10%)位置,從-270旋轉到180,時間1s,先加速再減速 :
PropertyValuesHolder valuesHolderX = PropertyValuesHolder.ofFloat("rotation", - 270f, 180f);
//兩個中心點其實可以用set方法直接設置,mView.setPivotX(pivotX)
float pivotX = mView .getWidth() * 0.1f;
float pivotY = mView .getHeight() * 0.1f;
PropertyValuesHolder valuesHolderPvX = PropertyValuesHolder.ofFloat("pivotX", pivotX, pivotX);
PropertyValuesHolder valuesHolderPvY = PropertyValuesHolder.ofFloat("pivotY", pivotY, pivotY);
ObjectAnimator animator = ObjectAnimator.ofPropertyValuesHolder( mView, valuesHolderX, valuesHolderPvX, valuesHolderPvY);
animator.setDuration(1000);
animator.setInterpolator(new AccelerateDecelerateInterpolator());
animator.start();
  3.4 Alpha效果 舉例:View從透明到完全不透明,時間1s,先加速再減速:
ObjectAnimator animator = ObjectAnimator.ofFloat(mView, "alpha", 0f , 1f );
animator.setDuration(1000);
animator.setInterpolator(new AccelerateDecelerateInterpolator());
animator.start();
四、使用XML定義屬性動畫 在XML中定義屬性動畫更容易在多個Activity中復用,且更容易編輯動畫順序。考慮到屬性動畫使用了新的屬性動畫API,為了與補間動畫的動畫文件區分開,在Android 3.1後,屬性動畫的XML動畫文件定義在res/animator/文件夾中。 屬性動畫各接口與XML tag對應關系為: ValueAnimator對應; ObjectAnimator對應 AnimatorSet對應 下面是官網上提供的一個例子:

    
        
    
這裡有兩個動畫集合,外層的動畫集合嵌套內層的動畫集合,外層動畫集合有兩個子元素,它們按照android:ording的要求順序播放,子集合(xy變化)執行完成後再執行下面的alpha動畫。子集合內,x的屬性動畫和y的屬性動畫一起執行。 XML的動畫文件定義好後,我們需要將其加載成Java對象使用,並設置各動畫的target,具體方法如下:
AnimatorSet set = (AnimatorSet) AnimatorInflater.loadAnimator(context, R.anim.property_animator);
set.setTarget(myObject);
set.start();
五、屬性動畫實現ViewGroup內Layout變化動畫 屬性動畫對處理ViewGroup內子元素變化導致的動畫行為提供了非常好的支持。使用LayoutTransition類來處理ViewGroup元素的變化動畫。通過給ViewGroup設置LayoutTransition,View從ViewGroup內添加/移除/變的可見(setVisibility(VISIBLE))/變的不可見(setVisibility(GONE))等情況都可以執行一個顯示或隱藏的動畫。當添加/刪除某個View時,ViewGroup內其他的View也可以展示挪到新位置的動畫。 具體設置方法如下:
LayoutTransition transition = new LayoutTransition();
transition.setAnimator(LayoutTransition.APPEARING, objectAnimatorApearing);
transition.setAnimator(LayoutTransition.CHANGE_APPEARING, objectAnimatorChangeAppearing);
transition.setAnimator(LayoutTransition.CHANGE_DISAPPEARING, objectAnimatorChangeDisappearing);
transition.setAnimator(LayoutTransition.CHANGING, objectAnimatorChanging);
transition.setAnimator(LayoutTransition.DISAPPEARING, objectAnimatorDisappearing);

ViewGroup group = new LinearLayout(context);
group.setLayoutTransition(transition);
  對應的常量意義為: APPEARING:當View在容器內展示出來時顯示的動畫; CHANGE_APPEARING:當View在容器內展示出來時,其他被影響了的View的動畫; DISAPPEARING:當View從容器內消失時展示的動畫; CHANGE_DISAPPEARING:當View從容器內消失時,其他被影響了的View的動畫; CHANGING:當不是View添加/移除導致的容器重新布局(Layout Change)時,所有被影響了的View的動畫;這個屬性並不是自動默認開啟的,需要通過transition.enableTransitionType(LayoutTransition. CHANGING)來開啟; 如果不通過setAnimator設置而通過enableTransitionType開啟動畫效果的話,LayoutTransition對這些情況的動畫都支持使用默認值。 在XML內將android:animateLayoutchanges置為true就可以開啟ViewGroup的layout transitions。如下:
六、其他注意要點 1.Android屬性動畫只能支持Android3.0以上版本,想要支持3.0以前的版本,需要使用NineOldAndroids包。   七、總結 本文總結了屬性動畫的使用方法,Android屬性動畫相對於補間動畫而言,的確是發生了質的變化,整個框架的抽象性設計非常合理,擴展性也非常強。在實際使用過程中,如果動畫很簡單,而且沒有文中提到的補間動畫的坑(View顯示位置與布局位置不同),可以考慮使用補間動畫,如果動畫比較復雜,建議使用屬性動畫。
  1. 上一頁:
  2. 下一頁:
熱門文章
閱讀排行版
Copyright © Android教程網 All Rights Reserved