Android 如何制作 ViewPager 循环?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/10188011/
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 02:48:53  来源:igfitidea点击:

How to make a ViewPager loop?

androidloopsandroid-fragments

提问by J3n

I have a ViewPager with some views. I'd like to go to the first one after right swiping on the last one.

我有一个带有一些视图的 ViewPager。我想在最后一个向右滑动后转到第一个。

I tried

我试过

@Override
public Fragment getItem(int arg0) {
    int i = arg0 % fragmentList.size();
    return fragmentList.get(i);
}

@Override
public int getCount() {
    return fragmentList.size()+1;
}

But I got an error

但我有一个错误

E/AndroidRuntime(22912): java.lang.IllegalStateException: Fragment already added: RubricFragment{4136cd80 #1 id=0x7f06000c android:switcher:2131099660:0}

回答by benkc

One possibility is setting up the screens like this:

一种可能性是像这样设置屏幕:

C' A B C A'

C'ABCA'

C' looks just like C, but when you scroll to there, it switches you to the real C. A' looks just like A, but when you scroll to there, it switches you to the real A.

C' 看起来就像 C,但是当您滚动到那里时,它会将您切换到真正的 C。A' 看起来就像 A,但是当您滚动到那里时,它会将您切换到真正的 A。

I would do this by implementing onPageScrollStateChangedlike so:

我会通过像这样实现onPageScrollStateChanged来做到这一点:

@Override
public void onPageScrollStateChanged (int state) {
    if (state == ViewPager.SCROLL_STATE_IDLE) {
        int curr = viewPager.getCurrentItem();
        int lastReal = viewPager.getAdapter().getCount() - 2;
        if (curr == 0) {
            viewPager.setCurrentItem(lastReal, false);
        } else if (curr > lastReal) {
            viewPager.setCurrentItem(1, false);
        }
    }
}

Note that this calls the alternate form of setCurrentItemand passes falseto cause the jump to happen instantly rather than as a smooth scroll.

请注意,这会调用setCurrentItem的替代形式并传递false以导致立即发生跳转而不是平滑滚动。

There are two main drawbacks I see to this. Firstly, upon reaching either end the user has to let the scrolling settle before they can go further. Secondly, it means having a second copy of all of the views in your first and last page. Depending on how resource-heavy your screens are, that may rule out this technique as a possible solution.

我认为这有两个主要缺点。首先,在到达任一端时,用户必须让滚动稳定下来,然后才能继续前进。其次,这意味着拥有第一页和最后一页中所有视图的第二个副本。根据您的屏幕资源占用的程度,这可能会排除此技术作为可能的解决方案。

Note also that since the view pager doesn't let clicks go through to underlying controls until after the scrolling has settled, it's probably fine to not set up clicklisteners and the like for the A' and C' fragments.

另请注意,由于视图寻呼机在滚动稳定之前不会让点击进入底层控件,因此不为 A' 和 C' 片段设置点击监听器等可能没问题。

Edit:Having now implemented this myself, there's another pretty major drawback. When it switches from A' to A or C' to C, the screen flickers for a moment, at least on my current test device.

编辑:现在自己实现了这个,还有另一个非常大的缺点。当它从 A' 切换到 A 或 C' 到 C 时,屏幕会闪烁片刻,至少在我当前的测试设备上是这样。

回答by homi3kh

I would create a dummy page at the end of the ViewPager. Then I use this code to go to the first page when the user scroll to the dummy page. I know it's far from perfect :D

我会在 ViewPager 的末尾创建一个虚拟页面。然后当用户滚动到虚拟页面时,我使用此代码转到第一页。我知道这远非完美 :D

@Override
public void onPageScrolled(int position, float arg1, int arg2) {
    if (position >= NUM_PAGE-1) {
        mViewPager.setCurrentItem(0, true);
    }
}

回答by Jason Tseng

My solution is based on benkc, but first and last page scroll animation are disabled, and when pages "scrolled" to real page, scroll animation is enable again, this scheme can solve the first drawback.

我的解决方案是基于benkc,但是禁用了首尾滚动动画,当页面“滚动”到真实页面时,再次启用滚动动画,这个方案可以解决第一个缺点。

but my ViewPager.setCurrentItem(position, false)result is still have scroll animation, so i implements animation which is too fast to seen.

但我的ViewPager.setCurrentItem(position, false)结果仍然有滚动动画,所以我实现了速度太快而无法看到的动画。

the fast scrolling animation like this, don't mind the comment, just my code didn't use these method:

像这样的快速滚动动画,不要介意评论,只是我的代码没有使用这些方法:

public class FixedSpeedScroller extends Scroller {
    private int mDuration = 0;

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

    @Override
    public void startScroll(int startX, int startY, int dx, int dy, int duration) {
        super.startScroll(startX, startY, dx, dy, mDuration);
    }

    @Override
    public void startScroll(int startX, int startY, int dx, int dy) {
        super.startScroll(startX, startY, dx, dy, mDuration);
    }
}

and use this method to viewpager's activity

并使用此方法查看pager的活动

private Scroller scroller;
private void setViewPagerScroll(boolean instant) {
    try {
        Field mScroller = null;
        mScroller = ViewPager.class.getDeclaredField("mScroller");
        mScroller.setAccessible(true);
        if (scroller == null) {
            scroller = (Scroller) mScroller.get(mViewPager);
        }
        FixedSpeedScroller fss = new FixedSpeedScroller(mViewPager.getContext());
        mScroller.set(mViewPager, instant ? fss : scroller);

    } catch (NoSuchFieldException | IllegalArgumentException | IllegalAccessException e) {
        e.printStackTrace();
    }
}

and modify onPageScrollStateChanged like this, only first page or last page (i have 5 pages) would change animation to fast scrolling, otherwise has normal scrolling:

并像这样修改 onPageScrollStateChanged ,只有第一页或最后一页(我有 5 页)会将动画更改为快速滚动,否则正常滚动:

public void onPageScrollStateChanged(int state) {
    if (state == ViewPager.SCROLL_STATE_IDLE) {
        if (position == 0) {
            setViewPagerScroll(true);
            mViewPager.setCurrentItem(3);

        } else if (position == 4) {
            setViewPagerScroll(true);
            mViewPager.setCurrentItem(1);

        } else {
            setViewPagerScroll(false);
        }
    }
}

FixedSpeedScroller references is here: http://blog.csdn.net/ekeuy/article/details/12841409

FixedSpeedScroller 参考在这里:http: //blog.csdn.net/ekeuy/article/details/12841409

回答by user3669166

this should do the job without dummy pages:

这应该可以在没有虚拟页面的情况下完成工作:

private boolean isFirstOrLastPage;
private int currentPageIndex = 0;


@Override
public void onPageScrolled(int arg0, float arg1, int arg2) {
    if(currentPageIndex!=arg0){
        isFirstOrLastPage = false;
        return;
    }
    if((arg0==0 || arg0==PAGES.size()-1) && arg1 == 0 && arg2 == 0){
        if(isFirstOrLastPage){
                 //DO SOMETHING
        }else{
            isFirstOrLastPage = true;
        }
    }
}

@Override
public void onPageSelected(int arg0) {
    currentPageIndex = arg0;
}

回答by MobileMon

this works, the accepted answer no good because there is a lag when the loop happens:

这是有效的,接受的答案不好,因为循环发生时存在滞后:

 @Override
public int getCount() {
    return Integer.MAX_VALUE;
}

@Override
public CharSequence getPageTitle(int position) {
    String title = mTitleList.get(position % mActualTitleListSize);
    return title;
}

@Override
public Object instantiateItem(ViewGroup container, int position) {
    int virtualPosition = position % mActualTitleListSize;
    return super.instantiateItem(container, virtualPosition);
}

@Override
public void destroyItem(ViewGroup container, int position, Object object) {
    int virtualPosition = position % mActualTitleListSize;
    super.destroyItem(container, virtualPosition, object);
}

answer taken from here : ViewPager as a circular queue / wrapping

从这里获取的答案:ViewPager as a circle queue / wrapping