Android中view的Touch事件

当屏幕中包含一个ViewGroup,而这个ViewGroup又包含一个子view,这个时候android系统如何处理Touch事件呢?到底是ViewGroup来处理Touch事件,还是子view来处理Touch事件呢?我只能很肯定的对你说不一定。呵呵,为什么呢?看看下面我的调查结果你 
就明白了。 

android系统中的每个View的子类都具有下面三个和TouchEvent处理密切相关的方法: 
1)public boolean dispatchTouchEvent(MotionEvent ev) 这个方法用来分发TouchEvent 
2)public boolean onInterceptTouchEvent(MotionEvent ev) 这个方法用来拦截TouchEvent 
3)public boolean onTouchEvent(MotionEvent ev) 这个方法用来处理TouchEvent 
当TouchEvent发生时,首先Activity将TouchEvent传递给最顶层的View, 
TouchEvent最先到达最顶层 view 的 dispatchTouchEvent ,然后由 dispatchTouchEvent 方法进行分发, 
如果dispatchTouchEvent返回true ,则交给这个view的onTouchEvent处理, 
如果dispatchTouchEvent返回 false ,则交给这个 view 的 interceptTouchEvent 方法来决定是否要拦截这个事件, 
如果 interceptTouchEvent 返回 true ,也就是拦截掉了,则交给它的 onTouchEvent 来处理, 
如果 interceptTouchEvent 返回 false ,那么就传递给子 view ,由子 view 的 dispatchTouchEvent 再来开始这个事件的分发。 
如果事件传递到某一层的子 view 的 onTouchEvent 上了,这个方法返回了 false ,那么这个事件会从这个 view 往上传递,都是 onTouchEvent 来接收。 



而如果传递到最上面的 onTouchEvent 也返回 false 的话,这个事件就会“消失”,而且接收不到下一次事件。 

先看一下ViewGroup的dispatchTouchEvent的关键源码:

public boolean dispatchTouchEvent(MotionEvent ev) {
	...
        if (action == MotionEvent.ACTION_DOWN) {
	...
       	    if (disallowIntercept || !onInterceptTouchEvent(ev)) {
                final View[] children = mChildren;
                final int count = mChildrenCount;
                for (int i = count - 1; i >= 0; i--) {
                    final View child = children[i];
                    if ((child.mViewFlags & VISIBILITY_MASK) == VISIBLE
                            || child.getAnimation() != null) {
                       ...
                            if (child.dispatchTouchEvent(ev))  {
                                // Event handled, we have a target now.
                                mMotionTarget = child;
                                return true;
                            }
                    }
                }
            }
        }
	...
        final View target = mMotionTarget;
        if (target == null) {
		...
            return super.dispatchTouchEvent(ev);
        }
        if (!disallowIntercept && onInterceptTouchEvent(ev)) {
            ...
            if (!target.dispatchTouchEvent(ev)) {
                // target didn't handle ACTION_CANCEL. not much we can do
                // but they should have.
            }
            // clear the target
            mMotionTarget = null;
            // Don't dispatch this event to our own view, because we already
            // saw it when intercepting; we just want to give the following
            // event to the normal onTouchEvent().
            return true;
        }
	...
        return target.dispatchTouchEvent(ev);
    }

根据以上代码可知,如果onInterceptTouchEvent方法返回true,会直接调用当前ViewGroup的onTouch方法,否则则会依次调用其内包含的子控件的dispatchTouchEvent方法。


0_1302589875305B.gif
总结一下,如果这一次事件没有人消耗掉,则系统不会给你下一次事件,因为他会认为你这次的事件阻塞了,没必要给下一次。onTouchEvent如果不消耗的话,会从子view传递到父view。


一个例子:

原文作者: king.chen

原文地址: http://my.eoe.cn/521690/archive/4285.html

需求:要做一个完全通过flip手势来切换的界面。在最上层用一个ViewFlipper作为容器,并检测flip手势操作。

难题:ViewFlipper的flip手势检测需要的MotionEvent会被各种子View的触摸检测给拦截了。比如界面上有一个Button,则当手指按下Button(还没有抬起)然后flip出Button,则最上层的flip手势检测无效。

原因:android对Touch Event的分发逻辑是View从上层分发到下层(dispatchTouchEvent函数),然后下层优先开始处理Event(先mOnTouchListener,再onTouchEvent)并向上返回处理情况(boolean值),若返回true,则上层不再处理。

于是难题出现了,你若把Touch Event都想办法给传到上层了(只能通过返回false来传到上层),那么下层的各种子View就不能处理后续事件了。
解决方案:
开始仅着眼于Touch Event处理完后的回传过程,想了N久不得,毕竟我想实现的是一个需要打破android事件处理逻辑的效果(就是一个连续性操作,只有不满足上层要求时,才轮到下层处理)。然后突然想到事件的分发过程,便豁然开朗:
覆写最上层的View的dispatchTouchEvent函数,代码如下:

1
2
3
4
5
6
7
  @Override
  public boolean dispatchTouchEvent(MotionEvent event) {
         if (_flipDetector.onTouchEvent(event)) {
                 event.setAction(MotionEvent.ACTION_CANCEL);
         }
         return super.dispatchTouchEvent(event);
  }

于是效果实现。也就是在分发之前便进行手势检测处理,若检测成功,则取消下层的一切处理过程。

总结一下就是:onInterceptTouchEvent可以接受到所有的Touch事件,而onTouchEvent则不一定。

声明:eoe文章著作权属于作者,受法律保护,转载时请务必以超链接形式附带如下信息

原文作者: king.chen

原文地址: http://my.eoe.cn/521690/archive/4285.html


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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值