Android教程網
  1. 首頁
  2. Android 技術
  3. Android 手機
  4. Android 系統教程
  5. Android 游戲
 Android教程網 >> Android技術 >> Android開發 >> 關於android開發 >> Android動畫基礎——屬性動畫(Property Animation),androidproperty

Android動畫基礎——屬性動畫(Property Animation),androidproperty

編輯:關於android開發

Android動畫基礎——屬性動畫(Property Animation),androidproperty


本篇涉及例子下載:Github

本篇講android 3.0引入的屬性動畫框架,上篇寫視圖動畫View Animation時就說過ViewAnimation的缺點,那就是動畫作用的是view本身的視覺部分,view實際屬性並沒有隨著動畫的改變而變化。很多時候就需要額外去出來由於動畫引起的事件不同步,比如ViewAnimation已經講View移出了屏幕,但View的事件觸發還在原地,這就需要額外處理了。 但是,PropertyAnimation的引入就完全解決了這個問題,它可以保證動畫和事件的變化總是一起的發生的。其本質是View是屬性變化帶動View重繪來完成動畫。

目錄

  • 屬性動畫框架結構
  • 個人理解
  • TypeEvaluator與Interpolators
  • ObjectAnimator
  • ValueAnimator
  • 動畫集: Keyframes於AnimatorSet

一、屬性動畫框架結構

個人覺得了解繼承結構對學習框架幫助挺大的,所以開始先說一下屬性動畫的框架,我自己用StartUML畫了下面的類圖: 結構類圖 畫得比較糙(StartUML用的不好, -_-!),上面沒畫出TypeEvaluator和Interpolator,一來是怕復雜了不好看重點信息,二來是後面會重點講。大致講一下各個類的作用:

  • Animator類:屬性動畫框架的基類,封裝了動畫時間、監聽器、動畫狀態的控制。
  • AnimatorListener:動畫狀態接口,封裝了不同狀態需要調用的方法,有如下方法
    • onAnimationStart() - 動畫開始時調用
    • onAnimationEnd() - 動畫結束時調用
    • onAnimationRepeat() - 動畫重復時調用
    • onAnimationCancel() - 動畫取消時調用,注意這個方法調用後會接著調用onAnimationEnd()
  • AnimatorSet:類似於視圖動畫中的AnimationSet,它代表了一個動畫集,可以指定動畫集中各個動畫的順序,是實現復雜動畫必不可少的利器。
  • ValueAnimation:屬性動畫的核心類,它能驅動View的屬性變化進而實現動畫。
  • AnimationUpdateListenr:與ValueAnimation搭配使用,每次需要刷新動畫幀時會調用這個接口裡的方法,進而對真正的View設置屬性完成動畫。它就包含一個接口方法:
    • onAnimationUpdate()
  • ObjectAnimator:ValueAnimator的便捷版本,也是平時使用最多的屬性動畫類,它通過反射調用自動完成View屬性的設置,非常簡單。
  • TimeAnimator:可是用於同步動畫的輔助類,可以在觸發動畫幀時通過接口讓動畫執行指定的時間點。

以上便是屬性動畫框架的大致結構,關於ypeEvaluator和Interpolator後面有講到。

二、個人理解

1.屬性動畫時“真正的”動畫機制嗎? 我覺得不是(放下手頭的磚,讓我說完 ㄟ( ▔, ▔ )ㄏ),為什麼我說不是?它並不是直接生成一段動畫,它是通過在眾多動畫幀上改變View的屬性,然後View重繪,進而達到動畫的目的。或者把它理解成一個過渡值產生器更合適,它在每個動畫幀時間點上產生一個過渡值,然後把這個值設為相應的屬性。 2.屬性動畫VS視圖動畫: 屬性動畫相比於視圖動畫的優點是顯而易見的,因為動畫的來源是由於View的屬性變化引起的重繪,所以不存在事件與動畫不一致的情況。 視圖動畫最大的優點就是它簡單了,不需要添加各種監聽器就能實現動畫。 我還沒有兩種動畫性能的對比,不知道在實現相同效果時孰優孰劣,所以不敢妄下結論。留到後面討論吧! 3.ValueAnimator VS ObjectAnimator ObjectAnimator是ValueAnimator的便捷類,為了避免復雜的實現盡量選擇用ObjectAnimator。

