Android自定义View的事件分发机制(二)

自定义View的事件分发机制(二)

  • 回顾
  • ViewGroup的事件分发

回顾

我们上一篇写了View的事件分发,暂且在此做一个回顾。

1、我们可以看出View的onTouchListener和onTouchEvent都是在dispatchTouchEvent这里被调用的。

2、 onTouch和onTouchEvent有什么区别,又该如何使用?
从源码中可以看出,这两个方法都是在View的dispatchTouchEvent中调用的,onTouch优先于onTouchEvent执行。如果在onTouch方法中通过返回true将事件消费掉,onTouchEvent将不会再执行。

另外需要注意的是,onTouch能够得到执行需要两个前提条件,第一mOnTouchListener的值不能为空,第二当前点击的控件必须是enable的。因此如果你有一个控件是非enable的,那么给它注册onTouch事件将永远得不到执行。对于这一类控件,如果我们想要监听它的touch事件,就必须通过在该控件中重写onTouchEvent方法来实现。

3、为什么我们自定义View的时,处理点击事件Touch事件时,要在onTouchEvent方法中返回true?

每一个触屏事件都必须是以ACTION_DOWN作为开头,后面跟一系列的ACTION_MOVE,最后再有一个ACTION_UP(或ACTION_CANCEL),标识触屏事件结束。所以Android就在ACTION_DOWN的时候做文章,官方文档对dispatchTouchEvent的返回值的解释是:True if the event was handled by the view, false otherwise。我们可以简单的理解为如果返回true,就说明它需要处理这个事件,就让它接收所有的触屏事件,否则,说明它不用处理,也就不让它接收后续的触屏事件了。

也就是是此时如果不返回true,是接收不到除了down的任何事件的。

ViewGroup的事件分发

ViewGroup顾名思义:也就是一系列View集合的意思。

前面我们也说到ViewGroup处理事件分发会涉及到三个回调方法

1、dispatchTouchEvent 分发
2、onInterceptTouchEvent 拦截
3、onTouchEvent 处理

@Override
    public boolean dispatchTouchEvent(MotionEvent ev) {
        return super.dispatchTouchEvent(ev);
    }

    @Override
    public boolean onInterceptTouchEvent(MotionEvent ev) {
        return super.onInterceptTouchEvent(ev);
    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        return super.onTouchEvent(event);
    }

这里我们先写一个demo,看一下系统正常的事件传递,这里我通过自定义的ViewGroup包裹了我们自定义的View

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

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

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

    @Override
    public boolean dispatchTouchEvent(MotionEvent ev) {
        Log.e("ViewGroup的事件分发","ViewGroup->dispatchTouchEvent:"+ev.getAction());
        return super.dispatchTouchEvent(ev);
    }

    @Override
    public boolean onInterceptTouchEvent(MotionEvent ev) {
        Log.e("ViewGroup的事件分发","ViewGroup->onInterceptTouchEvent:"+ev.getAction());
        return super.onInterceptTouchEvent(ev);
    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        Log.e("ViewGroup的事件分发","ViewGroup->onTouchEvent:"+event.getAction());
        return super.onTouchEvent(event);
    }
}
<com.wn.view01.TouchViewGroup
    android:id="@+id/costom_view_group"
    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"
    android:paddingBottom="@dimen/activity_vertical_margin"
    android:paddingLeft="@dimen/activity_horizontal_margin"
    android:paddingRight="@dimen/activity_horizontal_margin"
    android:paddingTop="@dimen/activity_vertical_margin"
    tools:context="com.wn.view01.MainActivity">

    <com.wn.view01.TouchView
        android:id="@+id/costom_view"
        android:layout_width="100dp"
        android:layout_height="100dp"
        android:background="@color/colorAccent"/>


</com.wn.view01.TouchViewGroup>

现象:
这里写图片描述

分解:

DOWN事件: ViewGroup.dispatchTouchEvent -> ViewGroup.onInterceptTouchEvent -> View.dispatchTouchEvent -> View.onTouch -> View.onTouchEvent

UP事件: ViewGroup.dispatchTouchEvent -> ViewGroup onInterceptTouchEvent -> View.onTouch -> View.onTouchEvent -> View.onclick

所以可以看出ViewGroup的整体事件的传递流程。从ViewGroup.dispatchTouchEvent到ViewGroup.onInterceptTouchEvent,再到View的事件。

这里我们有这样一个需求,就是我现在不需要子View响应任何触摸事件,这也是我们开发中比较常见的。那么此时我们该怎么办?

此时你会发现,我们的ViewGroup onInterceptTouchEvent起到了关键作用。这个方法我们通过看源码可以得知,他默认是返回false,现在我们重写这个方法,让他返回为true。

@Override
    public boolean onInterceptTouchEvent(MotionEvent ev) {
        Log.e("ViewGroup的事件分发","ViewGroup->onInterceptTouchEvent:"+ev.getAction());
        return true;
    }

这里写图片描述

从上图日志你可以看出,发现重写此方法后,子View的点击事件不在响应。

那么问题来了,此时子View的事件没有响应。我们ViewGroup的事件只响应了Down事件。如果我们想要监听ViewGroup的事件,此时要么设置他的点击事件,要么在onTouchEvent方法中返回true。这也是我们上一节所讲的知识点。

ViewGroup事件处理流程

这里写图片描述

总结:

  1. Android事件分发是先传递到ViewGroup,再由ViewGroup传递到View的。
  2. 在ViewGroup中可以通过onInterceptTouchEvent方法对事件传递进行拦截,onInterceptTouchEvent方法返回true代表不允许事件继续向子View传递,返回false代表不对事件进行拦截,默认返回false。
  3. 子View中如果将传递的事件消费掉,ViewGroup中将无法接收到任何事件。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值