Android基础1-事件拦截机制分析

Android基础1-事件拦截机制分析

关于Android的事件拦截机制,其实就是针对1个MotionEvent.ACTION_DOWN, 多个MotionEvent.ACTION_MOVE, 1个MotionEvent.ACTION_UP,

这一个完整的操作引起的一系列传递处理:

  • 基本传递流程
  • Show you my code
  • 总结
  • 下章内容

基本传递流程

Android的事件传递机制可以分为2部分,可以理解为1个V字型的结构。

ONE:

由上往下的传递过程,这个过程主要看ViewGroup的dispatchTouchEvent(…)的返回值,要是

关联函数有:dispatchTouchEvent,requestDisallowInterceptTouchEvent,onInterceptHoverEvent

TWO
由下往上的处理过程,这个过程是因为当前所处的View已经是这个ViewGroup树的最后一个节点了,

当前的View就是事件处理过程的起点,传递过程的终点。

这里的概念是:

要是当前的起点把dispatchTouchEvent(…)返回了true就表示把这个动作吃了,回调给上一级的父ViewGroup的时候父ViewGroup就没有处理的机会了。

要是当前的起点把dispatchTouchEvent(…)返回了false就表示并没有吃掉这个动作,回调给上一级的父ViewGroup的时候父ViewGroup的时候,交由父ViewGroup去处理。一直往上上去,一旦true就不交给父ViewGroup处理。

Show you my code

package com.cai.boluo.test;

import android.view.MotionEvent;
import android.view.View;

public class ViewGroup {

    protected static final int FLAG_DISALLOW_INTERCEPT = 0x80000;
    protected int mGroupFlags;

    public boolean dispatchTouchEvent() {
        boolean handled = false;
        boolean isIntercepted;
        if ((mGroupFlags & FLAG_DISALLOW_INTERCEPT) != 0) {
            isIntercepted = false;
        } else {
            isIntercepted = onInterceptTouchEvent();
        }
        if (!isIntercepted) {
            for (int i = 0; i < childCount; i++) {
                View ChildView = ViewChild[i];
                handled = ChildView.dispatchTouchEvent();
                if (handled)
                    return true;
            }
        }
        return onTouchEvent();
    }

    public boolean onInterceptTouchEvent() {
        return false;
    }
}

public class View {
    private boolean CLICKABLE = false;
    private boolean LONG_CLICKABLE = false;

    public boolean dispatchTouchEvent() {
        if (mOnTouchListener.onTouch()) {
            return true;
        }
        if (onTouchEvent()) {
            return true;
        }
        return false;
    }

    public boolean onTouchEvent() {
        if (CLICKABLE || LONG_CLICKABLE) {
            performClick();
            performLongClick();
            return true;
        }
        return false;
    }
}

上面试我看了ViewGroup.java和View.java之后整理出来的个人理解。
Read the fucking source
ViewGroup.java:
可以看出,默认的onInterceptTouchEvent()是返回false的,表示默认ViewGroup是不会拦截事件传递由上往下传递下去的,而这里的

dispatchTouchEvent
可以看得出,不管是传递还是处理,入口一直都是dispatchTouchEvent。

FLAG_DISALLOW_INTERCEPT
这个值判断优先级高于onInterceptTouchEvent,也就是说,如果针对ViewGroup的requestDisallowInterceptTouchEvent()函数处理了FLAG_DISALLOW_INTERCEPT这个值,那onInterceptTouchEvent写了也是白写。
当FLAG_DISALLOW_INTERCEPT和onInterceptTouchEvent的条件满足可以传递下去的时候,VIewGroup就会遍历自己子View,把事件传递下去。这里就是传递的过程。否则事件就不会传递下去,直接交由当前的ViewGroup自己执行处理流程,开始走由下往上的处理流程。

事件的处理流程
由代码可以看得出,

    public boolean dispatchTouchEvent() {
        if (mOnTouchListener.onTouch()) {
            return true;
        }
        if (onTouchEvent()) {
            return true;
        }
        return false;
    }

    public boolean onTouchEvent() {
        if (CLICKABLE || LONG_CLICKABLE) {
            performClick();
            performLongClick();
            return true;
        }
        return false;
    }

事件的处理是这样子的,首先判断当前的mOnTouchListener.onTouch()的返回值,如果是true就直接返回了,可以看出mOnTouchListener.onTouch()的优先级远远高于普通的mOnClickListener.
如果View没有设置mOnTouchListener,就会去走onTouchEvent(),在onTouchEvent()里面才会判断是否是* CLICKABLE || LONG_CLICKABLE*,有的话就分别执行我们平时设置的mOnclickListener和长按。
返回值: 取决于mOnTouchListener.onTouch()的返回值—–>onTouchEvent()的返回值—->onTouchEvent()执行了onClick和onLongClick之后会返回true,不能点击和长按的话才会返回false

总结
1:事件拦截机制分为传递和处理2个过程。
2:总入口都是ViewGroup和View的dispatchTouchEvent
3:由上往下,一旦为true不传递;由下往上,一旦为true不给处理
4:ViewGroup的拦截看FLAG_DISALLOW_INTERCEPT和onInterceptTouchEvent
5:View没有onInterceptTouchEvent不需要像ViewGroup一样去判断要不要传递下去,因为本来就是节点了,没法传递下去了,只需要看能不能在View里面把事件给处理掉。处理完了父的onTouchEvent还给不给执行。
6:View的处理优先级最高的是mOnTouchListener.onTouch(),返回true的话后面onTouchEvent()的click和longclick都没机会走了,返回false的话,继续看onTouchEvent()的CLICKABLE || LONG_CLICKABLE,一旦是CLICKABLE || LONG_CLICKABLE就会返回true,否则就会返回false.
7: View的dispatchTouchEvent()返回true的话,父ViewGroup就没机会执行自己的onTouchEvent(),要是返回false的话,父的onTouchEvent()还可以执行到。

Tips

处理View的滑动冲突

1:外部拦截法
所有的点击事件都是父ViewGroup中进行拦截,方式如下:
在onInterceptTouchEvent中根据event在DOWN, MOVE,UP 这3种情况下的坐标,来决定:
当前的ViewGroup中返回true,则事件交由当前ViewGroup的onTouchEvent来处理。
当前的ViewGroup中返回了false,则事件交给childView处理。
2:内部拦截法
所有的点击事件都交给子View去处理,父ViewGroup中的onInterceptTouchEvent一直返回false.
子View在dispatchTouchEvent中根据DOWN,MOVE,UP这3种情况的坐标,来调用parent.requestDisallowInterceptTouchEvent(true/false);
该函数可以在子View中要求父ViewGroup要不要拦截掉事件。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值