Android ViewPager 中的滑动方向

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/24721539/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-20 08:38:31  来源:igfitidea点击:

Swipe Direction in ViewPager

androidandroid-viewpagerswipedirectionfragmentstatepageradapter

提问by Greeso

I have an Android app that uses ViewPager and FragmentStatePagerAdapter. I however need to add a new feature in which I have to know the swipe direction to move from one fragment view to another, left or right. (i.e, when I swipe left, I would do one thing, and when I swipe right I would do something else).

我有一个使用 ViewPager 和 FragmentStatePagerAdapter 的 Android 应用程序。但是,我需要添加一个新功能,在该功能中我必须知道从一个片段视图向左或向右移动的滑动方向。(即,当我向左滑动时,我会做一件事,而当我向右滑动时,我会做其他事情)。

Please note, I do not need the events to happen AFTER the swipe is over. I have to do those events as the swipe occurs. I thought of using setOnPageChangeListener()but it does not tell me swipe direction. Can you advise me please on how to figure out swipe direction?

请注意,我不需要在滑动结束后发生事件。我必须在发生滑动时执行这些事件。我想过使用,setOnPageChangeListener()但它没有告诉我滑动方向。你能告诉我如何确定滑动方向吗?

Thanks.

谢谢。

回答by drees

I ran into this issue and need to know the direction of the swipe as it was happeningin order to prevent swiping in a certain direction. Here is how I solved my problem, hopefully it is helpful to someone. I found all of the previous examples inefficient for what I needed.

我遇到了这个问题,需要知道正在发生的滑动方向,以防止向某个方向滑动。以上是我解决问题的方法,希望对大家有所帮助。我发现之前的所有示例都无法满足我的需要。

If you subclass your ViewPager, you can respond to the onInterceptTouchEvent(MotionEvent event)and onTouchEvent(MotionEvent event)methods of the ViewPager

如果你的子类ViewPager,你可以在响应onInterceptTouchEvent(MotionEvent event)onTouchEvent(MotionEvent event)方法ViewPager

@Override
public boolean onInterceptTouchEvent(MotionEvent event) {
    boolean wasSwipeToRight = this.wasSwipeToRightEvent(event));
    // Do what you want here with left/right swipe

    return super.onInterceptTouchEvent(event);
}

@Override
public boolean onTouchEvent(MotionEvent event) {
    boolean wasSwipeToRight = this.wasSwipeToRightEvent(event));
    // Do what you want here with left/right swipe

    return super.onTouchEvent(event);
}

Here is the method which is called to determine the direction of the event.

这是用于确定事件方向的方法。

// Stores the starting X position of the ACTION_DOWN event
float downX;

/**
 * Checks the X position value of the event and compares it to
 * previous MotionEvents. Returns a true/false value based on if the 
 * event was an swipe to the right or a swipe to the left.
 *
 * @param event -   Motion Event triggered by the ViewPager
 * @return      -   True if the swipe was from left to right. False otherwise
 */
private boolean wasSwipeToRightEvent(MotionEvent event){
    switch (event.getAction()) {
        case MotionEvent.ACTION_DOWN:
            downX = event.getX();
            return false;

        case MotionEvent.ACTION_MOVE:
        case MotionEvent.ACTION_UP:
            return downX - event.getX() > 0;

        default:
            return false;
    }
}

回答by TomTaila

This is simple enough with the introduction of an instance variable to keep track of the current page.

这很简单,引入了一个实例变量来跟踪当前页面。

public class MyActivity extends Activity implements ViewPager.OnPageChangeListener {

    private ViewPager viewPager;
    private int currentPosition;


    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        // Do trivial stuff
        .
        .
        .
        viewPager.setOnClickListener(this); // doesnt have to be in onCreate
    }

    @Override
    public void onPageSelected(int position) {
        if(currentPosition < position) {
            // handle swipe LEFT
        } else if(currentPosition > position){
            // handle swipe RIGHT
        }
        currentPosition = position; // Update current position
    }
}

回答by Vino

Take a look at the onPageSelected(int position)method of ViewPager.OnPageChangeListener. The positiongives the index of newly selected page. If you keep a track of the current page index, then you can compare it against the positionindex to get the left/right direction of the swipe.

看一下ViewPager.OnPageChangeListeneronPageSelected(int position)方法。在给新选择的页面的索引。如果您跟踪当前页面索引,则可以将其与索引进行比较以获取向左/向右滑动的方向。positionposition

