Android ViewPager如何检测超出边界的滑动?

3
在我的Android应用程序中,我使用了一个viewpager来进行图像切换。我的要求是,如果用户滑动到第一页和最后一页之外,活动应该结束。
我参考了这个示例。但是,在我的活动中,方法setOnSwipeOutListener没有被调用。
这是我的自定义view pager类:
public class CustomViewPager extends ViewPager {

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

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

    float mStartDragX;
    OnSwipeOutListener mListener;

    public void setOnSwipeOutListener(OnSwipeOutListener listener) {
        mListener = listener;
    }

    @Override
    public boolean onInterceptTouchEvent(MotionEvent ev) {
        float x = ev.getX();
        switch (ev.getAction()) {
        case MotionEvent.ACTION_DOWN:
            mStartDragX = x;
            break;
        case MotionEvent.ACTION_MOVE:
            if (mStartDragX < x && getCurrentItem() == 0) {
                mListener.onSwipeOutAtStart();
            } else if (mStartDragX > x
                    && getCurrentItem() == getAdapter().getCount() - 1) {
                mListener.onSwipeOutAtEnd();
            }
            break;
        }
        return super.onInterceptTouchEvent(ev);
    }

    public interface OnSwipeOutListener {
        public void onSwipeOutAtStart();

        public void onSwipeOutAtEnd();
    }

} 

在我的活动类中,我调用了自定义viewpager类的setOnSwipeOutListener方法,但它没有被调用。
myPager = (CustomViewPager) findViewById(R.id.home_pannels_pager);

.......

myPager.setOnSwipeOutListener(new OnSwipeOutListener() { // the method never called
    @Override
    public void onSwipeOutAtStart() {
        Log.e("swipe Out At Start ", "swipe out");
    }

    @Override
    public void onSwipeOutAtEnd() {
        Log.e("swipe Out At End ", "swipe end");
    }
});

myPager.setOnPageChangeListener(new ViewPager.SimpleOnPageChangeListener() {
    @Override
    public void onPageSelected(int po) {
        Log.e("positon", ""+po);
    }
});

请帮助我检测用户是否在第一页和最后一页之外滑动以关闭此活动,并告诉我如何从代码中调用该方法。

我的要求是如果用户滑出第一页和最后一页,活动应该结束。-- 在我看来,从用户体验的角度来看,这是令人不快的。 - CommonsWare
@CommonsWare 为什么会很糟糕呢?当您在Onboarding中使用它时,人们会向下滑动到最后一页,在最后一页上,他们必须点击一个按钮或执行不同的操作。相反,如果他们可以滑动并完成Onboarding,那对他们来说不是更容易吗? - Gokhan Arik
1
@GokhanArik 因为用户很少能回到引导屏幕。按照您的建议,他们会不停地滑动,滑动,滑动,哎呀,现在他们无法返回,因为他们滑动了太多次。我的评论并不是针对引导屏幕,但即使在您的情况下,我仍然不会这样做。 - CommonsWare
https://dev59.com/s2Yr5IYBdhLWcg3w29ri#76712000 这个链接是有效的。 - Kanan
4个回答

1

在我的情况下,onInterceptTouchEvent无法工作。我用onTouchEvent方法进行更改,现在它可以工作了。原始解决方案来自tjlian616

    @Override
public boolean onTouchEvent(MotionEvent ev){
    if(getCurrentItem()==getAdapter().getCount()-1){
        final int action = ev.getAction();
        float x = ev.getX();
        switch(action & MotionEventCompat.ACTION_MASK){
        case MotionEvent.ACTION_DOWN:
            mStartDragX = x;
            break;
        case MotionEvent.ACTION_MOVE:
            break;
        case MotionEvent.ACTION_UP:
            if (x<mStartDragX){
                mListener.onSwipeOutAtEnd();
            }else{
                mStartDragX = 0;
            }
            break;
        }
    }else{
        mStartDragX=0;
    }
    return super.onTouchEvent(ev);
}    

0

我修改了M.A.Murali的代码:

public class CheckBoundsPager extends ViewPager {
    public CheckBoundsPager(Context context) {
        super(context);
    }

    public CheckBoundsPager(Context context, AttributeSet attrs) {
        super(context, attrs);

    }

    OnSwipeOutListener mListener;

    public void setOnSwipeOutListener(OnSwipeOutListener listener) {
        mListener = listener;
    }

    private float mStartDragX;
    private float mStartDragY;
    private float MIN_MOVE=50; //minimal movement in px - change it to you value


    @Override
    public boolean onInterceptTouchEvent(MotionEvent ev) {
        float x = ev.getX();
        float y = ev.getY();
        switch (ev.getAction()) {
            case MotionEvent.ACTION_DOWN: {
                //here we set x and y on user start drag
                mStartDragX = x;
                mStartDragY = y;

                }
                break;
            case MotionEvent.ACTION_MOVE: {

                //most important to check if x drag is more than y
                float xDiff=Math.abs(mStartDragX-x);
                float yDiff=Math.abs(mStartDragY-y);

                //added condition if swipe y is less than x
                if (mStartDragX < x-MIN_MOVE && xDiff>yDiff &&  getCurrentItem() == 0) {
                    mListener.onSwipeOutAtStart();
                } else if (mStartDragX > x+MIN_MOVE
                        && xDiff>yDiff && getCurrentItem() == getAdapter().getCount() - 1) {
                    mListener.onSwipeOutAtEnd();
                }
                }
                break;
        }
        return super.onInterceptTouchEvent(ev);
    }

    public interface OnSwipeOutListener {

        public void onSwipeOutAtStart();

        public void onSwipeOutAtEnd();
    }
}

这个解决方案检查我们是向左还是向右拖动,而且我们的拖动移动是在 x 轴上的。记得更改 MIN_MOVE


2
欢迎来到StackOverflow。请不要包含所有原始问题,只展示需要更改的部分。这将有助于未来遇到相同问题的人更好地理解您是如何解决问题的。 - buczek

0

我也使用了这个SO答案中的代码。确保你对你的活动类进行必要的更改。这是我所做的...

我改变了我的活动,使它实现了CustomViewPager.OnSwipeOutListener

在我的活动中,在mPager = (CustomViewPager) findViewById(R.id.pager);行之后,我调用 mPager.setOnSwipeOutListener(this);

然后你只需要在你的活动中重写onSwipeOutAtStart()onSwipeOutAtEnd()方法即可。


-1

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接