检测ViewGroup及其所有子视图上的SwipeGesture

时间:2018-02-09 16:56:20

标签: java android

我有一个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;
    }
}

1 个答案:

答案 0 :(得分:2)

当触摸事件发生时,它首先被传递到父布局视图,并通过onInterceptTouchEvent传递给子视图,返回true或false。您希望覆盖并拦截父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;
}