android事件分发机制

android事件分发机制:
我们在屏幕上进行一系列的点击/滑动/抬起等动作时所触发的事件,都是在与android的组件进行交互,而几乎所有的组件都是继承于View或ViewGroup,那他们在android应用中是如何被传递的呢?

事件分发离不开三个重要的方法:
public boolean dispatchTouchEvent(MotionEvent event) //事件分发:返回true当前view消耗事件 不再传递事件 false相反

public boolean onTouchEvent(MotionEvent event) //事件的响应返回true 标明事件已经被消耗 不再传递,false相反

public boolean onInterceptTouchEvent(MotionEvent ev) //拦截事件,true标明拦截此事件 false不拦截

View和ViewGroup都有前面两个方法,而ViewGroup独有第三个方法;因为ViewGroup是设计为组件容器,有一些子view,所以需要让事件传递进行拦截,而View只有它自己,所有不需要拦截;需要声明ViewGroup其实也是View的子类,并且重写了View的dispatchTouchEvent方法

View中事件传递:
以在Activity里面添加一个Button为例:
点击事件 —>> MainActivity(dispatchTouchEvent) —>> false传递给view Button;true则会在Acitivity消耗不再传递事件 —>> button组件 -->> dispatchTouchEvent -->> 如果有注册onTouchListener的话,则先执行Touch事件,返回true则不会执行后面的onTouchEvent和ClickListener;false就会继续执行后面的OnTouchEvent,而ClickListener就是在这里面的

以在Activity里面添加一个自定义viewGroup组件为例:
点击事件 —>> MainActivity(dispatchTouchEvent) —>> false传递给view Button;true则会在Acitivity消耗不再传递事件 —>> dispatchTouchEvent -->> onInterceptTouchEvent -->> 如果有子组件就调用子组件的dispatchTouchEvent -->> 子组件onInterceptTouchEvent -->>如果后面没有子组件了就调用onTouchEvent,如果onTouchEvent返回true则消耗此事件,false的话就事件回传,传给父组件的ontouchEvent,直到消耗此事件或者传回到屏幕

注意:

  1. 在ViewGroup中,如果要自定义是否拦截事件,除了要重写onInterceptTouchEvent方法之外,还要设置ViewGroup的mGroupFlags标志位,调用它的方法requestDisallowInterceptTouchEvent(true)去设置,因为在源码中,做了这样一个判断:
public boolean dispatchTouchEvent(MotionEvent ev) {
final boolean intercepted;
if (actionMasked == MotionEvent.ACTION_DOWN
        || mFirstTouchTarget != null) {
    mGroupFlags必须有FLAG_DISALLOW_INTERCEPT标志
    final boolean disallowIntercept = (mGroupFlags & FLAG_DISALLOW_INTERCEPT) != 0;
    if (!disallowIntercept) {
        intercepted = onInterceptTouchEvent(ev);
        ev.setAction(action); // restore action in case it was changed
    } else {
        intercepted = false;
    }    
} else {
    // There are no touch targets and this action is not an initial down
    // so this view group continues to intercept touches.
    intercepted = true;
}  
}
  1. ViewGroup在事件传递中,遍历自己的子View虽然是从末尾位置到开头,事件也是从末尾开始的,请看以下部分源码:
1. 在dispatchTouchEvent方法中遍历子View
final ArrayList<View> preorderedList = buildOrderedChildList();
final boolean customOrder = preorderedList == null
        && isChildrenDrawingOrderEnabled();
final View[] children = mChildren;
for (int i = childrenCount - 1; i >= 0; i--) {
    final int childIndex = customOrder
            ? getChildDrawingOrder(childrenCount, i) : i;
    final View child = (preorderedList == null)
            ? children[childIndex] : preorderedList.get(childIndex);
    dispatchTransformedTouchEvent将会去执行子view的事件传递        
	if (dispatchTransformedTouchEvent(ev, false, child, idBitsToAssign)) {
			省略部分代码
	}
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

帅气好男人_Jack

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值