1. 程式人生 > >一張圖搞懂android事件分發機制

一張圖搞懂android事件分發機制

        事件分發機制在安卓中非常重要,這個事情如果搞不懂,會困擾你很多事情。比如說,應用了github上的某個大神的庫,如果發現這個庫實現了你需求的80%,還有那麼20%需要你結合實際需求來實現,改大神程式碼又不能改,怎麼辦呢?這個時候往往需要搞清楚自己的佈局控制元件和第三方庫的控制元件事件傳遞關係。說的比較模糊,沒關係,只要知道事件傳遞必須學會,就ok了。

     直接上圖(圖片較大,可右鍵標籤頁中開啟,也可下載下來看):

   

        圖上已經標的很清楚了,所有返回情況一定要知道,這樣的話,介面一些效果才能達到預期效果。如果想問這個事件傳遞自己怎麼去驗證我說的是對的,也簡單的,自己定義幾個view,巢狀佈局即可,簡單貼下程式碼:

<?xml version="1.0" encoding="utf-8"?>
<com.joyoung.eventdispatch.ActivityLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context="com.joyoung.eventdispatch.MainActivity">

    <com.joyoung.eventdispatch.ViewGroupLayout
        android:layout_width="match_parent"
        android:layout_height="200dp">
        <com.joyoung.eventdispatch.MyViewLayout
            android:id="@+id/button"
            android:layout_width="match_parent"
            android:layout_height="100dp"
            android:text="click me"
            android:background="@color/colorAccent"
             />

    </com.joyoung.eventdispatch.ViewGroupLayout>

</com.joyoung.eventdispatch.ActivityLayout>
public class ViewGroupLayout extends LinearLayout {
    private final String TAG = ViewGroupLayout.class.getName();
    public ViewGroupLayout(Context context) {
        super(context);
    }

    public ViewGroupLayout(Context context, @Nullable AttributeSet attrs) {
        super(context, attrs);
    }

    public ViewGroupLayout(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
    }

    @Override
    public boolean dispatchTouchEvent(MotionEvent ev) {
        Log.e(TAG, "----dispatchTouchEvent---------" + ev.getAction());
        return false;
    }

    @Override
    public boolean onInterceptTouchEvent(MotionEvent ev) {
        Log.e(TAG, "----onInterceptTouchEvent---------" + ev.getAction());
        return super.onInterceptTouchEvent(ev);
    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        Log.e(TAG, "----onTouchEvent---------" + event.getAction());
        return super.onTouchEvent(event);
    }
}
public class MyViewLayout extends View {
    private final String TAG = MyViewLayout.class.getName();
    public MyViewLayout(Context context) {
        super(context);
    }

    public MyViewLayout(Context context, @Nullable AttributeSet attrs) {
        super(context, attrs);
    }

    @Override
    public boolean dispatchTouchEvent(MotionEvent event) {
        Log.e(TAG, "----dispatchTouchEvent---------" + event.getAction());
        return true;
    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        Log.e(TAG, "----onTouchEvent---------" + event.getAction());
        return false;
    }
}

 基本的分析就是如上程式碼所示,通過日誌來分析事件傳遞的方向。最後總結一下:

  1. 如果從activity到viewgroup再到子view一路都是super的返回方式,表示不作任何處理,最後返回給上層的onTouchEvent處理,直到傳遞到activity,之後的事件也不會傳遞下來,直接在activity中通過dispatchTouchEvent的分發給onTouchEvent處理;
  2. activity和最終的子view中都沒有事件攔截onInterceptTouchEvent;
  3. dispatchTouchEvent的super有著自己的意義,並不是簡單的預設的false,如果是false的話,子view根本沒機會處理時間;
  4. 最底層view的onTouchEvent返回true消費完,不反饋, 上層檢視沒有收到處理資訊。返回false和返回super效果相同;
  5. activity的dispatchTouchEvent返回true和false事件都不會向下傳遞,只有返回super向下傳遞,也不會觸發activity中的onTouchEvent方法;