这里主要探讨Activity的onTouchEvent()、View的onTouch()、onTouchEvent()、onClick()之间的区别
测试代码如下:
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_view_touch);
btnTest = findViewById(R.id.btn_test);
btnTest.setOnTouchListener(new View.OnTouchListener() {
@Override
public boolean onTouch(View v, MotionEvent event) {
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
Log.e(TAG, "onTouch: ACTION_DOWN" );
break;
case MotionEvent.ACTION_MOVE:
Log.e(TAG, "onTouch: ACTION_MOVE" );
break;
case MotionEvent.ACTION_UP:
Log.e(TAG, "onTouch: ACTION_UP" );
break;
}
return false;
}
});
btnTest.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Log.e(TAG, "onClick: ");
Toast.makeText(ViewTouchActivity.this, "click!", Toast.LENGTH_SHORT).show();
}
});
}
@Override
public boolean onTouchEvent(MotionEvent event) {
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
Log.e(TAG, "onTouchEvent: ACTION_DOWN" );
break;
case MotionEvent.ACTION_MOVE:
Log.e(TAG, "onTouchEvent: ACTION_MOVE" );
break;
case MotionEvent.ACTION_UP:
Log.e(TAG, "onTouchEvent: ACTION_UP" );
break;
}
// 返回值为true,false貌似都没有多大影响
return super.onTouchEvent(event);
}
其中的Button为自定义的button,代码如下:
public MyButton(Context context) {
super(context);
}
public MyButton(Context context, AttributeSet attrs) {
super(context, attrs);
}
public MyButton(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
@Override
public boolean onTouchEvent(MotionEvent event) {
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
Log.e(TAG, "onTouchEvent: ACTION_DOWN");
break;
case MotionEvent.ACTION_MOVE:
Log.e(TAG, "onTouchEvent: ACTION_MOVE");
break;
case MotionEvent.ACTION_UP:
Log.e(TAG, "onTouchEvent: ACTION_UP");
break;
}
return super.onTouchEvent(event);
}
主要看View的onTouchListener、onTouchEvent、onClick方法,activity的onTouchEvent方法
一、 activity的onTouchEvent方法
直接看源码:
/**
* Called when a touch screen event was not handled by any of the views
* under it. This is most useful to process touch events that happen
* outside of your window bounds, where there is no view to receive it.
*
* @param event The touch screen event being processed.
*
* @return Return true if you have consumed the event, false if you haven't.
* The default implementation always returns false.
*/
public boolean onTouchEvent(MotionEvent event) {
if (mWindow.shouldCloseOnTouch(this, event)) {
finish();
return true;
}
return false;
}
翻译:如果屏幕的触摸事件没有被他下边的view所处理,那么它将调用。通常用来处理发生在view触摸边界外边的触摸事件。 简单来说就是只要触摸屏幕,如果触摸的边界在view的触摸边界内,如果view处理了这个事件,那么该方法将不发生调用。如果view没有处理该事件,将由该方法处理;如果触摸的边界在view的触摸边界外(没有任何view来处理这个事件),将发生调用。
二、 view的setOnTouchListener方法
源码如下:
/**
* Interface definition for a callback to be invoked when a touch event is
* dispatched to this view. The callback will be invoked before the touch
* event is given to the view.
*/
public interface OnTouchListener {
/**
* Called when a touch event is dispatched to a view. This allows listeners to
* get a chance to respond before the target view.
*
* @param v The view the touch event has been dispatched to.
* @param event The MotionEvent object containing full information about
* the event.
* @return True if the listener has consumed the event, false otherwise.
*/
boolean onTouch(View v, MotionEvent event);
}
翻译:当触摸事件分发给该view时发生调用。回调将在触摸事件给该目标view之前调用。
返回值true表示消费了事件,false相反。
三、 view的onTouchEvent方法
源码如下:
/**
* Implement this method to handle touch screen motion events.
* <p>
* If this method is used to detect click actions, it is recommended that
* the actions be performed by implementing and calling
* {@link #performClick()}. This will ensure consistent system behavior,
* including:
* <ul>
* <li>obeying click sound preferences
* <li>dispatching OnClickListener calls
* <li>handling {@link AccessibilityNodeInfo#ACTION_CLICK ACTION_CLICK} when
* accessibility features are enabled
* </ul>
*
* @param event The motion event.
* @return True if the event was handled, false otherwise.
*/
public boolean onTouchEvent(MotionEvent event) {
...
switch (action) {
case MotionEvent.ACTION_UP:
...
performClick();
...
break;
...
}
翻译:实现这个方法从而处理屏幕的触摸移动事件。如果事件被处理,返回结果为true;否则返回false。如果你想用这个方法监测点击事件,建议你去实现performClick方法,这将保证连贯的系统行为。
从源码也可以看到,在ACTION_UP事件中调用了performClick(),实际就是执行了onClick方法。
测试场景
onTouch返回值为false,其他为默认值,ACTION_MOVE个数不确定 * 10-31 15:11:08.104 20389-20389/com.rain.testeverything E/ViewTouchActivity: onTouch: ACTION_DOWN * 10-31 15:11:08.104 20389-20389/com.rain.testeverything E/MyButton: onTouchEvent: ACTION_DOWN * 10-31 15:11:08.153 20389-20389/com.rain.testeverything E/ViewTouchActivity: onTouch: ACTION_UP * 10-31 15:11:08.153 20389-20389/com.rain.testeverything E/MyButton: onTouchEvent: ACTION_UP
onTouch返回值为true,同时设置的有点击事件,ACTION_MOVE个数不确定 * 10-31 15:05:26.027 15275-15275/com.rain.testeverything E/ViewTouchActivity: onTouch: ACTION_DOWN * 10-31 15:05:26.081 15275-15275/com.rain.testeverything E/ViewTouchActivity: onTouch: ACTION_UP
onTouch返回值为false,View的onTouchEvent返回false,同时设置的有点击事件,ACTION_MOVE个数不确定 * 10-31 15:24:32.156 26667-26667/com.rain.testeverything E/ViewTouchActivity: onTouch: ACTION_DOWN * 10-31 15:24:32.156 26667-26667/com.rain.testeverything E/MyButton: onTouchEvent: ACTION_DOWN * 10-31 15:24:32.156 26667-26667/com.rain.testeverything E/ViewTouchActivity: onTouchEvent: ACTION_DOWN * 10-31 15:24:32.198 26667-26667/com.rain.testeverything E/ViewTouchActivity: onTouchEvent: ACTION_MOVE * 10-31 15:24:32.209 26667-26667/com.rain.testeverything E/ViewTouchActivity: onTouchEvent: ACTION_UP
结论
1. onTouch方法如果返回true,onTouchEvent方法将接收不到事件,onClick方法也不会调用;
2. onTouch方法如果返回false,onTouchEvent方法也返回false,即最终view不处理事件,那么将由activity的onTouchEvent
方法进行事件的处理;
3. activity的onTouchEvent方法,只有在任何的view都不处理事件的时候才发生调用。