我有一个带有一些视图的ViewPager。我想在最后一次右手刷之后去第一个。
我试过
@Override
public Fragment getItem(int arg0) {
int i = arg0 % fragmentList.size();
return fragmentList.get(i);
}
@Override
public int getCount() {
return fragmentList.size()+1;
}
但我收到了错误
E/AndroidRuntime(22912): java.lang.IllegalStateException: Fragment already added: RubricFragment{4136cd80 #1 id=0x7f06000c android:switcher:2131099660:0}
答案 0 :(得分:26)
一种可能性是设置这样的屏幕:
C'A B C A'
C'看起来就像C,但当你滚动到那里时,它会切换到真正的C. '看起来就像A,但当你滚动到那里时,它会切换到真正的A。
我会通过实施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);
}
}
}
请注意,这会调用setCurrentItem的替代形式并传递false
以使跳转立即发生而不是平滑滚动。
我看到了两个主要缺点。首先,在到达任一端时,用户必须让滚动在他们可以走得更远之前解决。其次,它意味着在您的第一页和最后一页中拥有所有视图的第二个副本。根据屏幕资源的大小,这可能会排除这种技术作为一种可能的解决方案。
另请注意,由于视图寻呼机不会让点击进入底层控件直到滚动结束后,因此可能没有为A'和C'片段设置clicklisteners等。
编辑:现在我自己实现了这个,还有一个相当重要的缺点。当它从A'切换到A或C'到C时,屏幕会闪烁片刻,至少在我当前的测试设备上。
答案 1 :(得分:6)
我会在ViewPager的末尾创建一个虚拟页面。 然后当用户滚动到虚拟页面时,我使用此代码转到第一页。我知道它远非完美:D
@Override
public void onPageScrolled(int position, float arg1, int arg2) {
if (position >= NUM_PAGE-1) {
mViewPager.setCurrentItem(0, true);
}
}
答案 2 :(得分:1)
我的解决方案基于benkc,但是第一页和最后一页滚动动画被禁用,当页面“滚动”到真实页面时,滚动动画再次启用,这个方案可以解决第一个缺点。
但我的ViewPager.setCurrentItem(position, false)
结果仍然有滚动动画,所以我实现的动画太快了。
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);
}
}
并将此方法用于viewpager的活动
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();
}
}
并像这样修改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引用位于:http://blog.csdn.net/ekeuy/article/details/12841409
答案 3 :(得分:0)
这应该可以完成没有虚拟页面的工作:
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;
}
答案 4 :(得分:0)
这是有效的,接受的答案不好,因为循环发生时存在延迟:
@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);
}