调用setCurrentItem(0)时,onPageSelected不会被触发

我有一个ViewPager活动,显示一堆图片。 当它启动时,ViewPager的位置是根据用户在之前的活动中select的内容设置的。 类似于一个画廊。

我希望每次select一个新页面时,即在第一次打开活动或用户滑动到新页面时,都会调用onPageSelected。

我设定的起点是这样的:

mPager.setCurrentItem(index); 

一切正常,除非setCurrentItem调用与索引设置为0,因为这将不会触发onPageSelected。

 mPager.setOnPageChangeListener(new OnPageChangeListener() { @Override public void onPageSelected(int index) { Log.d(TAG, "onPageSelected " + index); } ... } 

所以我的问题是, 这是一个错误,如果是的话,我能做些什么呢?

到目前为止,我发现的最干净的解决scheme是引用您在ViewPager上设置的onPageChangeListener(因为我不认为有ViewPager.getOnPageChangeListener()方法),那么在设置ViewPager的适配器,电话:

 onPageChangeListener.onPageSelected(viewPager.getCurrentItem()); 

但是,当前索引处页面的片段不会被实例化(至less如果您使用的是FragmentStatePagerAdapter),所以您可能需要将其包装在可运行的ala:

 viewPager.post(new Runnable(){ @Override public void run() { onPageChangeListener.onPageSelected(viewPager.getCurrentItem()); } }); 

此外,如果在onPageSelected处理程序中需要对片段的引用,则必须自己执行此操作。 我为我的FragmentStatePagerAdapter使用抽象基类,它重写实例化和销毁方法,并从SparseArray中添加/删除这些片段。

好的,所以我一直无法弄清楚这是一个错误(或一个function)。 但我想我会分享如何解决这个问题的可能的解决scheme..

在Activity的方法中写入你希望执行的function,然后在onPageSelected方法中调用它。

 mPager.setOnPageChangeListener(new OnPageChangeListener() { @Override public void onPageSelected(int index) { myOnPageSelectedLogic(index); } ... } 

然后在打电话之后

 setCurrentItem(index); 

在Activity中添加下面的if语句

 if(index == 0) { myOnPageSelectedLogic(0); } 

这不是超级漂亮,但我希望它可以帮助一个人:)

其实我觉得这是一个BUG。 我检查了ViewPager的源代码,发现onPageSelected的唯一触发器:

 if (dispatchSelected && mOnPageChangeListener != null) { mOnPageChangeListener.onPageSelected(item); } 

以上,variablesdispatchSelected由代码确定:

 final boolean dispatchSelected = mCurItem != item; //item is what you passed to setCurrentItem(item) 

而且,variablesmCurItem被定义和初始化为:

 private int mCurItem; // Index of currently displayed page. 

所以mCurItem默认为0.当调用setCurrentItem(0)时, dispatchSelected将为false,因此onPageSelected()不会被调度。

现在我们应该明白为什么调用setCurrentItem(0)是一个问题,而setCurrentItem(1,或2,3 …)不是。

如何解决这个问题呢:

  1. 将ViewPager的代码复制到您自己的项目并修复它:

     from final boolean dispatchSelected = mCurItem != item; //the old line to final boolean dispatchSelected = mCurItem != item || mFirstLayout; //the new line 

    然后使用您自己的ViewPager。

  2. 由于您有意识地调用了setCurrentItem(0),并有一个OnPageChangedListener的引用,所以请自己调度onPageSelected()。

  3. 听楼下怎么说…

对于首先打开的页面,不会触发onPageSelected 。 对于这种情况我手动执行所有需要的操作。 另外,我想对onPageSelected(0)调用也应该工作。

下面的解决scheme似乎为我工作。 也就是说,当viewpager第一次加载时,我会在位置0处得到一个callback,并且从用户滚动或setCurrentItem(x)调用中获得所有后续select。 我没有观察到任何不良行为。

 viewPager.addOnPageChangeListener(new ViewPager.OnPageChangeListener() { @Override public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) { if (positionOffsetPixels == 0) { //Do something on selected page at position } } @Override public void onPageSelected(int position) {} @Override public void onPageScrollStateChanged(int state) {} }); 

当位置从0更改为0时,您可以扩展ViewPager并自己调用监听器

 public class BetterViewPager extends ViewPager { public BetterViewPager(Context context, AttributeSet attrs) { super(context, attrs); } // we some the listner protected OnPageChangeListener listener; @Override public void setOnPageChangeListener(OnPageChangeListener listener) { super.setOnPageChangeListener(listener); this.listener = listener; } @Override public void setCurrentItem(int item) { // when you pass set current item to 0, // the listener won't be called so we call it on our own boolean invokeMeLater = false; if(super.getCurrentItem() == 0 && item == 0) invokeMeLater = true; super.setCurrentItem(item); if(invokeMeLater && listener != null) listener.onPageSelected(0); } } 
 public class PageChangeListener implements ViewPager.OnPageChangeListener { @Override public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) { } @Override public void onPageSelected(int position) { } @Override public void onPageScrollStateChanged(int state) { if (state == ViewPager.SCROLL_STATE_IDLE && getCurrentItem() == 0) { //this indicate viewpager finish scroll and page at position 0 is selected. } 

如果你不关心屏幕animotion尝试

 pager.setCurrentItem(1); pager.setCurrentItem(0);