View触摸事件相关分析

本文详细分析了Android中的触摸事件类型,事件序列,以及从Activity到View的事件分发流程。探讨了ViewGroup如何处理事件,以及View的响应逻辑。同时介绍了多点触摸的不同场景和系统提供的事件工具类,如GestureDetector、VelocityTracker和ScaleGestureDetector等。
摘要由CSDN通过智能技术生成

事件的类型,主要有六种:

  • MotionEvent.ACTION_DOWN:第一个手指刚接触屏幕
  • MotionEvent.ACTION_POINTER_DOWN:多点触摸第二个手指接触屏幕
  • MotionEvent.ACTION_MOVE:手指在屏幕上滑动,如果是多点触摸则无法明确区分具体是哪一个手指在滑动
  • MotionEvent.ACTION_POINTER_UP:多点触摸有某个手指离开屏幕,但不是最后一个手指
  • MotionEvent.ACTION_UP:最后一个手指离开屏幕
  • MotionEvent.CANCEL:非人为因素取消

事件序列

正常情况下,事件序列会由一个DOWN开始、一个UP结尾和0-n个中间事件,比如MOVE、POINTER_DOWN、POINTER_UP组成。

事件分发

事件分发是从Activity --> ViewGroup --> View。

Activity基本不做事,但是可以增加事件序列最开头的响应,和无人消费事件的最末尾响应。

ViewGroup主要职责:

  • 在DOWN事件清空上次操作事件的状态位和重置mFirstTouchTarget即事件响应的View链表集合
  • 在DOWN事件遍历所有子View询问它们是否要消耗事件,如果有就记录到mFirstTouchTarget集合
  • 可以重写onInterceptTouchEvent方法决定是否对事件序列进行拦截,该方法默认是不拦截的
  • 分发所有事件,比如MOVE、UP等
  • 如果有子View响应了事件,即mFirstTouchTarget有记录,那么事件序列的后续事件直接交给mFirstTouchTarget集合进行处理,不用再遍历子View,所以mFirstTouchTarget的设计理念就是性能优化,去掉了DOWN后续事件的遍历操作。
  • 如果没有子View响应事件,那么交由自己的onTouchEvent进行处理,如果自己也不消费事件,那么往上回传,最后可能会传回给Activity;否则,自己消费所有的后续事件序列。

View的职责:

  • 判断当前View是ENABLE或DISENABLE
  • 判断当前View是可点击或不可点击状态,在可点击状态下,View是默认消费事件的。
  • 在DOWN事件设置长按监听,如果超过500毫秒没有UP事件响应,那么长按事件回调。如果这个回调结果代表消费事件,那么不会响应单击事件;否则还可以响应单击事件。
  • 在UP事件响应单击事件。会首先响应listener的onTouch(),该方法结果如果代表消费事件,那么onTouchEvent()不会回调;否则可以继续回调onTouchEvent();再看这个方法的结果决定是否回调View.onClickListener的回调。

具体可以看看下面的源码分析

事件分发–Activity
// Activity 这里是事件分发的入口
public boolean dispatchTouchEvent(MotionEvent ev) {
   
  if (ev.getAction() == MotionEvent.ACTION_DOWN) {
   
    // 可以重写这个方法实现事件最开始的处理,但是不能拦截事件
    onUserInteraction();
  }
  // 交给下层View去处理,注意window就是PhoneWindow,这里最后会进入ViewGroup的方法,即dispatchTouchEvent(),就是下面会分析的步骤
  if (getWindow().superDispatchTouchEvent(ev)) {
   
    return true;
  }
  // 如果所有的View都不处理事件,那么交给Activity自己处理,虽然实现只是简单的丢弃
  return onTouchEvent(ev);
}
事件分发–ViewGroup
// ViewGroup
public boolean dispatchTouchEvent(MotionEvent ev) {
   
  // 记住,事件序列是从DOWN开始
  if (actionMasked == MotionEvent.ACTION_DOWN) {
   
    // 所以,这里需要清空之前的事件序列,包括把mFirstTouchTarget和FLAG_DISALLOW_INTERCEPT重置
    // mFirstTouchTarget是一个链表,代表要响应这次事件序列的View集合
    // FLAG_DISALLOW_INTERCEPT,可以禁止或允许ViewGroup拦截除了DOWN之外的事件,getParent().requestDisallowInterceptTouchEvent()
    cancelAndClearTouchTargets(ev);
    resetTouchState(
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值