案例
TestActivity
public class TestActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_test);
TouchView view = findViewById(R.id.touch_view);
view.setOnTouchListener(new View.OnTouchListener() {
@Override
public boolean onTouch(View v, MotionEvent event) {
Log.e("xxx", "onTouch -> " + event.getAction());
return false; // @1
}
});
view.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Log.e("xxx", "onClick");
}
});
}
}
TouchView
public class TouchView extends View {
// 在代码中创建 TouchView view = new TouchView(this); 实例时会调用
public TouchView(Context context) {
super(context);
}
// 在布局文件中引用(<com.zc.myapp.listener.TouchView />)时会调用
public TouchView(Context context, AttributeSet attrs) {
super(context, attrs);
}
// 在../res/values/styles.xml中定义样式时会调用
public TouchView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
@Override
public boolean onTouchEvent(MotionEvent event) {
Log.e("xxx","onTouchEvent -> " + event.getAction());
return super.onTouchEvent(event); // @2
}
@Override
public boolean dispatchTouchEvent(MotionEvent event) {
super.dispatchTouchEvent(event); // @3
return true; // @4
}
}
测试结论
1、TestActivity中有view.setOnTouchListener()方法,TouchView中覆写onTouchEvent()方法,没有覆写dispatchTouchEvent()方法
1.1 @1处返回false,@2处返回super.onTouchEvent(event),输出结果:OnTouchListener.DOWN -> OnTouch.DOWN -> OnTouchListener.MOVE -> OnTouch.MOVE -> OnTouchListener.UP -> OnTouch.UP -> OnClickListener
1.2 @1处返回false,@2处返回true,输出结果:OnTouchListener.DOWN -> OnTouch.DOWN -> OnTouchListener.MOVE -> OnTouch.MOVE -> OnTouchListener.UP -> OnTouch.UP
1.3 @1处返回false,@2处返回false,输出结果:OnTouchListener.DOWN -> OnTouch.DOWN
1.4 @1处返回true,不管@2处返回super.onTouchEvent(event) / true / false,输出结果:OnTouchListener.DOWN -> OnTouchListener.MOVE -> OnTouchListener.UP
2、TestActivity中没有view.setOnTouchListener()方法,TouchView中覆写onTouchEvent()方法,没有覆写dispatchTouchEvent()方法
2.1 @2处返回super.onTouchEvent(event),输出结果:OnTouch.DOWN -> OnTouch.MOVE -> OnTouch.UP -> OnClickListener
2.2 @2处返回true,输出结果:OnTouch.DOWN -> OnTouch.MOVE -> OnTouch.UP
2.3 @2处返回false,输出结果:OnTouch.DOWN
3、TestActivity中有view.setOnTouchListener()方法,TouchView中覆写onTouchEvent()方法,也覆写dispatchTouchEvent()方法
3.1 没有@3行,不管@4返回true / false,不管@1处返回true / false,不管@2处返回true / false,输出结果:没有任何输出
3.2 有@3行,@4返回true,@1处返回false,@2处返回super.onTouchEvent(event),输出结果:OnTouchListener.DOWN -> OnTouch.DOWN -> OnTouchListener.MOVE -> OnTouch.MOVE -> OnTouchListener.UP -> OnTouch.UP -> OnClickListener
3.3 有@3行,@4返回true,@1处返回false,@2处返回true / false,输出结果:OnTouchListener.DOWN -> OnTouch.DOWN -> OnTouchListener.MOVE -> OnTouch.MOVE -> OnTouchListener.UP -> OnTouch.UP
3.4 有@3行,@4返回false,@1处返回false,@2处返回super.onTouchEvent(event) / true / false,输出结果:OnTouchListener.DOWN -> OnTouch.DOWN
源码分析
View.dispatchTouchEvent(MotionEvent event)方法
public boolean dispatchTouchEvent(MotionEvent event) {
...
boolean result = false;
...
if (onFilterTouchEventForSecurity(event)) {
/*
* ListenerInfo 是View中的静态内部类,存放着View的各种Listener
* protected OnFocusChangeListener mOnFocusChangeListener;
* protected OnScrollChangeListener mOnScrollChangeListener;
* public OnClickListener mOnClickListener;
* protected OnLongClickListener mOnLongClickListener;
* 等等...
*/
ListenerInfo li = mListenerInfo;
if (li != null && li.mOnTouchListener != null && (mViewFlags & ENABLED_MASK) == ENABLED
&& li.mOnTouchListener.onTouch(this, event)) {
result = true;
}
if (!result && onTouchEvent(event)) { // @1
result = true;
}
}
...
return result;
}
@1处的onTouchEvent(MotionEvent event)方法
public boolean onTouchEvent(MotionEvent event) {
final float x = event.getX();
final float y = event.getY();
final int viewFlags = mViewFlags;
final int action = event.getAction();
...
if (clickable || (viewFlags & TOOLTIP) == TOOLTIP) {
switch (action) {
case MotionEvent.ACTION_UP:
...
if (!post(mPerformClick)) {
performClickInternal(); // @2 View的点击事件
}
...
break;
case MotionEvent.ACTION_DOWN:
...
break;
case MotionEvent.ACTION_CANCEL:
...
break;
case MotionEvent.ACTION_MOVE:
...
break;
}
return true;
}
return false;
}
@2处的performClickInternal()方法
private boolean performClickInternal() {
notifyAutofillManagerOnClick();
return performClick(); // @3
}
@3处的performClick()方法 【执行View的点击事件】
/**
* Call this view's OnClickListener, if it is defined. Performs all normal
* actions associated with clicking: reporting accessibility event, playing
* a sound, etc.
* @return True there was an assigned OnClickListener that was called, false
* otherwise is returned.
*/
// NOTE: other methods on View should not call this method directly, but performClickInternal()
// instead, to guarantee that the autofill manager is notified when necessary (as subclasses
// could extend this method without calling super.performClick()).
public boolean performClick() {
notifyAutofillManagerOnClick();
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;
}