onTouch:检测 ACTION_UP 而不阻塞其他触摸事件
onTouch: detect ACTION_UP without blocking other touch events
我有一个用作按钮的自定义视图。 canvas 都是我自己画的。现在我在 ACTION_DOWN
时制作大纲,并在 ACTION_UP
或 ACTION_CANCEL
后删除它。
@Override
public boolean onTouch(View v, MotionEvent event) {
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
Log.e("test", "ACTION_DOWN");
break;
case MotionEvent.ACTION_UP:
Log.e("test", "ACTION_UP");
break;
case MotionEvent.ACTION_CANCEL:
Log.e("test", "ACTION_CANCEL");
break;
}
return true;
}
这对我有用,除了现在它阻止了此视图后面的另一个手势,该手势正在检测 ACTION_MOVE
(向左滚动)。
如果我 return 为假,那么它工作正常但现在 ACTION_UP
没有被调用。
如果手指被抬起,我想调用 ACTION_UP
,否则传递事件。
您是否尝试过覆盖 dispatchTouchEvent
?
更新:
所以触摸事件有点像野兽。 运行下面是这个...
- 它们首先从您 Activity 的根容器中冒出来。这是通过调用
dispatchTouchEvent
然后 onInterceptTouchEvent
假设拦截没有被子视图阻止来完成的。
- 如果没有view拦截事件,就会冒泡到调用
onTouch
的叶子节点(比如按钮)。如果节点不处理它 (returns true
) 它的父节点有机会等等。
这意味着您可以使用 dispatchTouchEvent
或 onInterceptTouchEvent
来监视触摸事件而不改变行为。除非你真的要拦截我建议使用 dispatchTouchEvent
的事件,因为它保证 运行 而拦截可能会被阻止(例如:DrawerLayout
将拦截边缘附近的触摸事件,以便打开抽屉)。
所以最后的结果是:
public class MyView extends Button {
@Override
public boolean dispatchTouchEvent(MotionEvent event) {
switch (event.getActionMasked()) {
case MotionEvent.ACTION_DOWN:
Log.e("test", "ACTION_DOWN");
break;
case MotionEvent.ACTION_UP:
Log.e("test", "ACTION_UP");
break;
case MotionEvent.ACTION_CANCEL:
Log.e("test", "ACTION_CANCEL");
break;
}
return super.dispatchTouchEvent(event);
}
}
更新:
抱歉,出于某种原因(主要是我的阅读能力差)我一直以为我们是在和家长打交道。这是我会做的...
继续执行 onTouch
和 return true
以消耗所有事件。这意味着在您的视图上开始的任何触摸事件都将被吃掉。然后我们要做的是将点转换为父坐标 space 并手动向上传递触摸事件,它在您的自定义视图中看起来像这样...
private boolean passingTouchEventToParent = true;
final private Rect hitRect = Rect();
@Override
public boolean onTouch(MotionEvent event) {
// Handle your custom logic here
final ViewParent viewParent = getParent();
if (passingTouchEventToParent &&
viewParent != null &&
viewParent instanceof View) {
// Gets this view's hit rectangle in the parent's space
getHitRect(hitRect);
event.offsetLocation((float) hitRect.left, (float) hitRect.top);
passingTouchEventToParent = viewParent.onTouchEvent(event);
}
if (event.getActionMasked() == MotionEvent.ACTION_UP) {
// Motion event finished, reset passingTouchEventToParent
passingTouchEventToParent = true;
}
return true;
}
我有一个用作按钮的自定义视图。 canvas 都是我自己画的。现在我在 ACTION_DOWN
时制作大纲,并在 ACTION_UP
或 ACTION_CANCEL
后删除它。
@Override
public boolean onTouch(View v, MotionEvent event) {
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
Log.e("test", "ACTION_DOWN");
break;
case MotionEvent.ACTION_UP:
Log.e("test", "ACTION_UP");
break;
case MotionEvent.ACTION_CANCEL:
Log.e("test", "ACTION_CANCEL");
break;
}
return true;
}
这对我有用,除了现在它阻止了此视图后面的另一个手势,该手势正在检测 ACTION_MOVE
(向左滚动)。
如果我 return 为假,那么它工作正常但现在 ACTION_UP
没有被调用。
如果手指被抬起,我想调用 ACTION_UP
,否则传递事件。
您是否尝试过覆盖 dispatchTouchEvent
?
更新:
所以触摸事件有点像野兽。 运行下面是这个...
- 它们首先从您 Activity 的根容器中冒出来。这是通过调用
dispatchTouchEvent
然后onInterceptTouchEvent
假设拦截没有被子视图阻止来完成的。 - 如果没有view拦截事件,就会冒泡到调用
onTouch
的叶子节点(比如按钮)。如果节点不处理它 (returnstrue
) 它的父节点有机会等等。
这意味着您可以使用 dispatchTouchEvent
或 onInterceptTouchEvent
来监视触摸事件而不改变行为。除非你真的要拦截我建议使用 dispatchTouchEvent
的事件,因为它保证 运行 而拦截可能会被阻止(例如:DrawerLayout
将拦截边缘附近的触摸事件,以便打开抽屉)。
所以最后的结果是:
public class MyView extends Button {
@Override
public boolean dispatchTouchEvent(MotionEvent event) {
switch (event.getActionMasked()) {
case MotionEvent.ACTION_DOWN:
Log.e("test", "ACTION_DOWN");
break;
case MotionEvent.ACTION_UP:
Log.e("test", "ACTION_UP");
break;
case MotionEvent.ACTION_CANCEL:
Log.e("test", "ACTION_CANCEL");
break;
}
return super.dispatchTouchEvent(event);
}
}
更新:
抱歉,出于某种原因(主要是我的阅读能力差)我一直以为我们是在和家长打交道。这是我会做的...
继续执行 onTouch
和 return true
以消耗所有事件。这意味着在您的视图上开始的任何触摸事件都将被吃掉。然后我们要做的是将点转换为父坐标 space 并手动向上传递触摸事件,它在您的自定义视图中看起来像这样...
private boolean passingTouchEventToParent = true;
final private Rect hitRect = Rect();
@Override
public boolean onTouch(MotionEvent event) {
// Handle your custom logic here
final ViewParent viewParent = getParent();
if (passingTouchEventToParent &&
viewParent != null &&
viewParent instanceof View) {
// Gets this view's hit rectangle in the parent's space
getHitRect(hitRect);
event.offsetLocation((float) hitRect.left, (float) hitRect.top);
passingTouchEventToParent = viewParent.onTouchEvent(event);
}
if (event.getActionMasked() == MotionEvent.ACTION_UP) {
// Motion event finished, reset passingTouchEventToParent
passingTouchEventToParent = true;
}
return true;
}