Android 動畫的實現(xiàn)原理
Android 動畫的實現(xiàn)原理主要涉及視圖刷新機制、時間插值和屬性計算,其核心是通過不斷修改視圖屬性(如位置、透明度等)并觸發(fā)重繪來實現(xiàn)動態(tài)效果.
- 視圖動畫(View Animation)
僅影響視圖的繪制結果,不改變視圖的實際位置或大小(例如點擊事件仍停留在原位置)。 - 屬性動畫(Property Animation)----實際修改屬性值(如 view.setTranslationX()),影響視圖布局和交互。
原理:
通過 ValueAnimator 或 ObjectAnimator 動態(tài)修改對象的任意屬性(包括自定義屬性),
利用反射或 PropertyValuesHolder 實現(xiàn)屬性值的連續(xù)變化。
核心類:
ValueAnimator:計算動畫過程中的值,需手動更新屬性。
ObjectAnimator:自動更新目標對象的屬性(如 View 的 alpha、translationX)。
AnimatorSet:組合多個動畫。
關鍵機制:時間插值(Interpolator),類型估值器(TypeEvaluator)
底層原理:
動畫的每一幀由 Choreographer 調度,通過 VSYNC 信號同步屏幕刷新率(通常 60Hz)。
ValueAnimator 在每幀回調中計算新值,并觸發(fā)視圖重繪(invalidate())。
事件的分發(fā)機制
Android 的事件分發(fā)機制負責將用戶觸摸事件(MotionEvent)傳遞到正確的 View 或 ViewGroup,
其核心流程涉及 事件傳遞順序、攔截邏輯 和 消費機制。
- 事件分發(fā)的三個核心方法
| 方法 | 作用 | 返回值意義 |
|---|---|---|
| dispatchTouchEvent | 事件分發(fā)入口,負責將事件傳遞給子視圖或自身處理。 | true:事件被消費;false:未消費,繼續(xù)向上傳遞。 |
| onInterceptTouchEvent | 僅 ViewGroup 有,判斷是否攔截事件。 | true:攔截事件,不再下發(fā)子視圖;false:繼續(xù)下發(fā)。 |
| onTouchEvent | 處理事件(如點擊、滑動)。 | true:消費事件;false:未消費,向上傳遞。 |
dispatchTouchEvent:方法事件,當點擊事件傳給當前view時,這個方法被調用;
onInterceptTouchEvent:在dispatchTouchEvent()內部調用,判斷是否攔截該事件;
onTouchEvent: 在dispatchTouchEvent()內部調用。處理點擊事件。
Android中事件分發(fā)順序:Activity(Window) -> ViewGroup -> View
事件分發(fā)過程由dispatchTouchEvent() 、onInterceptTouchEvent()和onTouchEvent()三個方法協(xié)助完成

