【问题标题】:Detecting a SwipeGesture on a ViewGroup and all its child views在 ViewGroup 及其所有子视图上检测 SwipeGesture
【发布时间】:2018-02-10 11:40:58
【问题描述】:

我有一个RelativeLayout,其中包含许多带有各种触摸事件的子视图。我想在用户在父级RelativeLayout 上的任意位置滑动时收到通知,这样我就可以更新一些 UI,同时仍然让子视图处理自己的触摸/拖动事件。为 Android 完成此任务的标准方法是什么?

我在想我可以在所有视图上放置一个叠加层,让它检测滑动手势,如果不是滑动,我可以将触摸事件传递给层次结构中的其他视图。 Android 似乎不支持这种触摸检测,一旦一个视图决定查看事件是否是某个手势,其他视图将无法看到这些事件。

滑动手势由三个触摸事件组成:ACTION_DOWN、ACTION_MOVE 和 ACTION_UP。您需要记录所有三个事件,然后查看是否是滑动。如果不是滑动,那么我们需要将这些事件传递给其他子视图,以查看它是否符合他们正在寻找的手势的标准。如果是滑动,我们希望阻止将事件发送到子视图。只是不确定这是否真的可行。

更新

使用答案部分中用户的想法,我能够编写符合我规范的布局。这个RelativeLayout 只处理左右滑动,但可以添加到处理更多方向。 OnSwipeListener 只是一个 interface 有两个方法 void swipedLeft()void swipedRight()

public class SwipeRelativeLayout extends RelativeLayout {

    public OnSwipeListener mSwipeListener = null;

    private static final int SWIPE_DISTANCE_THRESHOLD = 100;
    private float mStartX = 0;
    private float mStartY = 0;
    private float mEndX = 0;
    private float mEndY = 0;

    public SwipeRelativeLayout(Context context) {
        super(context);
    }

    public SwipeRelativeLayout(Context context, AttributeSet attrs) {
        super(context, attrs);
    }

    public SwipeRelativeLayout(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
    }

    public SwipeRelativeLayout(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
        super(context, attrs, defStyleAttr, defStyleRes);
    }

    @Override
    public boolean onInterceptTouchEvent(MotionEvent event) {
        boolean handled = onTouchEvent(event);
        if (event.getAction() == MotionEvent.ACTION_UP) return handled;
        return false;
    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        switch (event.getAction()) {
            case MotionEvent.ACTION_DOWN: {
                mStartX = event.getRawX();
                mStartY = event.getRawY();
                break;
            }
            case MotionEvent.ACTION_MOVE: {
                float distanceX = event.getRawX() - mStartX;
                float distanceY = event.getRawY() - mStartY;
                if (Math.abs(distanceX) > Math.abs(distanceY) && Math.abs(distanceX) > SWIPE_DISTANCE_THRESHOLD) {
                    if (distanceX > 0) {
                        if (mSwipeListener != null) mSwipeListener.swipedRight();
                    } else {
                        if (mSwipeListener != null) mSwipeListener.swipedLeft();
                    }
                    return true;
                }
                return false;
            }
        }
        return true;
    }
}

【问题讨论】:

    标签: java android


    【解决方案1】:

    当触摸事件发生时,它首先传递给父布局视图,然后通过onInterceptTouchEvent 传递给子视图,返回真或假。您想要覆盖和拦截父 RelativeLayout 上的触摸事件,并确定您是否看到了滑动手势。如果您看到了滑动,您想返回您已经处理过它。在这种情况下,ACTION_UP 是可能滑动的结束,如果您的 onTouchEvent 处理了该事件,那么您可以返回 true 并且它下面的视图将不会获得完成事件,因此会忽略它们的手势。

    @Override
    public boolean onInterceptTouchEvent(MotionEvent event) {
        boolean handled = onTouchEvent(event);
        if (event.getAction() == MotionEvent.ACTION_UP) return handled;
        return false;
    }
    

    【讨论】:

    • 我会在哪里实现这个?在RelativeLayout 的子类中?这是处理这种情况的最佳做法还是只是一种技巧?
    • 是的,另外,当执行 swype 手势并且 relativelayout 消耗它时,返回 true 和 setInterceptTouchEvent(true) 所以最后一个事件不会发送给孩子
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2023-02-02
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-04-12
    • 2012-05-17
    • 2011-03-18
    相关资源
    最近更新 更多