android 属性动画变大,Android PropertyAnimation 属性动画(一)初探
8種機械鍵盤軸體對比
本人程序員,要買一個寫代碼的鍵盤,請問紅軸和茶軸怎么選?
前言
相對于靜態(tài)的頁面,動畫往往能更直觀地表達所需的信息,在UI開發(fā)過程中起著相當(dāng)大的作用。
Android為我們提供了一系列實現(xiàn)動畫效果的方法,PropertyAnimaiton是最常見也是最實用的一種,如同它的名字一樣,它的實現(xiàn)方式是通過改變對象的一系列屬性值來改變對象的狀態(tài), 例如動態(tài)地改變繪制的位置就可以實現(xiàn)繪制物體的移動效果,動態(tài)地改變對象的顯示狀態(tài)可以實現(xiàn)閃爍效果。
Animator概覽
Android提供的實現(xiàn)屬性動畫的工具是android.animation.Animator這個類,它的使用需要配合animation包下的其他工具類,這個類的功能是什么,我們要如何使用它來實現(xiàn)屬性動畫呢?
我們可以將Animator理解為Android為我們提供的一個按我們的需要在一定時間段內(nèi)連續(xù)地計算并返回值的工具,這個值可以是通用的整型、浮點型,也可以是我們自定義的類型。
我們可以設(shè)置返回值的范圍,并可以控制值變化的快慢,例如實現(xiàn)自由落體下落的物體時我們需要讓高度值以一個越來越快的速度降低。
這里的連續(xù)需要注意,實際上是不可能產(chǎn)生真正意義上的連續(xù)值的,但是如果在繪制過程中計算這個值的速度小于繪制一幀所需要的時間,那么我們就可以在視覺上認為這個值是在連續(xù)改變的。這一點也是理解其作用的關(guān)鍵:我們很難去寫出一個可以隨時獲取連續(xù)值的工具,而Animator正是一個滿足我們這個需求的一個通用工具。
通過將Animator與View的繪制過程結(jié)合,就可以實現(xiàn)絕大多數(shù)的動畫效果, 但是Animator也不只局限在使用在繪制動畫,只要是有相似需求的地方都可以使用它來實現(xiàn), 同時由于屬性動畫只針對屬性進行修改,與被修改對象之前幾乎沒有耦合,不需要對被修改對象作出改變,可以設(shè)置方式也多種多樣,這些都是動畫的另一種實現(xiàn)方法ViewAnimator所無法做到的,所以我屬性動畫是現(xiàn)在實現(xiàn)動畫效果的普遍做法。
使用Animator
Animator子類
下面就來看看如何使用Animator滿足我們的需求。
我們使用Animator可以分為兩個步驟,一是進行數(shù)值的計算,二是將計算出的數(shù)值設(shè)置到對應(yīng)的對象上。而Animator有著三個子類:ValueAnimator ObjectAnimator AnimatorSet。ValueAnimator實現(xiàn)了上述過程的第一個步驟:進行數(shù)值的計算。第二個步驟則需要我們重寫它的回調(diào)在值發(fā)生改變時候手動地為對象更新屬性值。
ObjectAnimator則在其基礎(chǔ)上進行了進一步的封裝,加入了一些方法使得它可以綁定一個對象,在數(shù)值改變的同時對對象的屬性進行更新。
AnimatorSet可以對Animator進行組合,讓它們之間進行聯(lián)動,例如可以設(shè)置一個動畫根據(jù)另一個動畫的狀態(tài)來決定是否開始、暫停或停止。
可以看到,ValueAnimator提供了一個Animator最核心的內(nèi)容,也是使用中最為靈活的一個。ObjectAnimator由于綁定了相應(yīng)的對象,在使用上會受一些限制。AnimatorSet專用于需要組合動畫的場景。
ValueAnimator
在這篇博客中,我們關(guān)注最為核心的ValueAnimator。
關(guān)鍵屬性
ValueAnimator對象內(nèi)部維護了一系列屬性來保存所需的各種信息。Duration:動畫的持續(xù)時間,通過setDuration()方法設(shè)置
Repeat count and behavior:重復(fù)計數(shù)與重復(fù)模式,我們可以通過設(shè)置這兩個屬性來控制動畫是否重復(fù)以及重復(fù)的次數(shù),通過setRepeatCount()與setRepeatMode()方法設(shè)置
Frame refresh delay:幀刷新延遲,也就是計算兩幀動畫之間的間隔時間,但這個時間只是Animator盡力去保持的值,具體的間隔時間會由于系統(tǒng)負載與性能的不同而不同,同時設(shè)置它的方法為一個靜態(tài)方法:ValueAnimator.setFrameDelay(),會被設(shè)置到所有的Animator上,這是因為這些Animator都在同一個時間循環(huán)中。這個屬性也有可能會被忽略如果動畫系統(tǒng)采用了內(nèi)部的計時來源,例如vsync來計算屬性。同時這個方法需要在與start()方法相同的進程中調(diào)用
Time interpolation:時間插值器,是我們實現(xiàn)不同動畫效果的關(guān)鍵,每一時刻所返回的數(shù)值由它決定,后文會詳細講
初始化與TypeEvaluator
ValueAnimator對象的構(gòu)造函數(shù)只由內(nèi)部使用,獲取ValueAnimator對象的方法是調(diào)用它的工廠方法:
ValueAnimator.ofArgb()
ValueAnimator.ofInt()
ValueAnimator.ofFloat()
ValueAnimator.ofObject()
ValueAnimator.ofPropertyValuesHolder() //本篇未涉及,下一篇進行講解
前三個可以看作是ValueAnimator為我們提供的初始化方式,它們的參數(shù)都是對應(yīng)類型的長度可變參數(shù):(Type ...values),我們需要提供一個以上的參數(shù),ValueAnimator最終提供的值會在這些值之前變動。
一般情況下這里提供的Argb(用于顏色值的變化)和整型、浮點值基本可以滿足我們的需求,但是某些時候我們需要結(jié)果是我們自定義的一些對象,這個時候就需要用到TypeEvaluator<>接口了,與這個接口對應(yīng)的工廠方法是ValueAnimator.ofObject():1
2ValueAnimator (TypeEvaluator evaluator,
Object... values)
這里的可變參數(shù)類型變?yōu)榱薕bject,同時還需要我們提供一個TypeEvaluator<>,用于“告訴”Animator如何返回這個Object值。
TypeEvaluator<>接口并不復(fù)雜,只有一個方法需要我們重寫:1
2
3T evaluate (float fraction,
T startValue,
T endValue)
startValue與endValue非常好理解,就是我們在獲取Animator時指定的值的起始值和結(jié)束值。類型與返回類型一致,當(dāng)然都是我們自定義的類型。
這里的fraction就是決定我們最終返回值的關(guān)鍵參數(shù)。我們可以把這個fraction理解為animator提供給我們的最終的數(shù)值改變的比例,以小數(shù)表示,小于0表示低于startValue,大于0表示超出endValue,0-1之間表示在startValue與endValue之間。我們要做的就是把這個值轉(zhuǎn)換為在起始和結(jié)果范圍之間的合適的對象值。
例如,對于基本的浮點類型,默認的FloatEvaluator是這樣的:1
2
3
4public Float evaluate(float fraction, Number startValue, Number endValue){
float startFloat = startValue.floatValue();
return startFloat + fraction * (endValue.floatValue() - startFloat);
}
可以看到,就是相當(dāng)于把fraction所表示的比例“投射”到了我們所需要的數(shù)據(jù)對象上,這里是浮點類型。如果使用我們的自定義類型,我們必須為自己的類型定義這樣的操作。
注意:這里要求我們必須將fraction線性地反應(yīng)到對應(yīng)的類型上,因為fraction反映的是最終的動畫進度,我們必須如實地按照這個進度改變我們的屬性,所以需要將result = x0 + t * (x1 - x0)`這樣的形式反映到我們自己的對象上。
自定義了TypeEvaluator以后就可以作為參數(shù)使用在上面的obObject()工廠方法中了。
插補細分器(Interpolators)
下面介紹使用ValueAnimator控制值變化過程中最為重要的一個概念:插補細分器(Interpolators)。
它實際上是一個關(guān)于時間的函數(shù), 根據(jù)時刻的不同來返回不同的值,進而來控制最后的輸出的值。那么它是如何表示的呢?
系統(tǒng)為我們提供了一系列預(yù)置的Interpolators,以較常用的LinearInterpolater為例,顧名思義,它是一個線性的插補細分器,意味著輸入與輸出呈線性關(guān)系:1
2
3public float getInterpolation(float input){
return input;
}
輸入輸出的關(guān)鍵函數(shù)就是這個getInterpolation()了,可以看到,參數(shù)與返回值都是float類型,input的值在0-1之間,結(jié)合前面,我們可以很容易理解,這個input就是一個以0-1之間的小數(shù)表示的過去的時間值,例如整個動畫是1000ms,當(dāng)input為0.25的時候意味著現(xiàn)在的時間過去了250ms。
而返回值就是經(jīng)過我們的轉(zhuǎn)換,表示出的動畫應(yīng)該進行的時間的比例,這里由于是線性的,所以可以直接返回input,這個值最后會到哪里呢?自然就是給我們前面介紹的TypeEvaluator。下面一段源碼展示了這個過程:1
2
3
4
5if (mInterpolator != null) {
fraction = mInterpolator.getInterpolation(fraction);
}
return mEvaluator.evaluate(fraction, mFirstKeyframe.getValue(),
mLastKeyframe.getValue());
作為getInterpolation()參數(shù)的fraction代表著過去的時間比例,這里調(diào)用我們設(shè)置的Interpolator來更新這個fraction,現(xiàn)在這個fraction表示的就是動畫已經(jīng)進行的比例,下一步就要根據(jù)它來獲取對應(yīng)的對象值(調(diào)用了我們之間談到過的evaluate()方法,這里的KeyFrame的概念會在之后的博客講到),后面的兩個參數(shù)就是傳遞給evaluate的起始與結(jié)束范圍。
最終,我們就獲得了一個按照我們設(shè)定的Interpolator返回的動畫屬性值。
如果想要實現(xiàn)加速效果呢?Android同樣為我們提供了現(xiàn)成的AccelerateInterpolator:1
2
3
4
5
6
7public float getInterpolation(float input){
if (mFactor == 1.0f) {
return input * input;
} else {
return (float)Math.pow(input, mDoubleFactor);
}
}
同樣很簡潔,這里用到了mFactor與mDoubleFactor分別表示我們在構(gòu)造函數(shù)里面設(shè)置的指數(shù)值:1
2
3
4public AccelerateInterpolator(float factor){
mFactor = factor;
mDoubleFactor = 2 * mFactor;
}
如果我們設(shè)置的為1,會返回input的平方,其他值則會返回input的mDoubleFactor次方,使得動畫屬性可以以不同的函數(shù)曲線形式變化。
如果我們要實現(xiàn)自己的Interpolator呢?只需要實現(xiàn)TimeInterpolator接口,這個接口只需要我們實現(xiàn)一個getInterpolation方法。我們可以根據(jù)input值返回不同的值來返回不同的值表示動畫的進度。
注意:返回值的范圍不一定要在0-1之間,小于0或大小1的值可以表示超出預(yù)設(shè)范圍的目標(biāo)值。
這篇博客到此結(jié)束,在下一篇博客中將會以一個繪制自由落體的彈跳小球的示例來演示如何使用Animator與介紹它的回調(diào)函數(shù)。
總結(jié)
以上是生活随笔為你收集整理的android 属性动画变大,Android PropertyAnimation 属性动画(一)初探的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 实例21:python
- 下一篇: 努比亚连续按下android版本,虚惊一