Android群英传——第三章事件分发机制

View事件分发机制

什么是分发?分发就是将一些事务交给下属来处理,事件的分发其实包含了:事件的拦截,事件的处理(这样说可能不是太准确)
事件拦截机制中,ViewGroup有onInterceptTouchEvent(),dispatchTouchEvent(),onTouchEvent()三个方法,分别起到事件分发、事件拦截、事件处理的作用
而View中只有dispatchTouchEvent(),onTouchEvent()方法。

假设有这样一个Layout: ViewGroupA -> ViewGroupB -> View

当用户点击了这个布局的时候,
首先会从最外层ViewGroupA开始进行判断,首先将事件分发给子View(dispatchTouchEvent()),即子View具有优先处理的权利

ViewGroupA代码如下

import android.content.Context;
import android.graphics.Canvas;
import android.util.AttributeSet;
import android.util.Log;
import android.view.MotionEvent;
import android.widget.LinearLayout;

/**
 * Created by feathers on 16-11-13.
 */

public class MyViewGroupA extends LinearLayout {

    private final String TAG = "MyViewGroupA";

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

    public MyViewGroupA(Context context, AttributeSet attrs) {
        super(context, attrs);
    }

    public MyViewGroupA(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
    }

    @Override
    public boolean dispatchTouchEvent(MotionEvent ev) {
        Log.i(TAG, "dispatchTouchEvent()");
        boolean b = super.dispatchTouchEvent(ev);
        Log.i(TAG, "dispatchTouchEvent() return ");
        return b;
    }

    @Override
    public boolean onInterceptTouchEvent(MotionEvent ev) {
        Log.i(TAG, "onInterceptTouchEvent()");
        boolean b = super.onInterceptTouchEvent(ev);
        Log.i(TAG, "onInterceptTouchEvent() return");
        return b;
    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        Log.i(TAG, "onTouchEvent()");
        boolean b = super.onTouchEvent(event);
        Log.i(TAG, "onTouchEvent() return");
        return b;
    }
}

ViewGroupB代码同A类似:

import android.content.Context;
import android.graphics.Canvas;
import android.util.AttributeSet;
import android.util.Log;
import android.view.MotionEvent;
import android.widget.LinearLayout;

/**
 * Created by feathers on 16-11-13.
 */

public class MyViewGroupB extends LinearLayout {

    private final String TAG = "MyViewGroupB";

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

    public MyViewGroupB(Context context, AttributeSet attrs) {
        super(context, attrs);
    }

    public MyViewGroupB(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
    }
    @Override
    public boolean dispatchTouchEvent(MotionEvent ev) {
        Log.i(TAG, "dispatchTouchEvent()");
        boolean b = super.dispatchTouchEvent(ev);
        Log.i(TAG, "dispatchTouchEvent() return");
        return b;
    }

    @Override
    public boolean onInterceptTouchEvent(MotionEvent ev) {
        Log.i(TAG, "onInterceptTouchEvent()");
        boolean b = super.onInterceptTouchEvent(ev);
        Log.i(TAG, "onInterceptTouchEvent() return ");
        return b;
    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        Log.i(TAG, "onTouchEvent()");
        boolean b = super.onTouchEvent(event);
        return b;
    }
}

地位最低的MyButton:

import android.content.Context;
import android.util.AttributeSet;
import android.util.Log;
import android.view.MotionEvent;
import android.widget.Button;

/**
 * Created by feathers on 16-11-13.
 */

public class MyButton extends Button {

    private final String TAG = "MyButton";

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

    public MyButton(Context context, AttributeSet attrs) {
        super(context, attrs);
    }

    public MyButton(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
    }

    @Override
    public boolean dispatchTouchEvent(MotionEvent event) {
        Log.i(TAG, "dispatchTouchEvent()");
        boolean b = super.dispatchTouchEvent(event);
        Log.i(TAG, "dispatchTouchEvent() return");
        return b;
    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        Log.i(TAG, "onTouchEvent()");
        boolean b = super.onTouchEvent(event);
        return b;
    }
}

xml如下:

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/activity_main"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context="com.example.myapplication.MainActivity">

   <com.example.myapplication.MyViewGroupA
       android:layout_width="match_parent"
       android:layout_height="match_parent">
       <com.example.myapplication.MyViewGroupB
           android:layout_width="match_parent"
           android:layout_height="match_parent">
           <com.example.myapplication.MyButton
               android:layout_width="wrap_content"
               android:layout_height="wrap_content"
               android:text="测试"/>
       </com.example.myapplication.MyViewGroupB>
   </com.example.myapplication.MyViewGroupA>
