文章的知識借鑑了很多其他大神的內容,梳理了很久,有些內容已經忘記文章的銜接了,這裏對原作者說聲抱歉了。
本篇文章介紹的都是Android 的基礎內容,很多是老生常談了,不過我總結了自己經歷的一些項目,與學習中遇到的一些有代表性的內容,寫了一個Android動畫工程,基本可以與下面介紹的內容對照起來,感興趣的可以下載下來對照觀看,會更容易理解。
Android 系統提供了三種動畫:View animation 、 Frame animation 、Property animation
一,View animation
View animation 視圖動畫,也稱作(Tween)補間動畫,是一種漸進式動畫,通過圖像的平移、縮放、旋轉和透明度等漸進方式完成動畫效果。特別注意:補間動畫執行之後其實並沒有真正改變View的屬性,即left、top、right和bottom的值,只是系統臨時繪製的結果。View動畫也有一些特殊的使用場景,如LayoutAnimation,以及Actiivty切換的效果。
1.Animation
xml屬性 |
java方法 |
意義 |
android:detachWallpaper |
setDetachWallpaper(boolean) |
是否在壁紙上運行 |
android:duration |
setDuration(long) |
動畫持續時間,毫秒爲單位 |
android:fillAfter |
setFillAfter(boolean) |
動畫結束是否保持最後的狀態 |
android:fillBefore |
setFillBefore(boolean) |
動畫結束是否還原開始的狀態 |
android:fillEnabled |
setFillEnabled(boolean) |
與android:fillBefore效果相同 |
android:interpolator |
setInterpolator(Interpolator) |
設定插值器(指定的動畫效果,譬如回彈、勻速等) |
android:repeatCount |
setRepeatCount(int) |
重複次數 |
android:repeatMode |
setRepeatMode(int) |
重複類型有兩個值,reverse表示倒序回放,restart表示從頭播放 |
android:startOffset |
setStartOffset(long) |
調用start函數之後等待開始運行的時間,單位爲毫秒 |
android:zAdjustment |
setZAdjustment(int) |
表示被設置動畫的內容運行時在Z軸上的位置(top/bottom/normal),默認爲normal |
|
reset() |
重置Animation的初始化 |
|
cancel() |
取消Animation動畫 |
|
start() |
開始Animation動畫 |
|
setAnimationListener(AnimationListener listener) |
設置動畫監聽 |
|
hasStarted() |
判斷當前Animation是否開始 |
|
hasEnded() |
判斷當前Animation是否結束 |
2.AlphaAnimation 漸變透明度
xml屬性 |
java方法 |
意義 |
android:fromAlpha |
AlphaAnimation(float fromAlpha, …) |
動畫開始的透明度(0.0到1.0,0.0是全透明,1.0是不透明) |
android:toAlpha |
AlphaAnimation(…, float toAlpha) |
動畫結束的透明度,同上 |
3.RotateAnimation 旋轉動畫
xml屬性 |
java方法 |
意義 |
android:fromDegrees |
RotateAnimation(float fromDegrees, …) |
旋轉開始角度,正代表順時針度數,負代表逆時針度數 |
android:toDegrees |
RotateAnimation(…, float toDegrees, …) |
旋轉結束角度,正代表順時針度數,負代表逆時針度數 |
android:pivotX |
RotateAnimation(…, float pivotX, …) |
起點X座標(數值、百分數、百分數p,譬如50表示以當前View左上角座標加50px爲初始點、50%表示以當前View的左上角加上當前View寬高的50%做爲初始點、50%p表示以當前View的左上角加上父控件寬高的50%做爲初始點) |
android:pivotY |
RotateAnimation(…, float pivotY) |
起點Y座標,同上規律 |
4.ScaleAnimation 漸變伸縮動畫
xml屬性 |
java方法 |
意義 |
android:fromXScale |
ScaleAnimation(float fromX, …) |
初始X軸縮放比例,1.0表示無變化 |
android:toXScale |
ScaleAnimation(…, float toX, …) |
結束X軸縮放比例 |
android:fromYScale |
ScaleAnimation(…, float fromY, …) |
初始Y軸縮放比例 |
android:toYScale |
ScaleAnimation(…, float toY, …) |
結束Y軸縮放比例 |
android:pivotX |
ScaleAnimation(…, float pivotX, …) |
起點X座標(數值、百分數、百分數p,譬如50表示以當前View左上角座標加50px爲初始點、50%表示以當前View的左上角加上當前View寬高的50%做爲初始點、50%p表示以當前View的左上角加上父控件寬高的50%做爲初始點) |
android:pivotY |
ScaleAnimation(…, float pivotY) |
起點Y軸座標,同上規律 |
5. TranslateAnimation 位置移動動畫
xml屬性 |
java方法 |
意義 |
android:fromXDelta |
TranslateAnimation(float fromXDelta, …) |
起始點X軸座標(數值、百分數、百分數p,譬如50表示以當前View左上角座標加50px爲初始點、50%表示以當前View的左上角加上當前View寬高的50%做爲初始點、50%p表示以當前View的左上角加上父控件寬高的50%做爲初始點) |
android:fromYDelta |
TranslateAnimation(…, float fromYDelta, …) |
起始點Y軸從標,同上規律 |
android:toXDelta |
TranslateAnimation(…, float toXDelta, …) |
結束點X軸座標,同上規律 |
android:toYDelta |
TranslateAnimation(…, float toYDelta) |
結束點Y軸座標,同上規律 |
6. LayoutAnimation 佈局動畫,作用於ViewGroup,爲ViewGroup指定一個動畫,它的子元素出場時都具有這種動畫效果,初始化的時候觸發。
有兩種設置方式,一種直接在xml中設置,一種在代碼中通過LayoutAnimationController來設置,具體內容可以查看項目實例。
xml屬性 |
java方法 |
意義 |
android:delay |
setDelay(folat) |
子元素開始動畫延遲的時間 |
android:animationOrder |
setOrder() |
normal(順序顯示)、reverse(逆向顯示),random(隨機顯示) |
7. Activity切換效果
Activity有默認的切換效果,也可以自定義切換效果,主要是使用overridePendingTransition(int enterAnim, int exitAnim),這個方法必須在startActiivty()或者finis()之後調用纔有效。fragment(api11)可以添加切換動畫,兼容使用FragmentTransition的setCustomAnimation添加切換動畫,必須是View動畫,兼容和適配的問題。具體內容可以查看項目實例。
8.AnimationSet 繼承Animation,可以持有AlphaAnimation、RotateAnimation、ScaleAnimation、TranslateAnimation等動畫的容器。
|
Animation(boolean) |
true,共享插值器設定效果;flase,各自使用自身插拔器 |
9.Interpolator 插值器,指定動畫效果
java類 |
xml id值 |
描述 |
AccelerateDecelerateInterpolator |
@android:anim/accelerate_decelerate_interpolator |
動畫始末速率較慢,中間加速 |
AccelerateInterpolator |
@android:anim/accelerate_interpolator |
動畫開始速率較慢,之後慢慢加速 |
AnticipateInterpolator |
@android:anim/anticipate_interpolator |
開始的時候從後向前甩 |
AnticipateOvershootInterpolator |
@android:anim/anticipate_overshoot_interpolator |
類似上面AnticipateInterpolator |
BounceInterpolator |
@android:anim/bounce_interpolator |
動畫結束時彈起 |
CycleInterpolator |
@android:anim/cycle_interpolator |
循環播放速率改變爲正弦曲線 |
DecelerateInterpolator |
@android:anim/decelerate_interpolator |
動畫開始快然後慢 |
LinearInterpolator |
@android:anim/linear_interpolator |
動畫勻速改變 |
OvershootInterpolator |
@android:anim/overshoot_interpolator |
向前彈出一定值之後回到原來位置 |
PathInterpolator
|
|
新增,定義路徑座標後按照路徑座標來跑。 |
ShareInterpolator |
android:shareInterpolator=“boolean” |
set標籤中有多個動畫,共享時爲true;不共享,在每個動畫中添加 |
10. 自定義動畫,如Rotate3dAnimation
自定義需要繼承Animation,並重新applyTransformation(float interpolatedTime,Transformation t)方法和initalize(int width ,int height ,int parentWidth ,int parentHeight)方法。
a. interpolatedTime 代表了時間的進行程度,如設置時間1000ms,數值是0-—1,1表示動畫結束;Transformation 代表補間動畫在不同時刻對圖形或控件的變形程度。該對象封裝了一個Matrix對象,可以對它進行位移、傾斜、旋轉等變換,Transformation將對應的圖片或資源進行相應的變換。
b. initalize(…)函數,這是一個回調函數,告訴Animation目標View 的大小參數,在這裏可以初始化一些相關參數,如動畫執行時間、Interpolator等等。
爲了控制圖片或View進行三維空間的變換,還需要藉助於一個Camera類,這是一個3d空間變換工具,作用類似於Matrix,有如下常用方法:
getMatrix(Matrix matrix):將Camera所做的變換應用到指定的matrix上。
rotateX(float deg)、rotateY(float deg)、rotateZ(float deg):將目標控件沿X/Y/Z軸旋轉。
translate(float x,float y,float z):目標控件在三維空間進行位移變換。
applyToCanvas(Canvas canvas):把Camera所做的變換應用到Canvas上。
Camera類座標系可以參考 http://www.jianshu.com/p/34e0fe5f9e31
二,Frame animation
Frame animation 幀動畫,通過不停的切換圖片實現動畫效果,比較容易OOM,注意圖片大小和資源回收。
<animation-list>必須是根節點,包含一個或多個<item>元素,android:oneshot =“boolean”,true代表執行一次,false表示循環執行。在<item>元素中,android:drawable 表示Drawable資源,android:duration執行時間。
三,Property animation
Property animation 屬性動畫 ,通過不停的改變對象的屬性實現動畫效果,如平移translationX/Y、縮放scaleX/Y、旋轉rotationX/Y等並刷新屏幕來實現動畫效果,並且實現點擊位置的實時改變。在實際開發中建議採用代碼來實現屬性動畫,比較簡單,更重要的是,很多時候一個屬性的起始值是無法確認的。
java類 |
xml id值 |
描述 |
AnimatorSet |
<set> |
|
ValueAnimator |
<animator> |
|
ObjectAnimator |
<objectAnimator> |
|
|
android:ordering |
“together”表示動畫集合中的子動畫一起播放;“sequentially”集合動畫按照前後順序播放,默認是together |
1. ValueAnimator
在一個特定的時間內執行一個動畫,繼承於ValueAnimator它沒有直接操作屬性值的邏輯,需要添加動畫更新的監聽,並在onAnimationUpdater()中執行自定義的動畫邏輯。
ValueAnimator mAnimator =ValueAnimator.ofInt(1,100);
2. TimeAnimator
時序監聽會掉工具,是在api16引入,不能直接實現動畫效果,在監聽方法TimeListener中返回動畫持續的時間,邏輯也需要自己添加。
一個對象的一個屬性動畫, 繼承於ValueAnimator,允許你指定要進行動畫的對象以及該對象 的一個屬性。該類會根據計算得到的新值自動更新屬性。多數場景下采用的就是ObjectAnimator。
ObjectAnimator類提供了ofInt、ofFloat、ofObject這個三個常用的方法,這些方法都是設置動畫作用的元素、屬性、開始、結束等任意屬性值。當屬性值(上面方法的參數)只設置一個時就把通過getXXX反射獲取的值作爲起點,設置的值作爲終點;如果設置兩個(參數),那麼一個是開始、另一個是結束。
特別注意:ObjectAnimator的動畫原理是不停的調用setXXX方法更新屬性值,所有使用ObjectAnimator更新屬性時的前提是Object必須聲明有getXXX和setXXX方法。
我們通常使用ObjectAnimator設置View已知的屬性來生成動畫,而一般View已知屬性變化時都會主動觸發重繪圖操作,所以動畫會自 動實現;但是也有特殊情況,譬如作用Object不是View,或者作用的屬性沒有觸發重繪,或者我們在重繪時需要做自己的操作
ObjectAnimator objectAnimator = ObjectAnimator.ofFloat(View view,String propertyName,float... values);
view 表示動畫的對象
propertyName 作用對象的屬性名稱,如translationX/Y,scaleX/Y
float... values 一個集合的時間值,一般爲兩個值,開始、結束,有propertyName決定其意義,如果指定屬性表示的是顏色,就不需要指定valueType.
xml屬性 |
java方法 |
意義 |
android:propertyName |
ObjectAnimator.ofFloat(…,String propertyName,…) |
String類型,必須要設置的節點屬性,代表要執行動畫的屬性(通過名字引用),闢如你可以指定了一個View的”alpha” 或者 “backgroundColor” ,這個objectAnimator元素沒有對外說明target屬性,所以你不能在XML中設置執行這個動畫,必須通過調用 loadAnimator()方法加載你的XML動畫資源,然後調用setTarget()應用到具備這個屬性的目標對象上(譬如TextView) |
android:valueFrom |
ObjectAnimator.ofFloat(…,…,float startValue,…) |
相對應valueTo,動畫的起始點,如果沒有指定,系統會通過屬性的get方法獲取,顏色也是6位十六進制的數字表示。 |
android:valueTo |
ObjectAnimator.ofFloat(…,…,,…,float endValue) |
float、int或者color類型,必須要設置的節點屬性,表明動畫結束的點;如果是顏色的話,由6位十六進制的數字表示。 |
android:repeatCount |
setRepeatCount(int) |
重複次數,-1表示無限循環,默認0 |
android:repeatMode |
setRepeatMode(int) |
重複類型有兩個值,reverse表示倒序回放,restart表示從頭播放 |
android:startOffset |
setStartDelay(long startDelay) |
調用start函數之後等待開始運行的時間,單位爲毫秒 |
android:valueType |
ofFloat,ofInt |
指定屬性的類型,關鍵參數,如果該value是一個顏色,那麼就不需要指定,因爲動畫框架會自動的處理顏色值。有intType和floatType(默認)兩種:分別說明動畫值爲int和float型。 |
4. PropertyValuesHolder 多屬性動畫同時工作管理類(適合在同一個Vie對象)
PropertyValuesHolder a1 =PropertyValuesHolder.ofFloat(“alpha”,0,1f);
PropertyValuesHolder a2 =PropertyValuesHolder.ofFloat(“translationY”,0,1f);
ObjectAnimator.ofPropertyValuesHolder(view,a1,a2,…).setDuration(100).start();
5. AnimatorSet 動畫集合,相對於PropertyValuesHolder,AnimatorSet適合多個或單個View,可以設置動畫執行的順序,類似與View 動畫中的AnimationSet。
java方法 |
|
play |
執行 |
with |
同時執行 |
after |
在指定的動畫之後執行 |
before |
在指定的動畫之前執行 |
playTogether |
同時執行 |
playSequentially |
順序播放 |
6. 屬性動畫計算原理
a.Interpolator 插值器
AccelerateDecelerateInterolator:先加速後減速。
AccelerateInterpolator:加速。
DecelerateInterpolator:減速。
AnticipateInterpolator:先向相反方向改變一段再加速播放。
AnticipateOvershootInterpolator:先向相反方向改變,再加速播放,會超出目標值然後緩慢移動至目標值,類似於彈簧回彈。
BounceInterpolator:快到目標值時值會跳躍。
CycleIinterpolator:動畫循環一定次數,值的改變爲一正弦函數:Math.sin(2 * mCycles * Math.PI * input)。
LinearInterpolator:線性均勻改變。
OvershottInterpolator:最後超出目標值然後緩慢改變到目標值。
TimeInterpolator 時間插值器 ,一個允許自定義Interpolator的接口,以上都實現了該接口,根據時間流失的百分比來計算出當前屬性值改變的百分比。
b.Evaluator 類型估值器
Evaluators就是屬性動畫系統如何去計算一個屬性值。它們通過Animator提供的動畫的起始和結束值去計算一個動畫的屬性值。
IntEvaluator:整數屬性值。
FloatEvaluator:浮點數屬性值。
ArgbEvaluator:十六進制color屬性值。
TypeEvaluator:用戶自定義屬性值接口,譬如對象屬性值類型不是int、float、color類型,你必須實現這個接口去定義自己的數據類型。
根據當前屬性改變的百分比來計算改變後的屬性值,系統預設的有屬性動畫中的插值器和估值器是實現非勻速動畫的重要條件。
更具體的內容可以參照:http://www.cnblogs.com/huolongluo/p/6523552.html
7.ViewPropertyAnimator
其一:我們在一個沒有內建「屬性概念」的語言中做屬性動畫。由於系統運行時對「屬性」沒概念,因此 ObjectAnimator 需要通過特殊手段把「代表屬性名稱的字符串」變成對「目標對象屬性的 setter 方法」的調用。比如遇到字符串 "alpha" 就知道該去調用 View.setAlpha()。這種間接手段被稱爲反射 reflection 或者 JNI(java native interface),雖然可靠但會帶來額外開銷。基於對視圖屬性的瞭解,我們應該提供一些 API 使得動畫可以直接操作屬性,避開這種間接手段。
其二:有些情景中可能需要同時對一個 View 的多個屬性做動畫。雖然所有動畫共享計時機制而不會因計時產生額外開銷,但多個屬性動畫需要構造多個 Animator 對象。既然我們知道要對 View 的哪幾個屬性做動畫,就應該考慮將多個動畫合併成一個,以減少開銷。一種方法是使用 PropertyValuesHolder,它允許僅構造一個 Animator 對象,就可以實現多個屬性動畫。但這種方法需要更多的代碼,對簡單的動畫而言過於笨重。應該有一種新的方法既能實現我們的期望,同時代碼也是簡單易讀的。
其三:View 的每一個屬性都會執行一些操作以確保視圖對象及其父對象在合適的時候重繪。比如, 在 x 軸平移視圖,會使視圖過去和現在的位置失效,以確保父視圖正確地重繪它。而在 y 軸平移視圖,也會做類似的操作。如果這兩個屬性同時改變,還做雙份的重繪工作就顯得多餘。所以應該將這些工作合併在一起。ViewPropertyAnimator 可以做到
ViewPropertyAnimator 提供了一種並行屬性動畫的簡單方法。只需構建一個 Animator(譯註:針對上述2);能夠直接修改目標視圖的屬性值(譯註:針對上述1);優化重繪工作,使多個屬性的重繪僅發生一次(譯註:針對上述3)
一個簡單的例子:
AnimatorSet
ObjectAnimator animX = ObjectAnimator.ofFloat(myView, "x", 50f);
ObjectAnimator animY = ObjectAnimator.ofFloat(myView, "y", 100f);
AnimatorSet animSetXY = new AnimatorSet();
animSetXY.playTogether(animX, animY);
animSetXY.start();
PropertyValuesHolder
PropertyValuesHolder pvhX = PropertyValuesHolder.ofFloat("x", 50f);
PropertyValuesHolder pvhY = PropertyValuesHolder.ofFloat("y", 100f);
ObjectAnimator.ofPropertyValuesHolder(myView, pvhX, pvyY).start();
ViewPropertyAnimator(api12)
ViewPropertyAnimator viewPropertyAnimator =mCloud.animate();
viewPropertyAnimator.x(50f).y(100f);
或者mCloud.animate().x(50f).y(100f);
animate():從調用 View 對象的 animate() 方法開始,該方法返回一個 ViewPropertyAnimator 實例,然後就可以調用它的方法來設置動畫參數。
自動開始:要注意上述兩行代碼並未調用 start() 方法,因爲在新 API 中動畫啓動是隱式的,一旦聲明完,這些動畫就「立刻」「一起」啓動了。如果要深究細節的話,其實也並非「立刻」啓動,而是在下一次 UI 刷新時。ViewPropertyAnimator 正是利用了這個時間差,把所有聲明的動畫收集在一起。只要還在繼續聲明新的動畫,那麼所有動畫就會繼續等待下一次 UI 刷新。一旦完成聲明,所有動畫就在下一次 UI 刷新時一起啓動了。
流式接口:ViewPropertyAnimator 擁有流式接口(Fluent interface),允許函數鏈式調用,使得在一行代碼中可以構建多個屬性動畫。
更具體的內容可以參照:https://segmentfault.com/a/1190000004411201
8. LayoutTransition 容器佈局動畫
LayoutTransition對 ViewGroup中的View進行動畫設置顯示。LayoutTransition的動畫效果都是設置給ViewGroup,然後當被設置動畫的 ViewGroup中添加刪除View時體現出來。該類用於當前佈局容器中有View添加、刪除、隱藏、顯示等時候定義佈局容器自身的動畫和View的動 畫,也就是說當在一個LinerLayout中隱藏一個View的時候,我們可以自定義 整個由於LinerLayout隱藏View而改變的動畫,同時還可以自定義被隱藏的View自己消失時候的動畫等。
LayoutTransition類中主要有五種容器轉換動畫類型
• LayoutTransition.APPEARING:當View出現或者添加的時候View出現的動畫。
• LayoutTransition.CHANGE_APPEARING:當添加View導致佈局容器改變的時候整個佈局容器的動畫。
• LayoutTransition.DISAPPEARING:當View消失或者隱藏的時候View消失的動畫。
• LayoutTransition.CHANGE_DISAPPEARING:當刪除或者隱藏View導致佈局容器改變的時候整個佈局容器的動畫。
• LayoutTransition.CHANGE:當不是由於View出現或消失造成對其他View位置造成改變的時候整個佈局容器的動畫。
我們可以通過如下方式使用系統提供的默認ViewGroup的LayoutTransition動畫:android:animateLayoutChanges=”true”
在ViewGroup添加如上xml屬性默認是沒有任何動畫效果的,因爲前面說了,該動畫針對於ViewGroup內部東東發生改變時纔有效,所以當我們設置如上屬性然後調運ViewGroup的addView、removeView方法時就能看見系統默認的動畫效果了。
還有一種就是通過如下方式設置: android:layoutAnimation=”@anim/customer_anim”
在使用LayoutTransition時,你可以自定義這幾種事件類型的動畫,也可以使用默認的動畫,總之最終都是通過 setLayoutTransition(LayoutTransition lt)方法把這些動畫以一個LayoutTransition對象設置給一個ViewGroup。譬如實現如上Xml方式的默認系統LayoutTransition動畫如下:
LayoutTransition mTransitioner = new LayoutTransition();
mViewGroup.setLayoutTransition(mTransitioner);
稍微再高端一點吧,我們來自定義這幾類事件的動畫,分別實現他們,那麼你可以像下面這麼處理:
mTransitioner = new LayoutTransition();
......
ObjectAnimator anim = ObjectAnimator.ofFloat(this, "scaleX", 0, 1);
......//設置更多動畫
mTransition.setAnimator(LayoutTransition.APPEARING, anim);
......//設置更多類型的動畫
mViewGroup.setLayoutTransition(mTransitioner);
9.Keyframes
keyFrame是一個 時間/值 對,通過它可以定義一個在特定時間的特定狀態,而且在兩個keyFrame之間可以定義不同的Interpolator,就相當多個動畫的拼接,第一個動畫的結束點是第二個動畫的開始點。KeyFrame是抽象類,要通過ofInt(),ofFloat(),ofObject()獲得適當的KeyFrame,然後通過PropertyValuesHolder.ofKeyframe獲得PropertyValuesHolder對象,如以下例子:
Keyframe kf0 = Keyframe.ofInt(0, 400);
Keyframe kf1 = Keyframe.ofInt(0.25f, 200);
Keyframe kf2 = Keyframe.ofInt(0.5f, 400);
Keyframe kf4 = Keyframe.ofInt(0.75f, 100);
Keyframe kf3 = Keyframe.ofInt(1f, 500);
PropertyValuesHolder pvhRotation = PropertyValuesHolder.ofKeyframe("width", kf0, kf1, kf2, kf4, kf3);
ObjectAnimator rotationAnim = ObjectAnimator.ofPropertyValuesHolder(btn2, pvhRotation);
rotationAnim.setDuration(2000);
上述代碼的意思爲:設置btn對象的width屬性值使其:
開始時 Width=400
動畫開始1/4時 Width=200
動畫開始1/2時 Width=400
動畫開始3/4時 Width=100
動畫結束時 Width=500
第一個參數爲時間百分比,第二個參數是在第一個參數的時間時的屬性值。
定義了一些Keyframe後,通過PropertyValuesHolder類的方法ofKeyframe封裝,然後通過ObjectAnimator.ofPropertyValuesHolder獲得Animator。
用下面的代碼可以實現同樣的效果:
ObjectAnimator oa=ObjectAnimator.ofInt(btn2, "width", 400,200,400,100,500);
oa.setDuration(2000);
oa.start();
=====================================
Android Animation 項目地址:https://github.com/xianjuren/AndroidAnimation