View体系(三)初探View事件分发机制

事件分发机制,简而言之就是Android对触摸事件的一系列传递和处理的机制。在了解分发机制之前需要对下面三个方法有个大概的了解:

  • public boolean dispatchTouchEvent(MotionEvent event)

用来进行事件的分发。如果有事件传递给当前View,那么此方法一定会被调用。返回值受当前View的onTouchEvent(MotionEvent event)和子ViewdispatchTouchEvent(MotionEvent event)方法的影响,表示是否消耗当前事件。

  • public boolean onInterceptTouchEvent(MotionEvent ev)

用来判断是否拦截事件,返回值表示是否拦截当前事件。

  • public boolean onTouchEvent(MotionEvent event)

用来处理事件,返回值表示是否消耗当前事件,如果不消耗,则在同一事件序列中,当前View无法再次接收到事件。

我们知道Android的View结构是树状结构的,View可以放在一个ViewGroup里,这个ViewGroup又可以放在一个ViewGroup里,那么当我们点击一个嵌套的结构,事件传递是怎样的呢?
为此,我们用代码来实现一下。

1.创建BaseViewGroup作为底层ViewGroup,代码如下:

public class BaseViewGroup extends FrameLayout {
    public BaseViewGroup(@NonNull Context context, @Nullable AttributeSet attrs) {
        super(context, attrs);
    }

    @Override
    public boolean dispatchTouchEvent(MotionEvent ev) {
        Log.d("ViewEvent", "BaseViewGroup-dispatchTouchEvent-"+ev.getAction());
        return super.dispatchTouchEvent(ev);
    }

    @Override
    public boolean onInterceptTouchEvent(MotionEvent ev) {
        Log.d("ViewEvent", "BaseViewGroup-onInterceptTouchEvent-"+ev.getAction());
        return super.onInterceptTouchEvent(ev);
    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        Log.d("ViewEvent", "BaseViewGroup-onTouchEvent-"+event.getAction());
        return super.onTouchEvent(event);
    }
}

2.创建TopViewGroup作为顶层ViewGroup,代码如下:

public class TopViewGroup extends FrameLayout {
    public TopViewGroup(@NonNull Context context, @Nullable AttributeSet attrs) {
        super(context, attrs);
    }

    @Override
    public boolean dispatchTouchEvent(MotionEvent ev) {
        Log.d("ViewEvent", "TopViewGroup-dispatchTouchEvent-"+ev.getAction());
        return super.dispatchTouchEvent(ev);
    }

    @Override
    public boolean onInterceptTouchEvent(MotionEvent ev) {
        Log.d("ViewEvent", "TopViewGroup-onInterceptTouchEvent-"+ev.getAction());
        return super.onInterceptTouchEvent(ev);
    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        Log.d("ViewEvent", "TopViewGroup-onTouchEvent-"+event.getAction());
        return super.onTouchEvent(event);
    }
}

3.创建MyView作为最上层的View,代码如下:

public class MyView extends View {
    public MyView(Context context, @Nullable AttributeSet attrs) {
        super(context, attrs);
    }

    @Override
    public boolean dispatchTouchEvent(MotionEvent ev) {
        Log.d("ViewEvent", "MyView-dispatchTouchEvent-"+ev.getAction());
        return super.dispatchTouchEvent(ev);
    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        Log.d("ViewEvent", "MyView-onTouchEvent-"+event.getAction());
        return super.onTouchEvent(event);
    }
}

4.布局自定义ViewViewGroup,代码如下:

<?xml version="1.0" encoding="utf-8"?>
<com.droidyu.viewsystem._3_event.BaseViewGroup xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="400dp"
    android:layout_height="400dp"
    android:background="#1f1"
    tools:context="._3_event.ViewEventActivity">

    <com.droidyu.viewsystem._3_event.TopViewGroup
        android:background="#ff1"
        android:layout_width="300dp"
        android:layout_height="300dp" >

        <com.droidyu.viewsystem._3_event.MyView
            android:background="#f11"
            android:layout_width="200dp"
            android:layout_height="200dp" />
    </com.droidyu.viewsystem._3_event.TopViewGroup>

</com.droidyu.viewsystem._3_event.BaseViewGroup>

最终,视图结构如下所示:

运行程序,点击红色的MyView,然后查看Log日志如下:

Log日志可以看出,正常情况下,

事件的传递顺序是:
BaseViewGroup -> TopViewGroup -> MyViewdispatchTouchEventonInterceptTouchEvent方法

事件处理顺序是:
MyView -> TopViewGroup -> BaseViewGrouponTouchEvent方法

此时将BaseViewGrouponInterceptTouchEvent返回值改为true,再次点击红色的MyView,然后查看Log日志如下:

Log日志可以看出,BaseViewGroup拦截事件之后,就直接处理事件,不会再将事件向子View传递。

还原代码,将TopViewGrouponInterceptTouchEvent返回值改为true,再次点击红色的MyView,然后查看Log日志如下:

Log日志可以看出,事件从BaseViewGroup传递到TopViewGroupTopViewGroup拦截事件之后,就直接处理事件,不会再将事件向子View传递,处理后会不消耗,返回给BaseViewGroup再处理。

还原代码,将MyViewonTouchEvent返回值改为true,再次点击红色的MyView,然后查看Log日志如下:

Log日志可以看出,事件传递到MyViewMyView处理事件之后,就不再向上传递。

还原代码,将TopViewGrouponTouchEvent返回值改为true,再次点击红色的MyView,然后查看Log日志如下:

Log日志可以看出,事件传递到MyViewMyView处理事件之后,又向上传递到TopViewGroup处理,TopViewGroup处理事件之后,就不再向上传递。

至此相信你对View的事件传递和处理有了一个更直观的认识,更多的讲解将在后续文章中更新,敬请期待。。。

源码见Github

学习更多知识,请关注我的个人博客:droidYu

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值