调用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 …)不是。
如何解决这个问题呢:
-
将ViewPager的代码复制到您自己的项目并修复它:
from final boolean dispatchSelected = mCurItem != item; //the old line to final boolean dispatchSelected = mCurItem != item || mFirstLayout; //the new line
然后使用您自己的ViewPager。
-
由于您有意识地调用了setCurrentItem(0),并有一个OnPageChangedListener的引用,所以请自己调度onPageSelected()。
-
听楼下怎么说…
对于首先打开的页面,不会触发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);