Android事件拦截机制分析

说明:该内容参考《Android群英传》徐宜生著

首先我们先举个栗子,方便我们后面更好的理解。想像一下生活中的一个常见的场景:假设你所在的公司,有一个总经理,级别最高;他下面有一个部长,级别次之;最底层的就是干活的你,没有级别。那么董事会将事情交给了总经理一项任务,总经理将事情交给了部长,部长又把任务交给了你。而你好不容易将任务完成,然后你就把完成的任务交给了部长,部长觉得还不错,就签字后交给了总经理,总经理觉得还不错,就签了字就给了董事会。那么,这样一个任务也就顺理的完成了。Android事件分发和这个场景也非常类似。

那么下面我们就用代码简单的实现一下这样的一个场景:

一个总经理——MyViewGroupA,最外层的ViewGroup

一个部长——MyViewGroupB,中间层的ViewGroup

干活的你——MyView,最内层的View;  如下图


首先我们自定义ViewGourpA:


public class MyViewGroupA extends FrameLayout {

    public static 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 onTouchEvent(MotionEvent event) {
        Log.i(TAG, TAG + "    onTouchEvent");
        return super.onTouchEvent(event);
    }

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

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

VIewGroupB和ViewGroupA代码大同小异这里就不在粘贴代码了。


自定义View

public class MyView extends View {

    public static String TAG = "MyView";

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

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

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

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        setMeasuredDimension(measureSpec(widthMeasureSpec), measureSpec(heightMeasureSpec));
    }

    /*
    * specMode总共有三个值
    * EXACTLY:即精确值模式,当组件指定layout_height或layout_width的值时,系统默认是的模式
    * AT_MOST:即最大值模式,当layout_width或layout_height使用wrap_content时,控件的大小随内容的变化而变化,但最大值不能超过父控件的大小
    * UNSPECIFIED:view想多大就多大,一般在绘制自定义view时才使用
    * 一般情况下View类只支持EXACTLY模式。
    * */
    private int measureSpec(int measureSpec) {
        int result = 200;//当控件的layout_height或layout_width为wrap_content时显示的默认的大小
        int specMode = MeasureSpec.getMode(measureSpec);
        int specSize = MeasureSpec.getSize(measureSpec);

        if (specMode == MeasureSpec.EXACTLY) {
            result = specSize;
        } else {
            if (specMode == MeasureSpec.AT_MOST) {
                result = Math.min(specSize, result);
            }
        }
        return result;
    }

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


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:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context="com.example.mvp.handleevent.MainActivity">

    <com.example.mvp.handleevent.MyViewGroupA
        android:layout_width="368dp"
        android:layout_height="495dp"
        android:background="#000000">

        <com.example.mvp.handleevent.MyViewGroupB
            android:layout_width="300dp"
            android:layout_height="300dp"
            android:background="#ffffff">

            <com.example.mvp.handleevent.MyView
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:background="#ffff00">

            </com.example.mvp.handleevent.MyView>
        </com.example.mvp.handleevent.MyViewGroupB>
    </com.example.mvp.handleevent.MyViewGroupA>

</RelativeLayout>

代码很简单,这里就不多做解释;

点击View后的Log如下所示:


可以看见,正常情况下,事件的传递顺序是:

总经理(MyViewGroupA)——>部长(MyViewGroupB)——>你(View),事件在传递的时候执行dispatchTouchEvent()方法,再执行OnInterceptTouchEvent()方法。

事件的处理顺序是:

你——>部长——>总经理。

事件传递的返回值非常容易理解:true,拦截,不继续传递;反之;

事件处理也类似:true,处理了,上一级就不用审核了;false,则给上级处理;

初始的情况,返回值都是false。

有需要源码的同学欢迎访问 https://github.com/downdodoing/HandleEvent.git

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值