源码阅读分析 - View的Touch事件分发
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 dispatchTouchEvent 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的dispatchTouchEvent的方法不会被执行
View的TouchEvent源码分析
public boolean dispatchTouchEvent(MotionEvent event) {
boolean result = false;
//存放所有的事件,如OnClickListener OnLongClickListener
ListenerInfo li = mListenerInfo;
//我们设置了点击事件所以li != null 为true
// (mViewFlags & ENABLED_MASK) == ENABLED设置的是判断是否可用
// li.mOnTouchListener.onTouch(this, event)我们这里设置的是false
if (li != null && li.mOnTouchListener != null
&& (mViewFlags & ENABLED_MASK) == ENABLED
&& li.mOnTouchListener.onTouch(this, event)) {//若为false则为false,反之为true
result = true;
}
//当result为false的时候,才会调用系统的onTouchEvent
if (!result && onTouchEvent(event)) {
result = true;
}
}
onTouchEvent其中最主要的内容是case MotionEvent.ACTION_UP中的 performClick();
public boolean performClick() {
final boolean result;
final ListenerInfo li = mListenerInfo;
if (li != null && li.mOnClickListener != null) {
playSoundEffect(SoundEffectConstants.CLICK);
//点击事件
li.mOnClickListener.onClick(this);
result = true;
} else {
result = false;
}
sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_CLICKED);
notifyEnterOrExitForAutoFillIfNeeded(true);
return result;
}
总结,点击事件是在up之后调用的方法