如果子视图返回 false,则让父视图采用 MotionEvents

发布于 2024-12-03 09:00:18 字数 2315 浏览 2 评论 0原文

我有一个应用程序需要以不寻常的方式处理事件。

对于我的问题,我首先解释一个简单的情况,Android当前的事件处理系统不适合我。

假设我有一个 FrameLayout(从现在起我将称为 ViewSwiper),添加到其上的所有视图都是 MATCH_PARENT X MATCH_PARENT(我将称为 PageView),它通过翻译实际视图并根据方向替换它来处理事件的移动。 该组件我已经完成并正常工作(使用动画来滑动视图)。

但问题在于我在其上添加的 PageView,如果 ImageView 在其 onTouchEvent 上返回 false,ViewSwiper 将处理事件并让另一个 PageView 进入屏幕,但如果我在其上添加 ScrollView,则所有事件将被 Scroll 消耗,并且 ViewSwiper 将没有机会替换 PageView。

所以我发现返回 false onTouchEvent 的 ScrollView 父级可以假设它是事件,我编写了 ScrollView 的这个子类来测试它:

public class ScrollViewVertical extends ScrollView {
    public ScrollViewVertical(Context context) {
        super(context);
        setOverScrollMode(OVER_SCROLL_ALWAYS);
        setVerticalScrollBarEnabled(false);
    }

    public boolean onTouchEvent(MotionEvent evt) {
        super.onTouchEvent(evt);
        return false;
    }
}

但是返回 false 会使任何进一步的事件分派给父级,但我需要这些事件垂直滚动,所以我的想法是仅当用户水平移动时才返回 false,这就是我的代码的样子:

public class ScrollViewVertical extends ScrollView {
    private MovementTracker moveTracker;
    public ScrollViewVertical(Context context) {
        super(context);
        setOverScrollMode(OVER_SCROLL_ALWAYS);
        setVerticalScrollBarEnabled(false);
        moveTracker = new MovementTracker();
    }
    public boolean onTouchEvent(MotionEvent evt) {
        if (moveTracker.track(evt))
            if (moveTracker.getDirection() == Direction.HORIZONTAL)
                return false;

        return super.onTouchEvent(evt);
    }
}

PS:在某些事件发生后,MovementTracker 将在 track() 上返回 true 并告诉哪些事件用户移动的方向。

但在这种情况下,ScrollView 会继续接收事件,因为它在第一个事件上返回 true。

关于如何在 ViewSwiper 的子级返回 false 时处理事件的任何想法(即使返回了一些 true)。

PS:如果需要,我可以提供更多信息,并接受不同的解决方案。

根据答案,我尝试了以下操作:

@Override
public boolean dispatchTouchEvent(MotionEvent ev) {
    onTouchEvent(ev);
    return intercept;
}

public boolean onTouchEvent(MotionEvent evt) {
    boolean x = super.onTouchEvent(evt);

    if (moveTracker.track(evt)) {
        intercept = moveTracker.getDirection() != Direction.VERTICAL;
        if (!intercept)
            getParent().requestDisallowInterceptTouchEvent(false);
    }

    return x;
}

仍然没有。

I have a application that need event handling on a unusual way.

For my question, let me first explain a simple case that the current event handling system of Android don't fits for me.

Supposing that I have a FrameLayout (that I'll call ViewSwiper since now) that all Views added on it are MATCH_PARENT X MATCH_PARENT (that I'll call PageView), it's handles events by translating the actual View and replace it based on the direction of moving.
This component I already have done and work properly ( Using Animation to swipe views ).

But the problem is on that PageView I add on top of it, in case of ImageViews that return false on it's onTouchEvent, the ViewSwiper will handle the events and let another PageView enter the screen, but if I add a ScrollView on that, all the events will be consumed by the Scroll and the ViewSwiper will not have chance to replace the PageView.

So I figured out that returning false onTouchEvent of the ScrollView the parent can assume it's events, I wrote this sub-class of ScrollView to test it:

