How to do circular scrolling on ViewPager?

后端 未结 10 1501
别那么骄傲
别那么骄傲 2020-11-28 04:31

I would like to set my ViewPager to do circular scrolling. I want the first page to be able to scroll to page 2 AND the last page. And I would like my last page to scroll to

相关标签:
10条回答
  • 2020-11-28 05:09

    I tried @portfoliobuilder's solution, it's great. But there's a tiny problem: when the current item is the head or the tail, if I just click the ViewPager, not drag, the item will change to the tail or the head. And I added a touch listener to the ViewPager to solve the problem.

    skinPager.setOnTouchListener(new OnTouchListener() {
    
            @Override
            public boolean onTouch(View v, MotionEvent event) {
                //Record the x when press down and touch up, 
                //to judge whether to scroll between head and tail
                int x = (int) event.getX();
                int y = (int) event.getY();
                if(event.getAction() == MotionEvent.ACTION_DOWN)
                    skinPagerPressX = x;
                else if(event.getAction() == MotionEvent.ACTION_UP)
                    skinPagerUpX = x;
                return false;
            }
        });
    

    The following is the modified function of portfoliobuilder:

    private void handleSetNextItem() {
        final int lastPosition = skinPager.getAdapter().getCount() - 1;
        //Only scroll when dragged
        if(mCurrentPosition == 0 && skinPagerUpX > skinPagerPressX) {
            skinPager.setCurrentItem(lastPosition, false);
        } else if(mCurrentPosition == lastPosition && skinPagerUpX < skinPagerPressX) {
            skinPager.setCurrentItem(0, false);
        }
    }
    
    0 讨论(0)
  • 2020-11-28 05:14

    Try this

    ((ViewPager) container)
                    .setOnPageChangeListener(new OnPageChangeListener() {
                        @Override
                        public void onPageSelected(int position) {
                            Log.i("TAG", "pos::" + position);
    
                        }
                        @Override
                        public void onPageScrollStateChanged(int state) {
                            // TODO Auto-generated method stub                            
                               int currentPage = pager.getCurrentItem();
                               Log.i("TAG", "currentPage::" + currentPage);
                               Log.i("TAG", "currentState::" + currentState);
                               Log.i("TAG", "previousState::" + previousState);
                               if (currentPage == 4 || currentPage == 0) {
                                previousState = currentState;
                                currentState = state;
                                if (previousState == 1 && currentState == 0) {
                                 pager.setCurrentItem(currentPage == 0 ? 4 : 0);
                                }
                               }
    
                        }
    
                        @Override
                        public void onPageScrolled(int arg0, float arg1,
                                int arg2) {
                            // TODO Auto-generated method stub
    
                        }
                    });
    
            return
    

    This should be placed inside

     @Override
        public Object instantiateItem(final View container, int position) {}
    
    0 讨论(0)
  • 2020-11-28 05:16

    This is a solution without fake pages and works like a charm:

    public class CircularViewPagerHandler implements ViewPager.OnPageChangeListener {
        private ViewPager   mViewPager;
        private int         mCurrentPosition;
        private int         mScrollState;
    
        public CircularViewPagerHandler(final ViewPager viewPager) {
            mViewPager = viewPager;
        }
    
        @Override
        public void onPageSelected(final int position) {
            mCurrentPosition = position;
        }
    
        @Override
        public void onPageScrollStateChanged(final int state) {
            handleScrollState(state);
            mScrollState = state;
        }
    
        private void handleScrollState(final int state) {
            if (state == ViewPager.SCROLL_STATE_IDLE && mScrollState == ViewPager.SCROLL_STATE_DRAGGING) {
                setNextItemIfNeeded();
            }
        }
    
        private void setNextItemIfNeeded() {
            if (!isScrollStateSettling()) {
                handleSetNextItem();
            }
        }
    
        private boolean isScrollStateSettling() {
            return mScrollState == ViewPager.SCROLL_STATE_SETTLING;
        }
    
        private void handleSetNextItem() {
            final int lastPosition = mViewPager.getAdapter().getCount() - 1;
            if(mCurrentPosition == 0) {
                mViewPager.setCurrentItem(lastPosition, true);
            } else if(mCurrentPosition == lastPosition) {
                mViewPager.setCurrentItem(0, true);
            }
        }
    
        @Override
        public void onPageScrolled(final int position, final float positionOffset, final int positionOffsetPixels) {
        }
    }
    

    You just have to set it to your ViewPager as onPageChangeListener and that's it:

    viewPager.setOnPageChangeListener(new CircularViewPagerHandler(viewPager));
    

    To avoid having this blue shine at the "end" of your ViewPager you should apply this line to your xml where the ViewPager is placed:

    android:overScrollMode="never"
    
    0 讨论(0)
  • 2020-11-28 05:19

    The answer of @tobi_b is not totally successful, since it doesn't slide smoothly from the last to the first(At least in my trial). But I was really inspired by his answer. My solution is when it's time to jump from the fake last to the real first, wait until last scroll finished. Here is my code, it's very simple,

    private final class MyPageChangeListener implements OnPageChangeListener {
    
        private int currentPosition;
    
        @Override
        public void onPageScrollStateChanged(int state) {
            if (state == ViewPager.SCROLL_STATE_IDLE) {
                if (currentPosition == viewPager.getAdapter().getCount() - 1) {
                    viewPager.setCurrentItem(1, false);
                }
                else if (currentPosition == 0) {
                    viewPager.setCurrentItem(viewPager.getAdapter().getCount() - 2, false);
                }
            }
        }
    
        @Override
        public void onPageScrolled(int scrolledPosition, float percent, int pixels) {
            //empty
        }
    
        @Override
        public void onPageSelected(int position) {
            currentPosition = position;
        }
    
    }
    

    However, this solution is not perfect. It has a little flaw when slide fast from the last to the first. If we slide twice in a very short time, the second slide will invalidate. This problem need to be solved.

    0 讨论(0)
提交回复
热议问题