三、TypeEvaluator與Interpolators

前面多次說道動畫幀(Frame),什麼叫Frame呢?相當於視圖動畫中的幀動畫,也就是每一個單獨的頁面,類似於膠卷電影中的一格。人眼的可察覺刷新頻率是24幀每秒,在低於這個頻率的動畫中我們看到影像就不是連續的。而熟悉動畫中用來指定動畫刷新頻率的是setFrameDelay()方法,默認情況下它的值是10ms,也就是100幀每秒。有了刷新頻率,如何講它映射到值呢?這就要用到TypeEvaluator和Interpolators了! 先說Interpolators(插值器):它的總用是怎樣將一個時間分數裝換為一個值分數,兩者的相對關系體現了動畫的形式:勻速、加速、先加速後減速,或者其它的數學變換。怎麼理解講一個時間分數裝換為值分數呢?來看一下接口吧!所以插值器都是TimeInterpolator接口的子類,其中聲明的方法:

abstract float  getInterpolation(float input)

input是一個已經過去的時間占總時間的比例,也就是動畫已經完成的百分比。返回的也是個小數,代表了希望這個點完成的總動畫的百分數。假設有這樣一個插值器,它接受0.5,返回0.8。這意味著這個差值器在經過50%的時間時,希望動畫完成了80%。為什麼是希望呢?因為真正映射為屬性值是由TypeEvaluator來完成的。 TypeEvaluator:(翻譯成類型求值器吧!這樣比較貼合它的意思)它完成了差值器返回的值到實際值的映射?或許你會疑問為什麼需要這個值,不應該是下面這個公式嗎?

startVal:起始值 endVal:結束值 percent:完成百分比 progress:當前值 progress = startVal + (endVal-startVal)*progress

對,的確是這樣的。內置的IntEvator、floatEvator也是這樣的,但是我們動畫的類型不一定都是這種數值類型的值吧!我們還可以動畫字符串,在不同的時間點顯示不同的字串,這時上述公式就不成立了。所以TypeEvaluator就是為了達到自定義裝換的需求的。要實現滿足自己需求的TypeEvaluator也很簡單,只需要實現TypeEvaluator接口就可以了,它聲明的方法如:

abstract T  evaluate(float fraction, T startValue, T endValue)

T是要動畫的屬性類型,fraction是值分數,startValue、endValue是進行動畫屬性的起始值和終止值。返回映射的中間值。 到這,可以對屬性動畫的工作原理做個簡單的接受了。 動畫需要指定持續時間,屬性起始值,屬性終止值,幀延時。然後每過幀延時的時間間隔,觸發插值器,接著觸發值裝換器,接下來是觸發AnimationUpdateListenr中的onAnimationUpdate()方法重新設置View的屬性,接著View重繪,如此循環知道動畫結束。為了方便,我畫了如下流程圖:
PropertyAnimationInvoke
ps:這符圖不是很嚴謹,因為有些內容是不好表達,比如動畫幀的計時是連續的,並不是等到上一幀完成了才開始計數下一幀。其次就是Animator本身的Listener是班法畫上去的,當Animator調用cance(),end()之類的方法是能打斷這個流程的。但是這圖對理解過程還是不錯的。

四、ObjectAnimator

先來講最常使用的屬性動畫,ObejectAnimator,通過置頂好動畫作用對象個對用屬性等設置值後,ObjectAnimator能夠通過反射區設置對象屬性達到動畫的目的。 ObjectAnimator提供了四種靜態方法來構造自己的對象,分別是:ofInt、ofFloat、ofArgb、ofObject 。它們動畫的值類型正如名字中說的那樣,如ofInt動畫作用於一個int域,offArgb注意與一個帶透明的顏色域。 來看一個用動畫改變欄背景的例子