Now that you mention OnPageChangeListener doesn't help, consider the onInterceptTouchEvent (MotionEvent ev)method of ViewPager. Take into consideration the MotionEvent's ACTION_DOWN, ACTION_MOVE and ACTION_UP. Hope this helps.

既然你提到OnPageChangeListener没有帮助,考虑onInterceptTouchEvent (MotionEvent ev)的方法ViewPager。考虑 MotionEvent 的 ACTION_DOWN、ACTION_MOVE 和 ACTION_UP。希望这可以帮助。

回答by axl coder

Maybe you can build a listener like this:

也许你可以像这样构建一个监听器:

buttonIcons.setOnTouchListener(new OnTouchListener() {

        @Override
        public boolean onTouch(final View v, final MotionEvent event) {
            switch (event.getAction()) {
            case MotionEvent.ACTION_DOWN:
                downX = event.getX();

                return true;

            case MotionEvent.ACTION_UP:

                upX = event.getX();
                final float deltaX = downX - upX;

                if (deltaX > 0 && deltaX > SWIPE_MIN_DISTANCE) {

                    final Animation loadInAnimation = AnimationUtils
                            .loadAnimation(
                                    activity.this,
                                    R.anim.slide_in_right);
                    final Animation loadOutAnimation = AnimationUtils
                            .loadAnimation(
                                    activity.this,
                                    R.anim.slide_out_left);

                    viewFlipper.setInAnimation(loadInAnimation);
                    viewFlipper.setOutAnimation(loadOutAnimation);
                    viewFlipper.showPrevious();

                    startSaveButtonAnimation();

                }
                if (deltaX < 0 && -deltaX > SWIPE_MIN_DISTANCE) {

                    final Animation loadInAnimation = AnimationUtils
                            .loadAnimation(
                                    activity.this,
                                    R.anim.slide_in_left);
                    final Animation loadOutAnimation = AnimationUtils
                            .loadAnimation(
                                    activity.this,
                                    R.anim.slide_out_right);

                    viewFlipper.setInAnimation(loadInAnimation);
                    viewFlipper.setOutAnimation(loadOutAnimation);
                    viewFlipper.showNext();

                    startSaveButtonAnimation();

                }
                return true;

            }

            return false;
        }
    });

回答by Yarh

You actually can find direction from using parameters of onPageScrolled.
Following listener is set to show log message once per direction of net fragment change ( left if left fragments reveals, center if no fragment reveals, right if right fragment reveals).
Class variables, need to keep track

您实际上可以通过使用 的参数找到方向onPageScrolled
以下侦听器设置为在每个净片段更改方向上显示一次日志消息(如果左侧片段显示,则为左,如果没有片段显示则居中,如果右侧片段显示则为右侧)。
类变量,需要跟踪

    // -1 - left, 0 - center, 1 - right
    private int scroll = 0; 
    // set only on `onPageSelected` use it in `onPageScrolled` 
    // if currentPage < page - we swipe from left to right
    // if currentPage == page - we swipe from right to left  or centered
    private int currentPage = 0; 
    // if currentPage < page offset goes from `screen width` to `0`
    // as you reveal right fragment. 
    // if currentPage == page , offset goes from `0` to `screen width`
    // as you reveal right fragment
    // You can use it to see 
    //if user continue to reveal next fragment or moves it back
    private int currentOffset = 0;
    // behaves similar to offset in range `[0..1)`
    private float currentScale = 0;

The listener

听者

pager.addOnPageChangeListener(
            new OnPageChangeListener(){

                @Override
                public void onPageScrolled(int page, float scale, int offset){


                    if(scale != 0f && offset > 10){


                        if(currentOffset > offset && currentScale > scale && (page + 1) == currentPage){


                            if(scroll != -1){
                                newImageSet = true;
                                scroll = -1;
                                Log.e("scroll", "left");
                            }
                        } else if(currentOffset < offset && currentScale < scale && page == currentPage){


                            if(scroll != 1){
                                newImageSet = true;
                                scroll = 1;
                                Log.e("scroll", "right");

                            }
                        }
                        currentOffset = offset;
                        currentScale = scale;



                }


                @Override
                public void onPageSelected(int i){
                    Log.e("scroll","centre");
                    // we are centerd, reset class variables
                    currentPage = i;
                    currentScale = 0;
                    currentOffset = 0;
                    scroll = 0;


                }


                @Override
                public void onPageScrollStateChanged(int i){

                }
            }
        );

回答by Eric Liu

You can add an OnPageChangeListner to the ViewPager and do something like this:

您可以将 OnPageChangeListner 添加到 ViewPager 并执行以下操作:

mViewPager.addOnPageChangeListener(new ViewPager.OnPageChangeListener() {
        float tempPositionOffset = 0;

        @Override
        public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
            if (position == 0) {
                if (tempPositionOffset < positionOffset) {
                    Log.d("eric", "scrolling left ...");
                } else {
                    Log.d("eric", "scrolling right ...");
                }

                tempPositionOffset = positionOffset;

           Log.d("eric", "position " + position + "; " + " positionOffset " + positionOffset + "; " + " positionOffsetPixels " + positionOffsetPixels + ";");
            }
        }

        @Override
        public void onPageSelected(int position) {

        }

        @Override
        public void onPageScrollStateChanged(int state) {

        }
    });

回答by Amro elaswar

I use this small implementation to detect if the user is scrolling to the right or to the left during the scrolling itself. I might have some bugs during certain conditions that I am not aware of but it is what I could come up with for what I needed without having to add a touch listener :

我使用这个小实现来检测用户在滚动过程中是向右还是向左滚动。在某些我不知道的情况下,我可能会遇到一些错误,但这是我可以想出的,而无需添加触摸侦听器:

viewPager.addOnPageChangeListener(new ViewPager.OnPageChangeListener() {

        int SCROLLING_RIGHT = 0;
        int SCROLLING_LEFT = 1;
        int SCROLLING_UNDETERMINED = 2;

        int currentScrollDirection = 2;

        @Override
        public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {

            if (isScrollDirectionUndetermined()){
                setScrollingDirection(positionOffset);
            }



            if (isScrollingLeft()){
                Log.i("TabLayout","Scrolling LEFT");
            }
            if (isScrollingRight()){
                Log.i("TabLayout","Scrolling RIGHT");

            }

        }

        private void setScrollingDirection(float positionOffset){
            if ((1-positionOffset)>= 0.5){
                this.currentScrollDirection = SCROLLING_RIGHT;
            }
            else if ((1-positionOffset)<= 0.5){
                this.currentScrollDirection =  SCROLLING_LEFT;
            }
        }

        private boolean isScrollDirectionUndetermined(){
            return currentScrollDirection == SCROLLING_UNDETERMINED;
        }

        private boolean isScrollingRight(){
            return currentScrollDirection == SCROLLING_RIGHT;
        }

        private boolean isScrollingLeft(){
            return currentScrollDirection == SCROLLING_LEFT;
        }

        @Override
        public void onPageSelected(int position) {
        }

        @Override
        public void onPageScrollStateChanged(int state) {
            if (state == ViewPager.SCROLL_STATE_IDLE){
                this.currentScrollDirection = SCROLLING_UNDETERMINED;
            }
        }

    });

We can detect the scroll direction because when the user is scrolling from left to right the positionOffsetgoes from 0 -> 1 and when scrolling from right to left it goes from 1 -> 0. We can then check that value once at the very beginning of a scroll and reset the flag only at the end of the scroll.

我们可以检测滚动方向,因为当用户从左向右滚动时,positionOffset从 0 -> 1 开始,当从右向左滚动时,它从 1 -> 0。然后我们可以在最开始检查该值一次滚动并仅在滚动结束时重置标志。

We set the currentScrollDirectionto undetermined at position idle instead of onPageSelectedbecause onPageSelectedcan get called if the user releases in the middle of a scroll and then you would get a false reading.

我们currentScrollDirection在空闲位置将 设置为 undetermined 而不是onPageSelected因为onPageSelected如果用户在滚动中间释放,则可能会被调用,然后您将获得错误读数。

回答by Matt Twig

You can use setOnPageChangeListener()and implement properly onPageScrolled(int position, float positionOffset, int positionOffsetPixels).

您可以setOnPageChangeListener()正确使用和实施onPageScrolled(int position, float positionOffset, int positionOffsetPixels)

You can detect direction by positionOffset and position variable:

您可以通过 positionOffset 和位置变量检测方向:

public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels)
{
   if(position == mCurrentPosition && positionOffset > 0)
   {
    //swipe right
   }
   else if (positionOffset > 0)
   {
   //swipe left
   }
}