ViewPager在当前页不是第一页时,屏幕旋转后偏移数据错误。

7

应用程序结构:

我的应用程序只有一个FragmentActivity,该FragmentActivity托管一个Fragment,该Fragment又托管一个ViewPagerViewPager具有一个适配器,该适配器是FragmentStatePagerAdapater的子类,并覆盖了getItem()以根据位置返回一个新的Fragment; getCount()设置为始终返回2。

问题:

应用程序在以下两种情况下工作得很好:当ViewPager显示第二个Fragment时发生旋转,或者在onResume()中告诉ViewPager滚动到第一页以外的页面。就我所知,这些情况是相同的。当发生其中一种事件时,滚动已停止,并且被ViewPager管理的Fragment中可见的Fragment是第二个Fragment。此时,回调函数onPageScrolled(int, float, int)的'position'参数仍为0(应为1),而'positionOffset'参数设置为1(这超出了文档中承诺的[0,1)范围)。我在ViewPager代码中进行了一些探索,发现boolean pageScrolled(int xpos)函数从使用[0,940]范围内的值(第一页为0,第二页为940)调用到使用[-940,0]范围内的值(第一个为-940,在第二个上为0)。如果ViewPager被重置以认为第二个页面是第一页,则这实际上是有意义的(有点),尽管这不是我想要的。

一些代码:

ViewPagerFragment(托管ViewPager)。MyViewPager只是支持库ViewPager的复制/粘贴;我想打印一些来自其私有方法的数据。

public class ViewPagerFragment extends Fragment implements MyViewPager.OnPageChangeListener{

@InjectView(R.id.view_pager) MyViewPager viewPager;

@DebugLog
public ViewPagerFragment() {
    setRetainInstance(true);
}


@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
                         Bundle savedInstanceState) {
    View view = inflater.inflate(R.layout.fragment_view_pager, container, false);
    ButterKnife.inject(this,view);
    Log.d("onCreateView()","ViewPagerFragment = "+this.toString());
    return view;
}

@Override
public void onResume() {
    super.onResume();
    setupPager();
}

void setupPager(){
    if(viewPager != null) {
        if (viewPager.getAdapter() == null) {
            viewPager.setAdapter(new MyFragmentAdapter(getChildFragmentManager()));
        }
        viewPager.setOnPageChangeListener(this);
        viewPager.setPageMargin(40);
    }
}

@Override
@DebugLog
public void onDestroyView() {
    super.onDestroyView();
    viewPager.setOnPageChangeListener(null);
    ButterKnife.reset(this);
}

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

    if(positionOffset == 1f){
        Log.d("onPageScrolled","position offset == 1 and position == "+position+". That's bad!");
    } else if(position == 1){
        Log.d("onPageScrolled","position offset == "+positionOffset+" and position == 1. That's good!");
    }

}

public static class MyFragmentAdapter extends FragmentStatePagerAdapter{

    public MyFragmentAdapter(FragmentManager fm) {
        super(fm);
    }

    @Override
    @DebugLog
    public Fragment getItem(int position) {
        return PageFragment.newInstance(position);
    }

    @Override
    public int getCount() {
        return 2;
    }
}

我的问题是:“我做错了什么导致ViewPager出了问题,我该如何解决?”如果移除setRetainInstance()调用,那么显然会重置一切,但我也会失去在ViewPager中的位置。移除setRetainInstance()调用,然后使用Bundle savedInstanceState来保存ViewPager的位置也无法解决问题(正如我在帖子开头提到的)。谢谢!

为什么要使用 viewPager.setPageMargin(40); - Ultimo_m
调用setPageMargin会有问题吗?我没有任何特定的原因来调用它(除了设置边距...)。 - AlexDG
1
哇...我遇到了完全相同的问题。目前我还没有解决,但是当旋转发生时重新初始化ViewPager怎么样?我认为重新初始化可能会很麻烦,但这可能是解决方案的一部分。 - Wooseong Kim
2个回答

0
将ViewPager的onSizeChanged方法重写为以下内容:
 @Override
    protected void onSizeChanged(int w, int h, int oldw, int oldh) {
        super.onSizeChanged(w, h, oldw, oldh);
         beginFakeDrag();
        fakeDragBy(0);
        endFakeDrag();
    } 

0

在ViewPager旋转后似乎存在一个错误。

我计算了当前页面的scrollX(偏移量),当一页滚动完成时,它总是为0。

然而,在旋转后,它变成了1或X(大约是页面宽度的938~9,如果页面宽度为940)。

当设备旋转时,我在onConfigurationChanged回调中再次调用setAdapter来解决onPageScrolled的一些问题。

以下是一些代码块。 Device是我的自定义类。

public void configOnOrientationChange() {
    if (Device.isPortrait(getContext())) {
        configOnPortraitOrientation();
    } else if (Device.isLandscape(getContext())) {
        configOnLandscapeOrientation();
    }

    int currentItem = mViewPager.getCurrentItem();
    if (mPagerAdapter != null) {
        mViewPager.setAdapter(mPagerAdapter);
        mViewPager.setCurrentItem(currentItem);
    }
}

希望这能有所帮助。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接