dispatchTouchEvent 方法事件: View,ViewGroup都有。
View 只會把事件分發(fā)到View.onTouchEvent();
ViewGroup 有一套分發(fā)的標準--onInterceptTouchEvent()。
onInterceptTouchEvent攔截方法分發(fā)。 ViewGroup獨有的。攔截了,其子類就收不到事件。
intercepted = true; // 沒有分發(fā)路徑,且也不是Down事件,直接攔截掉。
onTouchEvent 只有一個view,響應down事件,形成單鏈表下發(fā)后序move/up事件。move事件根據(jù)單鏈表分發(fā)事件。
- 事件分發(fā)流程
DOWN 事件流程(后續(xù) MOVE/UP 事件流程依賴 DOWN 事件的分發(fā)結果)
當一個點擊事件發(fā)生后,系統(tǒng)需要將這個事件傳遞給一個具體的view去處理。這個事件傳遞的過程就是分發(fā)過程。
a。Activity → Window → DecorView
事件首先由 Activity.dispatchTouchEvent() 傳遞到 Window(通常是 PhoneWindow),再轉到頂層 DecorView(根 ViewGroup)。
b。自上而下傳遞(ViewGroup)
從父 ViewGroup 到子 View,依次調用:
parent.dispatchTouchEvent()
→ parent.onInterceptTouchEvent() // 判斷是否攔截
→ child.dispatchTouchEvent() // 若不攔截,繼續(xù)下發(fā)
→......
c。自下而上處理(View)
若子 View 的 onTouchEvent() 返回 false(未消費),事件會回溯到父 ViewGroup 的 onTouchEvent()。
d。最終處理
若所有 View 均未消費事件,最終由 Activity.onTouchEvent() 處理。
MOVE/UP 事件流程
若 DOWN 事件被某個 View 消費,后續(xù)事件(MOVE、UP)會直接dispatchTouchEvent分發(fā)給該 View,不再經(jīng)過 onInterceptTouchEvent 判斷(除非手動干預)。
3.關鍵規(guī)則
攔截機制:
- ViewGroup 可通過 onInterceptTouchEvent() 攔截事件(如 ScrollView 在滑動時攔截子 View 的點擊事件)。
- 一旦攔截,該事件序列(DOWN 到 UP)后續(xù)事件均直接交給該 ViewGroup 的 onTouchEvent()。
消費優(yōu)先級:
View.onTouchListener > View.onTouchEvent() > View.onClickListener。
若 onTouchListener 返回 true,則 onTouchEvent 和 onClick 不會被觸發(fā)。
事件序列完整性:
若 View 未消費 DOWN 事件,后續(xù)事件(MOVE/UP)不會再傳遞給它。
4.底層機制
InputEventReceiver:
系統(tǒng)通過 ViewRootImpl 接收底層輸入事件,并通過 Choreographer 同步到主線程。
事件傳遞優(yōu)化:
Android 使用 TouchTarget 鏈表記錄能接收事件的 View,避免重復遍歷視圖樹。
- 總結:
核心思想:責任鏈模式,事件從頂層逐步下發(fā),再由底層決定是否消費。
優(yōu)化點:
避免在 onTouchEvent 中阻塞主線程。
合理使用 requestDisallowInterceptTouchEvent() 解決滑動沖突。
理解事件分發(fā)機制有助于自定義復雜交互(如嵌套滾動、手勢沖突)并優(yōu)化性能。
onIntercepterEvent Down事件。攔截事件分發(fā)的遍歷順序:根,右,左。與先序遍歷相反。
先遍歷根節(jié)點,再從右邊開始,最后遍歷左邊的子樹。
Down事件,走樹的遍歷分發(fā)。
move事件:Down事件返回true,會形成單鏈表,單鏈表的遍歷比樹的遍歷效率高。后序的move/up 事件,通過這個單鏈表分發(fā)路徑分發(fā)。
Cancel事件:系統(tǒng)內部做的,清除鏈表(分發(fā)路徑),非人為原因結束本次事件。
滑到屏幕底部,攔截掉事件后(onIntercepterEvent() return true),
在攔截的位置,生成Cancel事件,交由鏈表。鏈表下的所有元素都能收到Cancel事件。收到cancel事件后,會清空鏈表關系。分發(fā)路徑就沒了。
只有的move/up事件,只能分配到根節(jié)點vp1.
假設ViewGroup B希望處理這個點擊事件,即B覆寫了onInterceptTouchEvent()返回true、onTouchEvent()返回true。
- 調用onTouchEvent()處理事件(DOWN事件將不再往上傳遞給A的onTouchEvent())
- 該事件列的其他事件(Move、Up)將直接傳遞給B的onTouchEvent()。該事件列的其他事件(Move、Up)將不會再傳遞給B的onInterceptTouchEvent方法,該方法一旦返回一次true,就再也不會被調用了。
假設ViewGroup B沒有攔截DOWN事件(還是View C來處理DOWN事件),但它攔截了接下來的MOVE事件。
- DOWN事件傳遞到C的onTouchEvent方法,返回了true。
- 在后續(xù)到來的MOVE事件,B的onInterceptTouchEvent方法返回true攔截該MOVE事件,但該事件并沒有傳遞給B;這個MOVE事件將會被系統(tǒng)變成一個CANCEL事件傳遞給C的onTouchEvent方法。
- 后續(xù)又來了一個MOVE事件,該MOVE事件才會直接傳遞給B的onTouchEvent()。
后續(xù)事件將不會再傳遞給B的onInterceptTouchEvent方法,該方法一旦返回一次true,就再也不會被調用了。
4.1.2 匯總
當一個點擊事件發(fā)生時,調用順序如下
1.事件最先傳到Activity的dispatchTouchEvent()進行事件分發(fā)
2.調用Window類實現(xiàn)類PhoneWindow的superDispatchTouchEvent()
3.調用DecorView的superDispatchTouchEvent()
4.最終調用DecorView父類的dispatchTouchEvent(),即ViewGroup的dispatchTouchEvent()
View的dispatchTouchEvent()的源碼分析
public boolean dispatchTouchEvent(MotionEvent event) {
if (mOnTouchListener != null && (mViewFlags & ENABLED_MASK) == ENABLED && mOnTouchListener.onTouch(this, event)) {
return true;
}
return onTouchEvent(event);
}
onTouch()的執(zhí)行高于onClick()
當控件被點擊,onTouch()返回false(該事件沒被onTouch()消費掉) = dispatchTouchEvent()返回false(繼續(xù)向下傳遞) = 執(zhí)行onTouchEvent() = 執(zhí)行OnClick()
onTouch()和onTouchEvent()的區(qū)別
這兩個方法都是在View的dispatchTouchEvent中調用,但onTouch優(yōu)先于onTouchEvent執(zhí)行。
如果在onTouch方法中返回true將事件消費掉,onTouchEvent()將不會再執(zhí)行。
dispatchTouchEvent()和 onTouchEvent()消費事件、終結事件傳遞(返回true)
而onInterceptTouchEvent 并不能消費事件,它相當于是一個分叉口起到分流導流的作用,對后續(xù)的ACTION_MOVE和ACTION_UP事件接收起到非常大的作用