android 事件分发笔记

1.事件传递顺序
    Activity -> PhoneWindow  ->DecorView  -> RootView -> ChildView

2.ViewGroup onInterceptTouchEvent 在什么条件下会执行?

 if (actionMasked == MotionEvent.ACTION_DOWN|| mFirstTouchTarget != null) {
       ...//省略代码
     intercepted = onInterceptTouchEvent(ev);ev.setAction(action);
     // restore action in case it was changed
     }
   即MotionEvent.ACTION_DOWN 或者是 mFirstTouchTarget !=null
   down事件 或者 子View处理事件了
   如果此时事件不为down  (move 或者 up), 子view没有处理事件,则不会再去判断是否拦截事件,直接由viewGroup处理

3.事件在ViewGroup分发过程

Down事件 -> Viewgroup 是否拦截
            -> 拦截, mFirstTouchTarget =null  ->ViewGroup处理 (后续事件不再向下传递,皆由ViewGroup处理)
            -> 不拦截 ->向下分发到子View,   判断子View是否满足分发条件  (1.点击事件是否在子View范围,  2.子View没有播放动画)
                  ->找到满足子View  mFirstTouchTarge 赋值  = 子View   ->子view dispatchTouchEvent ,到此,事件分发到子view
                  ->未找到满足子View ViewGroup自己处理 onTouchEvent()
   
4.View对点击事件的处理过程

是否设置OnTouchListener
        ->是    ->    onTouch return
                   -> true    onTouchEvent 不再执行
                   -> false   -> onTouchEvent()
        ->否  -> onTouchEvent()

           在onTouchEvent()中执行onClickListener()
    几个点 : 1.view的Long_clickAble 或者clickable 为true  消耗点击事件
               2.long_clickable默认false
               3. 只要1成立,view为disable状态同样消耗点击事件

5.View滑动冲突处理
    (1)外部拦截法
              重写父布局onInterceptTouchEvent
@Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
    boolean intercepted = false;
    int x = (int) ev.getX();
    int y = (int) ev.getY();
    switch (ev.getAction()){
        case MotionEvent.ACTION_DOWN:
            intercepted = false;
            break;
        case MotionEvent.ACTION_MOVE:
            if (父容器需要当前点击事件){
                intercepted = true;
            }else {
                intercepted = false;
            }
            break;
        case MotionEvent.ACTION_UP:
            intercepted = false;
            break;
    }
    return intercepted;
}
 
 需要注意的几点:1.ACTION_DOWN父容器必须返回false,因为如果拦截down事件,后续事件将不会向下传递
                           2.move事件,需要则拦截,return true 
                           3.up事件 return false

    (2)内部拦截法
          内部拦截稍微复杂点,分别要重写子控件的dispatchTouchEvent以及父控件的onTouchEvent
     
//子控件
@Override
public boolean dispatchTouchEvent(MotionEvent ev) {
    int x = (int) ev.getX();
    int y = (int) ev.getY();
    switch (ev.getAction()){
        case MotionEvent.ACTION_DOWN:
            parent.requestDisallowInterceptTouchEvent(true);
            break;
        case MotionEvent.ACTION_MOVE:
            if (父容器需要当前点击事件) {
                parent.requestDisallowInterceptTouchEvent(false);
            }
            break;
        case MotionEvent.ACTION_UP:
            intercepted = false;
            break;
    }
    return super.dispatchTouchEvent(ev);
}
//父控件
@Override
public boolean onTouchEvent(MotionEvent event) {
    if (event.getAction() == MotionEvent.ACTION_DOWN){
        return false;
    }else {
        return true;
    }
}


内部拦截法是父容器不拦截任何事件,所有事件都传递给子元素,如果子元素需要则消耗掉事件,如果子元素不需要则交给父容器处理

你可能感兴趣的:(android学习)