事件处理

Q:如何捕获activity中的所有点击事件?

  • 事件分发方案。通过重写Activity的dispatchTouchEvent方法,对页面上的点击事件进行拦截。但是拦截不到Dialog中的点击事件,因为事件分发由DecorView开始发起,但是Dialog所处的DecorView和Activity的DecorView不是同一个,所以无法在Activitiy的dispatchTouchEvent方法进行拦截Dialog中的点击事件。
  • hook替换OnClickListener方案。这个方案主要是通过替换View中的mOnClickListener为我们自己的OnClickListener,然后进行点击事件的拦截处理。但是这个方案需要获取替换的那个View才行,所以新增的View和Dialog都需要单独处理才行。新增的View需要进行当前页面的View树进行监听,Dialog必须对Dialog中的View再进行一次hook。
  • AspectJ切面编程方案。这个方案是在编译期将代码插入到目标方法中,所以只要找到切点——也就是View中的onClick方法即可。可以完美解决我们的问题,并且不需要用户另外操作。
  • 无障碍服务方案。这个方案是通过Android中的无障碍服务,对APP中的所有点击事件进行拦截,对应的事件就是AccessibilityEvent.TYPE_VIEW_CLICKED。该方案也能完美解决我们的问题,但是有个很大的缺点,就是需要用户单独去设置页面开启该辅助服务才行。

Q:说说view中的事件分发?

ACTION_DOWN情况下:dispatchTouchEvent->onIntercepterTouchEvenet->onTouchEvent

Q:如果我只想有view的拖拽事件,而不想要view的点击事件,让你重写这个view的拖拽怎么设计?

onTouchEvent中return true

Q:里面的view在onTouchEvent中消费,然后拖动手指,直到手指从其他他viewgroup上挪开手指

一旦事件点击序列传到了view中,这个序列中的所有操作都交给这个view去处理

Q:view的onTouch和onTouchEvent事件的区别?

onTouch指setOnTouchListener的回调方法,它是优先于onTouchEvent事件的,如果onTouch方法返回true,是不会触发onTouchEvent事件的

Q:view的onClick事件在什么时候触发的,和onTouch有什么区别?

在onTouchEvent中的ACTION_UP中触发的,onTouch是在dispatchTouchEvent中触发的

Q:事件是先到window的还是先到decorview的,为什么这样设计?

image 这样设计是为了解耦,Activity只持有phonewindow,ViewRootImpl只持有decorview,phonewindow可以把事件分发到decorview

Q:一个点击事件是如何从屏幕传递到view的?

image

Q:MotionEvent是什么?有什么用?

一个MotionEvent对象内部使用一个数组来维护所有触控点的信息 UP/DOWN类型的事件包含了触控点索引,可以根据该索引做出对应的操作 触控点的索引是变化的,不能作为跟踪的依据,而必须依据触控点id

  • ACTION_DOWN: 表示手指按下屏幕
  • ACTION_MOVE: 手指在屏幕上滑动时,会产生一系列的MOVE事件
  • ACTION_UP: 手指抬起,离开屏幕、
  • ACTION_CANCEL:当出现异常情况事件序列被中断,会产生该类型事件
  • ACTION_POINTER_DOWN: 当已经有一个手指按下的情况下,另一个手指按下会产生该事件
  • ACTION_POINTER_UP: 多个手指同时按下的情况下,抬起其中一个手指会产生该事件

Q:ACTION_CANCEL是如何触发的?

ViewGroup在onInterceptTouchEvent中对ACTION_MOVE或者ACTION_UP进行了拦截,子View的dispatchTouchEvent和onTouchEvent就接收到的是ACTION_CACEL

Q:几个监听Lisner动作回调的优先级是如何?

if (mOnTouchListener!=null && mTouchListener.onTouch(event)){
    return true;
}else{
    if (单击事件){
        mOnClickListener.onClick(view);
    }else if(长按事件){
        mOnLongClickListener.onLongClick(view);
    }
}

Q:滑动冲突如何解决?

  • 外部拦截法中,重点在于是否拦截事件,那么重心就放在了 onInterceptTouchEvent 方法中
  • 内部拦截法中,首先是设置外部viewGroup拦截除了down事件以外的所有事件,接下来需要重写内部view的dispatchTouchEvent方法

Q:Activity的分发方法中调用了onUserInteraction()方法,你能说说这个方法有什么作用吗?

这个方法在Activity接收到down的时候会被调用,本身是个空方法,需要开发者自己去重写

Q:ViewGroup是如何将多个手指产生的事件准确分发给不同的子view的?

  • 每个MotionEvent中都包含了当前屏幕所有触控点的信息,他的内部用了一个数组来存储不同的触控id所对应的坐标数值。
  • 当一个子view消费了down事件之后,ViewGroup会为该view创建一个TouchTarget,这个TouchTarget就包含了该view的实例与触控id。这里的触控id可以是多个,也就是一个view可接受多个触控点的事件序列。
  • 当一个MotionEvent到来之时,ViewGroup会将其中的触控点信息拆开,再分别发送给感兴趣的子view。从而达到精准发送触控点信息的目的。

Q:dispatchTouchEvent\onInterceptTouchEvent\onTouchEvent中各返回值处理

image