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

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

2017-06-25 17:57 731 查看

自定义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事件处理流程



总结:

Android事件分发是先传递到ViewGroup,再由ViewGroup传递到View的。

在ViewGroup中可以通过onInterceptTouchEvent方法对事件传递进行拦截,onInterceptTouchEvent方法返回true代表不允许事件继续向子View传递,返回false代表不对事件进行拦截,默认返回false。

子View中如果将传递的事件消费掉,ViewGroup中将无法接收到任何事件。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: