我有一个自定义视图,我有触摸事件的功能(滑动等).现在可能会发生这种自定义视图在a中使用ScrollableLayout.问题是,当用户在我的自定义视图中滑动时,父(ScrollableLayout)也将处理滑动手势,因此它会滚动,但它不应该滚动.
我需要像event.preventDefaults()JavaScript 这样的东西.
我View#onTouchEvent总是覆盖并返回true.我想,当我从onTouchEvent这里返回true 意味着事件被消耗而没有其他视图会获得onTouchEvent,但这是错误的.
有谁能够帮我?
我的视图很容易测试它:
public class PreventingTouchEventView extends View {
public PreventingTouchEventView(Context context, AttributeSet attrs) {
super(context, attrs);
}
@Override
protected void onDraw(Canvas canvas) {
canvas.drawColor(Color.RED);
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
setMeasuredDimension(200, 200);
}
@Override
public boolean onTouchEvent(MotionEvent event) {
return true;
}
}
Run Code Online (Sandbox Code Playgroud)
我将一个示例android项目推送到github:https: //github.com/jjoe64/android-preventing-touch-test
如果触摸,滚动红帆布里面,ScrollableLayout应该不会滚动.
Des*_*ert 11
要防止来自该布局的触摸,您有以下几种选择:
1)设置OnTouchListener,它总是返回true.
2)覆盖dispatchTouchEvent(MotionEvent事件)以始终返回true
UPD: Okey,通常你必须设置OnTouchListener,它总是返回true,正如我之前所说的那样,以防止调用其他视图onTouch,但是使用ScrollView它完全是另一个故事.
首先,我将告诉你如何dispatchTouchEvent运作.它开始从根视图调度事件到它的子视图,这意味着dispatchTouchEvent父视图的名称是BEFORE 的子视图dispatchTouchEvent.
然后在ViewGroup.dispatchTouchEvent()那里有一段代码
final boolean disallowIntercept = (mGroupFlags & FLAG_DISALLOW_INTERCEPT) != 0;
if (!disallowIntercept) {
intercepted = onInterceptTouchEvent(ev);
ev.setAction(action); // restore action in case it was changed
} else {
intercepted = false;
}
Run Code Online (Sandbox Code Playgroud)
它决定是否应截取此触摸事件,这意味着如果interceptedflag为true,则此视图将截取所有后续事件.并ScrollView onInterceptTouchEvent实现拦截动作,如果他们正在进行垂直滚动.
所以我的第一个想法是设置FLAG_DISALLOW_INTERCEPT为自定义视图的父级以禁止这种拦截事件的机会,但是这个想法因为下一行代码而失败ViewGroup:
if (actionMasked == MotionEvent.ACTION_DOWN) {
// Throw away all previous state when starting a new touch gesture.
// The framework may have dropped the up or cancel event for the previous gesture
// due to an app switch, ANR, or some other state change.
cancelAndClearTouchTargets(ev);
resetTouchState();
}
Run Code Online (Sandbox Code Playgroud)
这意味着在MotionEvent.ACTION_DOWN清除所有状态之后(FLAG_DISALLOW_INTERCEPT同样也清除了).
所以最终的解决方案非常简单
public class PreventingTouchEventView extends View {
public PreventingTouchEventView(Context context, AttributeSet attrs) {
super(context, attrs);
}
@Override
protected void onDraw(Canvas canvas) {
canvas.drawColor(Color.RED);
}
@Override
public boolean dispatchTouchEvent(MotionEvent event) {
if (getParent() != null && event.getAction() == MotionEvent.ACTION_DOWN) {
getParent().requestDisallowInterceptTouchEvent(true);
}
return super.dispatchTouchEvent(event);
}
}
Run Code Online (Sandbox Code Playgroud)
这将FLAG_DISALLOW_INTERCEPT在第一次之后立即提高MotionEvent.ACTION_DOWN,这将不允许父母进一步拦截未来的行动.
但是请注意,如果你的父视图做了一些疯狂的事情MotionEvent.ACTION_DOWN并且拦截了这个事件,那么你就无法做任何事情,因为你的父母dispatchTouchEvent在你之前被调用了dispatchTouchEvent.
| 归档时间: |
|
| 查看次数: |
2836 次 |
| 最近记录: |