事件分发源码分析
2018-02-25 17:16
211 查看
View的TouchEvent事件分发源码
View 与 Touch 相关的有两个非常重要的方法dispatchTouchEvent 事件分发
//默认是false boolean result = false; // ListenerInfo li = mListenerInfo; ListenerInfo li = mListenerInfo; //如果是enabled而且触摸事件返回为true,则返回true if (li != null && li.mOnTouchListener != null && (mViewFlags & ENABLED_MASK) == ENABLED && li.mOnTouchListener.onTouch(this, event)) { result = true; } //如果result为false则执行onTouchEvent方法,若执行的onTouchEvent为true,则result为true if (!result && onTouchEvent(event)) { result = true; }
点击事件——>在View的onTouchEvent -> case MotionEvent.ACTION_UP: 里面调用了 performClick()——>li.mOnClickListener.onClick(this); 点击事件
onTouchEvent方法(一般都会被我们复写)
测试
首先自定义view
public class TouchView extends View { public TouchView(Context context) { super(context); } public TouchView(Context context, @Nullable AttributeSet attrs) { super(context, attrs); } public TouchView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); } @Override public boolean onTouchEvent(MotionEvent event) { Log.e("TAG", "onTouchEvent--->" + event.getAction()); return super.onTouchEvent(event); } @Override public boolean dispatchTouchEvent(MotionEvent event) { Log.e("TAG", "dispatchTouchEvent--->" + event.getAction()); return super.dispatchTouchEvent(event); } }
使用自定义view
View view = findViewById(R.id.touch_view); view.setOnTouchListener(new View.OnTouchListener() { @Override public boolean onTouch(View v, MotionEvent event) { Log.e("TAG","onTouch-->"+event.getAction()); return false; } }); view.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { Log.e("TAG","onClick"); } });
分析(0代表down,1代表up,2代表move)
第一种场景:OnTouchListener onTouchEvent dispatchTouchEfc4e
vent OnClickListener 四个都有的情况下 前提是OnTouchListener 返回false
结果:
dispatchTouchEvent—>0
onTouch–>0
onTouchEvent—>0
dispatchTouchEvent—>2
onTouch–>2
onTouchEvent—>2
dispatchTouchEvent—>1
onTouch–>1
onTouchEvent—>1
onClick
第二种场景:OnTouchListener onTouchEvent dispatchTouchEvent OnClickListener 四个都有的情况下 前提是OnTouchListener 返回true,其他不动
View view = findViewById(R.id.touch_view); view.setOnTouchListener(new View.OnTouchListener() { @Override public boolean onTouch(View v, MotionEvent event) { Log.e("TAG","onTouch-->"+event.getAction()); return true; } });
此时li.mOnTouchListener.onTouch(this, event)) 方法返回true则不会执行onTouchEvent方法
结果
dispatchTouchEvent—>0
onTouch–>0
dispatchTouchEvent—>2
onTouch–>2
dispatchTouchEvent—>1
onTouch–>1
第三种场景:onTouchEvent dispatchTouchEvent OnClickListener 三个的情况下 设置OnTouchEvent为true
OnTouchEvent默认点击了返回的是true
结果
dispatchTouchEvent—>0
onTouchEvent—>0
dispatchTouchEvent—>2
onTouchEvent—>2
dispatchTouchEvent—>2
dispatchTouchEvent—>1
onTouchEvent—>1
return super.onTouchEvent(event)和return true是有区别的,当设置为true时不会有onClick方法,而默认值会
原因:当设置为true时不会进入view中的onTouchEvent方法
第四种场景:OnTouchListener onTouchEvent dispatchTouchEvent OnClickListener 四个的情况下 设置dispatchTouchEvent 为true,其他的返回原样
@Override public boolean dispatchTouchEvent(MotionEvent event) { Log.e("TAG", "dispatchTouchEvent--->" + event.getAction()); return true; }
结果
dispatchTouchEvent—>0
dispatchTouchEvent—>2
dispatchTouchEvent—>1
view的dispatch的方法不会被执行
ViewGroup 的事件分发 源码分析
首先准备工作将原本activity_main布局中的LinearLayout换成自定义View的TouchViewGroup
public class TouchViewGroup extends LinearLayout { public TouchViewGroup(Context context) { super(context); } public TouchViewGroup(Context context, @Nullable AttributeSet attrs) { super(context, attrs); } public TouchViewGroup(Context context, @Nullable AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); } //事件分发 @Override public boolean dispatchTouchEvent(MotionEvent event) { Log.e("TAG", "ViewGroup dispatchTouchEvent--->" + event.getAction());//这是自己的处理事件 return super.dispatchTouchEvent(event); } //事件拦截 @Override public boolean onInterceptTouchEvent(MotionEvent ev) { Log.e("TAG", "ViewGroup onInterceptTouchEvent--->" + ev.getAction());//这是自己的处理事件 return super.onInterceptTouchEvent(ev); } //事件触摸 @Override public boolean onTouchEvent(MotionEvent event) { Log.e("TAG", "ViewGroup onTouchEvent--->" + event.getAction());//这是自己的处理事件 return super.onTouchEvent(event); } }
并修改其中的view打印事件
View view = findViewById(R.id.touch_view); view.setOnTouchListener(new View.OnTouchListener() { @Override public boolean onTouch(View v, MotionEvent event) { Log.e("TAG", "View onTouch-->" + event.getAction()); return false; } }); view.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { Log.e("TAG", "onClick"); } }); public class TouchView extends View { public TouchView(Context context) { super(context); } public TouchView(Context context, @Nullable AttributeSet attrs) { super(context, attrs); } public TouchView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); } @Override public boolean onTouchEvent(MotionEvent event) { Log.e("TAG", "View onTouchEvent--->" + event.getAction());//这是自己的处理事件 return super.onTouchEvent(event);//默认返回true //而点击事件是系统的UP中的事件,所以你返回true的时候并没有进入系统中的 //return true; } @Override public boolean dispatchTouchEvent(MotionEvent event) { Log.e("TAG", "View dispatchTouchEvent--->" + event.getAction()); return super.dispatchTouchEvent(event); } }
dispatchTouchEvent() 源码看看
boolean handled = false; // Handle an initial down. if (actionMasked == MotionEvent.ACTION_DOWN) { // 清除TouchTargets 只要知道 mFirstTouchTarget = null cancelAndClearTouchTargets(ev); resetTouchState(); } final boolean intercepted; if (actionMasked == MotionEvent.ACTION_DOWN || mFirstTouchTarget != null) { final boolean disallowIntercept = (mGroupFlags & FLAG_DISALLOW_INTERCEPT) != 0; if (!disallowIntercept) {//disallowIntercept==false intercepted = onInterceptTouchEvent(ev);//默认返回false 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; } TouchTarget newTouchTarget = null; if (!canceled && !intercepted) { if (newTouchTarget == null && childrenCount != 0) {//ACTION_DOWN for (int i = childrenCount - 1; i >= 0; i--) {// 反序的for循环 获取子View child newTouchTarget = getTouchTarget(child); if (dispatchTransformedTouchEvent(ev, false, child, idBitsToAssign)) { // 如果子 View 返回true 就会进来 主要给 mFirstTouchTarget = target; 赋值 addTouchTarget(child, idBitsToAssign); } } } }
/** * Clears all touch targets. * mFirstTouchTarget = null; 这句话核心清除 mFirstTouchTarget */ private void clearTouchTargets() { TouchTarget target = mFirstTouchTarget; if (target != null) { do { TouchTarget next = target.next; target.recycle(); target = next; } while (target != null); mFirstTouchTarget = null; } }
private boolean dispatchTransformedTouchEvent(MotionEvent event, boolean cancel, View child, int desiredPointerIdBits) { final boolean handled; // Canceling motions is a special case. We don't need to perform any transformations // or filtering. The important part is the action, not the contents. final int oldAction = event.getAction(); if (cancel || oldAction == MotionEvent.ACTION_CANCEL) { event.setAction(MotionEvent.ACTION_CANCEL); if (child == null) { // child == null 会调用 自己的 super View.dispatchTouchEvent(event) handled = super.dispatchTouchEvent(event); } else { // child == null 会调用 自己的 super View.dispatchTouchEvent(event) handled = child.dispatchTouchEvent(event); } event.setAction(oldAction); return handled; } }
onInterceptTouchEvent() 源码看看
onTouchEvent() 源码看看
场景分析
第一种常见,View和ViewGroup的TouchEvent全部设置为默认结果:
ViewGroup dispatchTouchEvent—>0
ViewGroup onInterceptTouchEvent—>0
View dispatchTouchEvent—>0
View onTouch–>0
View onTouchEvent—>0
ViewGroup dispatchTouchEvent—>2
ViewGroup onInterceptTouchEvent—>2
View dispatchTouchEvent—>2
View onTouch–>2
View onTouchEvent—>2
ViewGroup dispatchTouchEvent—>1
ViewGroup onInterceptTouchEvent—>1
View dispatchTouchEvent—>1
View onTouch–>1
View onTouchEvent—>1
即正常情况下:
第一次DOWN
ViewGroup.dispatchTouchEvent ->ViewGroup.onInterceptTouchEvent -> View.dispatchTouchEvent ->View.onTouch -> View.onTouchEvent
第二次MOVE
ViewGroup.dispatchTouchEvent -> ViewGroup onInterceptTouchEvent -> View.dispatchTouchEvent -> View.onTouch ->View.onTouchEvent
第三次UP
ViewGroup.dispatchTouchEvent -> ViewGroup onInterceptTouchEvent -> View.onTouch -> View.onTouchEvent -> View.onclick
第二种情况:onClick 没有 理解为没有消费事件,即没有进入onClick方法不返回true
ViewGroup.dispatchTouchEvent -> ViewGroup.onInterceptTouchEvent -> View.dispatchTouchEvent -> View.onTouch -> View onTouchEvent -> ViewGroup.onTouchEvent
第三种情况:在 View 的 onTouchEvent() 方法里面返回true 的情况下
第一次DOWN ViewGroup.dispatchTouchEvent -> ViewGroup.onInterceptTouchEvent -> View.dispatchTouchEvent -> View.onTouch -> View.onTouchEvent
第二次MOVE ViewGroup.dispatchTouchEvent -> ViewGroup.onInterceptTouchEvent -> View.dispatchTouchEvent -> View.onTouch -> View.onTouchEvent
第三次UP ViewGroup.dispatchTouchEvent -> ViewGroup.onInterceptTouchEvent -> View.onTouch -> View.onTouchEvent
第四种情况:在 ViewGroup 的 onInterceptTouchEvent() 方法里面返回 true 的情况下
ViewGroup.dispatchTouchEvent -> ViewGroup.onInterceptTouchEvent -> ViewGroup.onTouchEvent
总结
1.如果说子 View 没有一个地方返回 true ,只会进来一次只会响应 DOWN 事件,代表不需要消费该事件,如果你想响应 MOVE,UP 必须找个地方ture2.对于ViewGroup来讲,如果你想拦截子 View 的 Touch 事件,可以覆写 onInterceptTouchEvent 返回 true 即可 , 如果说 onInterceptTouchEvent 返回的是 true 会执行该 ViewGroup 的 onTouchEvent 方法 , 如果子 View 没有消费 touch 事件也会调用该 ViewGroup 的 onTouchEvent 方法
相关文章推荐
- Android事件分发机制源码分析
- [置顶] Android事件分发机制源码分析
- Android—— View事件分发机制的源码分析
- 事件分发源码分析(二)
- Android事件分发机制源码分析上----View事件分发分析
- 源码分析android的事件分发机制
- 单击事件分发机制-源码分析
- Android事件分发机制源码分析
- View的事件分发机制源码分析
- Android下的事件分发机制(结合源码分析)
- android 事件分发机制(源码分析)—(详细)(逐步总结)(值得一看)
- 深入理解Android事件分发机制之源码分析
- View的事件分发机制(源码分析)
- Android 事件分发机制(最新源码6.0分析)--childView
- Android查缺补漏(View篇)--事件分发机制源码分析
- Android VSync事件分发过程源码分析
- [置顶] 带你从源码角度分析ViewGroup中事件分发流程
- view事件分发源码学习和分析
- (十八)事件分发-源码分析
- Netty5源码分析(四) -- 事件分发模型