手势检测器不适用于可滚动列表活动

发布于 2024-10-07 20:04:00 字数 344 浏览 2 评论 0原文

我有一个简单的应用程序,有两个视图,一个是 TableView,另一个是 ListView。我使用 GestureDetector 来检测屏幕上的滑动,类似于此处< /a>.如果列表视图仅填充了几个项目,则一切正常,但是当 ListView 填满整个屏幕时,手势检测将停止工作。在屏幕上滑动只会突出显示列表项之一。

我认为发生这种情况是因为 ListView 以某种方式从 GestureListener 窃取了触摸事件。有办法防止这种情况吗?

I have a simple application with two views, one is a TableView and the other is ListView. I use GestureDetector to detect the swipes across the screen similarly to how it is done here. Everything works OK, if the list view is populated with just a few items, however when the ListView fills up the whole screen the gesture detection stops working. Doing the swipe across the screen simply shows highlights one of the list items.

I think this is happening because ListView somehow steals the touch events from the GestureListener. Is there a way to prevent this?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

黯然 2024-10-14 20:04:00

我发现,如果您遍历相当准确的水平路径,GestureDetector 在 ListItems 中工作得很好。但是,如果您稍微偏离,列表就会滚动并且手势不会完成。发生的事情如下:

  • GestureDetector 开始愉快地从您通过 setOnTouchListener() 安装在 ListItems 中的 onTouch 获取 MotionEvents。
  • 同时,ListView 正在侦听通过 onInterceptTouchEvent() 发送到其子视图的事件。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);
}

I found that GestureDetector works fine in ListItems if you traverse a fairly accurate horizontal path. However if you stray slightly, the list scrolls and the gesture does not complete. What is going on is as follows:

  • The GestureDetector starts off happily taking MotionEvents from the onTouch you install in the ListItems via setOnTouchListener().
  • The ListView is meanwhile listening in on events sent to its child views via onInterceptTouchEvent()
  • The ListView detects that you have started to scroll and returns true from onInterceptTouchEvent().
  • From then on the MotionEvents are sent to the ListView and NOT to the original target... the ListView starts receiving MotionEvents in its onTouch handler. This continues until the final ACTION_UP. (Note that the MotionEvents from ACTION_DOWN through all the ACTION_MOVEs to ACTION_UP are considered a single gesture and everything starts again after the final ACTION_UP in the sequence)
  • The original target (ListItem) gets an ACTION_CANCEL MotionEvent and the GestureDetector in your ListItem bails out. This can be seen to happen if you paste the code for GestureDetector into your app and step through it.

I needed my app to behave as if the horizontal swipe continued even if the touch strays from horizontal slightly.

SOLUTION:
This involves ViewGroup.requestDisallowInterceptTouchEvent (boolean disallowIntercept) which stops the parent being able to peek at the motion events. The method involves implementing onTouchListener to detect a slight swipe (10 pixels or so) then stopping the parent intercepting motion events. The parent will then not scroll and the gesture detector continues to completion.

Here's the code:

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);
}
烟燃烟灭 2024-10-14 20:04:00

您可以创建一个自定义列表视图,然后在该列表的每一行上实现手势检测器。可能值得一试。

You could create a custom listview and then implement the gesture detector inside of this i.e. on each row of the list. Could be worth a try.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文