天天看點

淺談Android 事件分發機制(一)

Android事件分發機制是Android開發者必須了解的知識,這方面的内容很多,自己純看文章總覺得比較抽象,自己寫了個demo,理一下事件分發的流程,加深印象。

view結構

image

PhoneWindow 的訓示通過 DecorView 傳遞給下面的 View,下面 View 的資訊也通過 DecorView 回傳給 PhoneWindow。這裡我們主要聊聊ViewGroup與view的事件分發

類型 相關方法 ViewGroup View
事件分發 dispatchTouchEvent
事件攔截 onInterceptTouchEvent ×
事件消費 onTouchEvent

dispatchTouchEvent

一般改寫不多,主要關注另外兩個。

onInterceptTouchEvent

,true,攔截,交給自己的onTouchEvent處理,不傳給下級;false,不攔截,傳給下級。

onTouchEvent

,true,自己搞定消費,不用上傳;false,上傳。

事件模拟

如圖布局,最外層的父布局ViewGroupA,中間層的ViewGroupB,最裡層的ViewC

<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    xmlns:app="http://schemas.android.com/apk/res-auto">

    <com.qhyccd.event.ViewGroupA
        app:layout_constraintTop_toTopOf="parent"
        android:layout_marginTop="100dp"
        android:layout_width="300dp"
        android:layout_height="300dp"
        android:background="@color/colorRed">

        <com.qhyccd.event.ViewGroupB
            android:layout_width="200dp"
            android:layout_height="200dp"
            android:background="@color/colorYellow">

            <com.qhyccd.event.ViewC
                android:layout_width="100dp"
                android:layout_height="100dp"
                android:background="@color/colorBlue" />

        </com.qhyccd.event.ViewGroupB>

    </com.qhyccd.event.ViewGroupA>

</FrameLayout>
           

首先模拟下以上場景,A、B、C三個角色,A>B>C

ViewGroupA

public class ViewGroupA extends LinearLayout {
    public ViewGroupA(Context context) {
        super(context);
    }

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

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

    @Override
    public boolean dispatchTouchEvent(MotionEvent ev) {
        Log.i("》》》", " ViewGroupA dispatchTouchEvent  ");
        return super.dispatchTouchEvent(ev);
    }

    @Override
    public boolean onInterceptTouchEvent(MotionEvent ev) {
        Log.i("》》》", " ViewGroupA onInterceptTouchEvent  ");
        return super.onInterceptTouchEvent(ev);
    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        Log.i("》》》", " ViewGroupA onTouchEvent  ");
        return super.onTouchEvent(event);
    }
}
           

ViewGroupB

public class ViewGroupB extends LinearLayout {

    public ViewGroupB(Context context) {
        super(context);
    }

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

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

    @Override
    public boolean dispatchTouchEvent(MotionEvent ev) {
        Log.i("》》》", " ViewGroupB dispatchTouchEvent  ");
        return super.dispatchTouchEvent(ev);;
    }

    @Override
    public boolean onInterceptTouchEvent(MotionEvent ev) {
        Log.i("》》》", " ViewGroupB onInterceptTouchEvent  ");
        return super.onInterceptTouchEvent(ev);
    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        Log.i("》》》", " ViewGroupB onTouchEvent  ");
        return super.onTouchEvent(event);
    }

}
           

ViewC

public class ViewC extends View {

    public ViewC(Context context) {
        super(context);
    }

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

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

    @Override
    public boolean dispatchTouchEvent(MotionEvent event) {
        Log.i("》》》", " ViewC dispatchTouchEvent  ");
        return super.dispatchTouchEvent(event);
    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        Log.i("》》》", " ViewC onTouchEvent  ");
        return super.onTouchEvent(event);
    }
}

           

情景一

預設情況下,點選C區域

ViewGroupA dispatchTouchEvent
ViewGroupA onInterceptTouchEvent
ViewGroupB dispatchTouchEvent  
ViewGroupB onInterceptTouchEvent  
ViewC dispatchTouchEvent 
ViewC onTouchEvent  
ViewGroupB onTouchEvent  
ViewGroupA onTouchEvent  
           

可見,事件是從A->B->C,再從C->B->A回傳

情景二

A想自己把事件攔截,不給下級處理,A裡面

onInterceptTouchEvent

傳回ture攔截事件

ViewGroupA dispatchTouchEvent 
ViewGroupA onInterceptTouchEvent
ViewGroupA onTouchEvent 
           

情景三

B想自己把事件攔截,不給下級處理,B裡面

onInterceptTouchEvent

傳回ture攔截事件。

ViewGroupA dispatchTouchEvent
ViewGroupA onInterceptTouchEvent
ViewGroupB dispatchTouchEvent  
ViewGroupB onInterceptTouchEvent  
ViewGroupB onTouchEvent  
ViewGroupA onTouchEvent  
           

B這裡隻是對事件攔截不往下傳遞,還是會往上回傳的。

如果想讓B自己把事件消費,不往上級傳遞,B的

onTouchEvent

傳回true

ViewGroupA dispatchTouchEvent
ViewGroupA onInterceptTouchEvent
ViewGroupB dispatchTouchEvent  
ViewGroupB onInterceptTouchEvent  
ViewGroupB onTouchEvent  
           

情景四

C屬于最底層view,對事件沒有攔截權限,C自己想把事件消費了,C的

onTouchEvent

傳回

true

,不再往上級回傳

ViewGroupA dispatchTouchEvent
ViewGroupA onInterceptTouchEvent
ViewGroupB dispatchTouchEvent  
ViewGroupB onInterceptTouchEvent  
ViewC dispatchTouchEvent 
ViewC onTouchEvent  
           

以上是靜态點選事件處理流程,模拟的事件分發機制,通過log列印可以看到事件的傳遞流程,這篇文章屬于基礎篇章,後續我們給view添加滑動,通過處理滑動沖突進一步了解事件的分發機制,敬請期待下一篇。

END

祝大家五一勞動節快樂!緻敬奮鬥在一線的碼農!

歡迎關注微信号

image.png

繼續閱讀