</RelativeLayout>

点击这个myButton:
输出以下信息:

//**DOWN事件,手按下
//最高一级捕获到动作,将事件分发给子View进行处理
// A开始分发
I/MyViewGroupA: dispatchTouchEvent()
// ViewGroupA是否要拦截事件,返回true代表拦截,则不会分发给子view
I/MyViewGroupA: onInterceptTouchEvent()
I/MyViewGroupA: onInterceptTouchEvent() return
// 如果没有被A拦截,B则会接受到此事件,然后同A相同,分发给子view,看看它们要不要处理
// B开始分发
I/MyViewGroupB: dispatchTouchEvent()
// ViewGroupB是否要拦截这个事件
I/MyViewGroupB: onInterceptTouchEvent()
I/MyViewGroupB: onInterceptTouchEvent() return 
// 没有被拦截,则让MyButton获取事件,同样先进性事件分发
I/MyButton: dispatchTouchEvent()
// 因为没有子View,所以不需要onIntercepTouchEvent()取判断是否交给子View处理
// 直接调用onTouchEvent()处理事件,但是有时候子View不想处理,如果不想处理,则onTouchEvent()可以返回false
I/MyButton: onTouchEvent()
// MyButton处理结束后,代表B的事件分发结束
I/MyButton: dispatchTouchEvent() return
// MyButton结束后,B也结束了
I/MyViewGroupB: dispatchTouchEvent() return
// 最后ViewGroupA的事件分发同样也结束了
I/MyViewGroupA: dispatchTouchEvent() return 
//**UP事件,手抬起
I/MyViewGroupA: dispatchTouchEvent()
I/MyViewGroupA: onInterceptTouchEvent()
I/MyViewGroupA: onInterceptTouchEvent() return
I/MyViewGroupB: dispatchTouchEvent()
I/MyViewGroupB: onInterceptTouchEvent()
I/MyViewGroupB: onInterceptTouchEvent() return 
I/MyButton: dispatchTouchEvent()
I/MyButton: onTouchEvent()
I/MyButton: dispatchTouchEvent() return
I/MyViewGroupB: dispatchTouchEvent() return
I/MyViewGroupA: dispatchTouchEvent() return 

当我们将事件拦截在ViewGroupB中会出现什么情况呢?
将ViewGroupB的onInterceptTouchEvent()返回值改为true

再来看log:

// GroupA给子View分发事件
I/MyViewGroupA: dispatchTouchEvent()
I/MyViewGroupA: onInterceptTouchEvent()
I/MyViewGroupA: onInterceptTouchEvent() return
// GroupB给子View分发事件
I/MyViewGroupB: dispatchTouchEvent()
I/MyViewGroupB: onInterceptTouchEvent()
I/MyViewGroupB: onInterceptTouchEvent() return 
// 这里发现onInterceptTouchEvent()的返回值为true,即需要拦截事件,此时ViewGroupB发现事件被拦截了,那么它自己就会处理事件
I/MyViewGroupB: onTouchEvent() // 调用onTouchEvent()处理事件
// B分发完成
I/MyViewGroupB: dispatchTouchEvent() return
// B分发完成后发现 A又调用了onTouchEvent()处理了事件,这是因为onTouchEvent()返回了false,即B虽然根据事件进行了处理,但是并没有消耗掉事件,这称为事件回传。
// 前面的MyButton处理事件后B没有调用onTouchEvent()的原因在于MyButton将事件消耗掉了,所以可以理解为事件被吃掉了,没有事件可以回传。
I/MyViewGroupA: onTouchEvent()
I/MyViewGroupA: onTouchEvent() return
// A分发完成
I/MyViewGroupA: dispatchTouchEvent() return 

既然dispatchTouchEvent()决定权这么大,那我们将dispatchTouchEvent()置为false会不会就代表这个事件不被处理了呢?
把ViewGroupView的dispatchTouchEvent()置为false:
LOg如下:

I/MyViewGroupA: dispatchTouchEvent()
I/MyViewGroupA: onInterceptTouchEvent()
I/MyViewGroupA: onInterceptTouchEvent() return
I/MyViewGroupB: dispatchTouchEvent()
I/MyViewGroupB: dispatchTouchEvent() return
// A发现B理都不理它,直接自己处理了
I/MyViewGroupA: onTouchEvent()
I/MyViewGroupA: onTouchEvent() return
I/MyViewGroupA: dispatchTouchEvent() return
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值