2025-03-27

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,
其核心流程涉及 事件傳遞順序、攔截邏輯 和 消費機制。

  1. 事件分發(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é)助完成


image.png

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ā)事件。

  1. 事件分發(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,避免重復遍歷視圖樹。

  1. 總結:
    核心思想:責任鏈模式,事件從頂層逐步下發(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事件接收起到非常大的作用

?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
【社區(qū)內容提示】社區(qū)部分內容疑似由AI輔助生成,瀏覽時請結合常識與多方信息審慎甄別。
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發(fā)布,文章內容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

相關閱讀更多精彩內容

友情鏈接更多精彩內容