我有一个简单的应用程序,有两个 View ,一个是 TableView,另一个是 ListView。我使用 GestureDetector 来检测屏幕上的滑动,其操作方式类似于 here 。如果 ListView 仅填充了几个项目,则一切正常,但是当 ListView 填满整个屏幕时,手势检测将停止工作。在屏幕上滑动只会突出显示列表项之一。
我认为发生这种情况是因为 ListView 以某种方式从 GestureListener 窃取了触摸事件。有没有办法防止这种情况发生?
最佳答案
我发现,如果您遍历相当准确的水平路径,GestureDetector 在 ListItems 中工作得很好。但是,如果您稍微偏离,列表就会滚动并且手势不会完成。事情的经过如下:
- GestureDetector 首先愉快地从您通过 setOnTouchListener() 安装在 ListItems 中的 onTouch 获取 MotionEvents。
- ListView 同时监听通过 onInterceptTouchEvent() 发送到其 subview 的事件
- ListView 检测到您已开始滚动并从 onInterceptTouchEvent() 返回 true。
- 从那时起,MotionEvents 将被发送到 ListView 而不是原始目标...ListView 开始在其 onTouch 处理程序中接收 MotionEvents。这一直持续到最后的 ACTION_UP。 (请注意,从 ACTION_DOWN 到所有 ACTION_MOVE 到 ACTION_UP 的 MotionEvent 被视为单个手势,并且在序列中的最后一个 ACTION_UP 之后一切都会重新开始)
- 原始目标 (ListItem) 收到 ACTION_CANCEL MotionEvent,并且 ListItem 中的 GestureDetector 退出。如果您将 GestureDetector 的代码粘贴到您的应用程序中并单步执行,就会看到这种情况发生。
我需要我的应用程序表现得就像水平滑动继续,即使触摸稍微偏离水平方向。
解决方案: 这涉及 ViewGroup.requestDisallowInterceptTouchEvent (boolean disallowIntercept),它阻止父级查看运动事件。该方法涉及实现 onTouchListener 来检测轻微的滑动(10 像素左右),然后停止父拦截运动事件。然后,父级将不会滚动,手势检测器将继续完成。
代码如下:
private boolean mFlingInProgress = false;
private float mStartX = 0;
private final int FLING_TRIGGER_DISTANCE = 10;
@Override
public boolean onTouch(View v, MotionEvent event) {
int action = event.getAction();
float currentX = event.getRawX();
switch (action) {
case MotionEvent.ACTION_DOWN:
mStartX = currentX;
break;
case MotionEvent.ACTION_MOVE:
if (false == mFlingInProgress) {
if (Math.abs(currentX - mStartX) > FLING_TRIGGER_DISTANCE) {
// stop the parent intercepting motion events
mLayout.getParent().requestDisallowInterceptTouchEvent(true);
mFlingInProgress = true;
}
}
break;
case MotionEvent.ACTION_UP:
mFlingInProgress = false;
break;
}
return mGestureDetector.onTouchEvent(event);
}
关于android - 手势检测器不适用于可滚动列表 Activity ,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/4446678/