public class MainActivity extends AppCompatActivity {

    @Bind(R.id.btn_bg) Button mGradientBg;
    ObjectAnimator mAnimator;

    @TargetApi(Build.VERSION_CODES.LOLLIPOP) @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        final View view = findViewById(android.R.id.content);
        final Drawable bgd =view.getBackground();
        mAnimator = ObjectAnimator.ofArgb(view,"backgroundColor",0x881DDA38,0x88D48AB2);
        mAnimator.setDuration(5*1000);
        mAnimator.setRepeatMode(ObjectAnimator.REVERSE);
        mAnimator.addListener(new AnimatorListenerAdapter() {
            @Override public void onAnimationEnd(Animator animation) {
                super.onAnimationEnd(animation);
                view.setBackground(bgd);
            }
        });
        ButterKnife.bind(this);
    }


    @OnClick(R.id.btn_bg) void onGradientActionbarClicked() {
        mAnimator.start();
    }
}

效果如下:
ObjectAnimator
上面就是ObjectAnimation使用過程,先通過四個靜態方法構造出一個ObjectAnimation對象,這裡使用的是ofArgb:

static ObjectAnimator   ofArgb(Object target, String propertyName, int... values)
  • 第一個是作用的對象
  • 第二個是string指定的屬性名
  • 第三個可變參數是動畫的起始值(可省略,省略以當前值算,且必須有getter)、終止值。

ObjectAnimator作用的域在對象是必須有相應的setter,getter(用於省略初始值的情況)方法,否則反射調用不了會報錯。至於沒有setter方法的域如何動畫,官方Guide提供了如下解決方案:

  • 使用包裝類,加入setter,getter。
  • 添加相應方法(自己定義View適合)
  • 換用ValueAnimator。

講一下使用包裝類,假設有類A,且A類中有域a,我可以正常操作A.a(訪問和寫值),現在我要動畫A的a域,直接用ObjectAnimator是不行了,因為A類中沒有A.setA()這個方法,那該怎麼辦呢?使用包裝類,寫一個A的包裝類AWrapper,它接受一個A對象來構造自己,然後裡面有一個setter和getter方法來設置和讀取A的a域。現在就可以在AWrapper上使用ObjectAnimator了。

六、ValueAnimator

ValueAnimator提供的便利性大大強於ObejectAnimator,因為需要你自己去更新對象的值,ValueAnimator只是為了提供了一個過渡值。為了更新對象的值,你就必須去設置前面講的AnimationUpdateListenr接口。一個簡單的例子來完成ValueAnimator的使用:

protected void onCreate(Bundle savedInstanceState) {
       super.onCreate(savedInstanceState);
       setContentView(R.layout.activity_main);
       ButterKnife.bind(this);
       final float X = 0, Y = 500;
       LogUtil.d("X,Y = "+X+","+Y);
       mValueAnimator = ValueAnimator.ofFloat(0f, 1f);
       mValueAnimator.setDuration(3 * 1000);
       mValueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
           @Override public void onAnimationUpdate(ValueAnimator animation) {
               mChangelocation.setY(Y * (Float)animation.getAnimatedValue());
               mChangelocation.invalidate();
           }
       });
       mValueAnimator.addListener(new AnimatorListenerAdapter() {
           @Override public void onAnimationEnd(Animator animation) {
               super.onAnimationEnd(animation);
               mChangelocation.setY(Y);
           }
       });
  }
  @OnClick(R.id.btn_cl) void onChangeLocationClicked() {
        mValueAnimator.start();
    }
}

效果:
ObjectAnimator

七、動畫集: Keyframes於AnimatorSet

類似於ViewAnimation中的動畫集,參考資料:AnimatorSet
Keyframes實現動畫集:Keyframes

本篇涉及例子下載:Github

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