public class ScrollViewVertical extends ScrollView {
    public ScrollViewVertical(Context context) {
        super(context);
        setOverScrollMode(OVER_SCROLL_ALWAYS);
        setVerticalScrollBarEnabled(false);
    }

    public boolean onTouchEvent(MotionEvent evt) {
        super.onTouchEvent(evt);
        return false;
    }
}

But returning false make any further events to get dispatched to the parent, but I need these events for VERTICAL scrolling, so I have the idea to return falses only if the user are moving HORIZONTAL, that's what my code looks like:

public class ScrollViewVertical extends ScrollView {
    private MovementTracker moveTracker;
    public ScrollViewVertical(Context context) {
        super(context);
        setOverScrollMode(OVER_SCROLL_ALWAYS);
        setVerticalScrollBarEnabled(false);
        moveTracker = new MovementTracker();
    }
    public boolean onTouchEvent(MotionEvent evt) {
        if (moveTracker.track(evt))
            if (moveTracker.getDirection() == Direction.HORIZONTAL)
                return false;

        return super.onTouchEvent(evt);
    }
}

PS: MovementTracker will returns true on track() after some events and tell on which direction the user is moving.

But in that case, the ScrollView keep receiving events since it's returns true on the first events.

Any ideas on how can I handle the events on ViewSwiper when it's child returns false (even if some trues are returned).

PS: I can give more info about this if needed, and accept different solutions also.

Based on answers I tried the following:

@Override
public boolean dispatchTouchEvent(MotionEvent ev) {
    onTouchEvent(ev);
    return intercept;
}

public boolean onTouchEvent(MotionEvent evt) {
    boolean x = super.onTouchEvent(evt);

    if (moveTracker.track(evt)) {
        intercept = moveTracker.getDirection() != Direction.VERTICAL;
        if (!intercept)
            getParent().requestDisallowInterceptTouchEvent(false);
    }

    return x;
}

Still nothing.

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

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

发布评论

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

评论(2

半枫 2024-12-10 09:00:18

在滚动视图的 onTouchEvent() 中尝试此

     //if (evt.getAction() == MotionEvent.ACTION_MOVE) {
    if (moveTracker.track(evt)){
       if (moveTracker.getDirection() == Direction.VERTICAL){
          //Or the direction you want the scrollview keep moving
          getParent().requestDisallowInterceptTouchEvent(true);

            }
        } 
 return true;

更新

请尝试对自定义滚动视图执行以下操作

@Override
public boolean dispatchTouchEvent(MotionEvent ev) {
super.dispatchTouchEvent(ev);
    return false;
}

,仅此而已,

这样我假设 MotionEvent 将在两个视图上执行。由于它们不冲突(一个是垂直的,另一个是水平的),所以这可以工作

try this in onTouchEvent() of the scrollview

     //if (evt.getAction() == MotionEvent.ACTION_MOVE) {
    if (moveTracker.track(evt)){
       if (moveTracker.getDirection() == Direction.VERTICAL){
          //Or the direction you want the scrollview keep moving
          getParent().requestDisallowInterceptTouchEvent(true);

            }
        } 
 return true;

Update

Please try the following to the custom Scrollview

@Override
public boolean dispatchTouchEvent(MotionEvent ev) {
super.dispatchTouchEvent(ev);
    return false;
}

And nothing else

This way i assume the MotionEvent will perform on both views. And since they don't conflict (One is vertical the other one is Horizontal) this could work

知你几分 2024-12-10 09:00:18

根据weakwire的答案,我得出了以下解决方案:

在ViewSwiper

    @Override
    public boolean dispatchTouchEvent(MotionEvent ev) {
        if(!super.dispatchTouchEvent(ev))
            onTouchEvent(ev);
        return true;
    }

和ScrollHorizo​​ntal上,当我不再需要时,我在dispatchTouchEvent上返回false。

Based on the answer from weakwire, I came to the following solution:

On ViewSwiper

    @Override
    public boolean dispatchTouchEvent(MotionEvent ev) {
        if(!super.dispatchTouchEvent(ev))
            onTouchEvent(ev);
        return true;
    }

And on ScrollHorizontal I return false on dispatchTouchEvent when I don't need then anymore.

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