您的位置:首页 > 移动开发 > Android开发

Android事件拦截机制分析

2017-04-07 10:57 253 查看
说明:该内容参考《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)——&g
9219
t;你(View),事件在传递的时候执行dispatchTouchEvent()方法,再执行OnInterceptTouchEvent()方法。

事件的处理顺序是:

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

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

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

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

有需要源码的同学欢迎访问 https://github.com/downdodoing/HandleEvent.git
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: