在 ViewPager 中滑动方向

Posted

技术标签:

【中文标题】在 ViewPager 中滑动方向【英文标题】:Swipe Direction in ViewPager 【发布时间】:2014-09-03 11:37:37 【问题描述】:

我有一个使用 ViewPager 和 FragmentStatePagerAdapter 的 android 应用。然而,我需要添加一个新功能,我必须知道滑动方向才能从一个片段视图移动到另一个片段视图,向左或向右移动。 (即,当我向左滑动时,我会做一件事,当我向右滑动时,我会做其他事情)。

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

谢谢。

【问题讨论】:

【参考方案1】:

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

如果您将 ViewPager 子类化,则可以响应 ViewPageronInterceptTouchEvent(MotionEvent event)onTouchEvent(MotionEvent event) 方法

@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);

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

// 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;
    

【讨论】:

downX 对我来说总是返回 0.0 @Roon13 是 event.getX() 在您触摸屏幕时返回一个值?【参考方案2】:

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

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
    

【讨论】:

【参考方案3】:

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

既然您提到 OnPageChangeListener 没有帮助,请考虑 ViewPageronInterceptTouchEvent (MotionEvent ev) 方法。考虑 MotionEvent 的 ACTION_DOWN、ACTION_MOVE 和 ACTION_UP。希望这会有所帮助。

【讨论】:

【参考方案4】:

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

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;
        
    );

【讨论】:

非常感谢!有效!。我已经为此苦苦挣扎了很长时间!。【参考方案5】:

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

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;
            
        

    );

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

我们在空闲位置将currentScrollDirection 设置为未确定,而不是onPageSelected,因为如果用户在滚动过程中释放onPageSelected 可能会被调用,然后您会得到错误的读数。

【讨论】:

【参考方案6】:

其实你可以通过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;

听者

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)

                
            
        );

【讨论】:

【参考方案7】:

您可以将 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) 

        
    );

【讨论】:

【参考方案8】:

通过使用 Kotlin 和 ViewPager2,这是我的解决方案,您可以将 OnPageChangeCallback 侦听器注册为下面的 sn-p(仅向右滑动)

val pager = rootView.findViewById<ViewPager2>(R.id.viewPager).apply 
        registerOnPageChangeCallback(object : OnPageChangeCallback()
            var oldPosition = 0
            override fun onPageScrolled(position: Int, positionOffset: Float, positionOffsetPixels: Int
            ) 
                super.onPageScrolled(position, positionOffset, positionOffsetPixels)
                if (position < oldPosition) 
                    setCurrentItem(oldPosition, false)
                 else 
                    oldPosition = position
                
            
        )
    

【讨论】:

【参考方案9】:

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

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

public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels)

   if(position == mCurrentPosition && positionOffset > 0)
   
    //swipe right
   
   else if (positionOffset > 0)
   
   //swipe left
   

【讨论】:

你在哪里设置 mCurrentPosition ? 您可以将 mCurrentPosition 替换为 yourViewPager.getCurrentItem() 不行,viewPager.getCurrentItem 改变 onRelease。

以上是关于在 ViewPager 中滑动方向的主要内容,如果未能解决你的问题,请参考以下文章

处理导航抽屉内的 ViewPager 滑动

ViewPager2嵌套RecyclerView滑动冲突解决办法

判断viewpager左右滑动方向

如何将 viewPager 的方向反转为从左到右的顺序?

如何在 ViewPager 中实现 Swipe 事件以查看 Flipper?

在viewpager中图片滑动展示时图片与文字对应不上?