68

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

我希望每次选择新页面时都会调用 onPageSelected,即首次打开 Activity 或用户滑动到新页面时。

我这样设置起点:

 mPager.setCurrentItem(index);

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

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

所以我的问题是;这是一个错误,如果是,我该怎么办?

4

10 回答 10

89

到目前为止,我发现的最干净的解决方案是引用您在 ViewPager 上设置的 onPageChangeListener(因为我认为没有 ViewPager.getOnPageChangeListener() 方法),然后在设置 ViewPager 的适配器之后, 称呼:

onPageChangeListener.onPageSelected(viewPager.getCurrentItem());

但是,当前索引处的页面片段还没有被实例化(至少如果你使用 FragmentStatePagerAdapter),所以你可能需要将它包装在一个可运行的文件中,ala:

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

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

于 2013-11-29T19:10:13.613 回答
35

好的,所以我无法弄清楚这是否是错误(或功能)。但我想我会分享解决问题的可能方法。

在 Activity 的方法中编写您希望执行的功能,然后在 onPageSelected 方法中调用它。

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

然后在打电话之后

setCurrentItem(index);

在Activity中,添加如下if语句

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

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

于 2012-08-22T09:43:47.387 回答
25

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

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

上面,变量dispatchSelected由代码确定:

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

并且,变量mCurItem被定义和初始化为:

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

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

现在我们应该明白为什么调用 setCurrentItem(0) 是一个问题,而 setCurrentItem(1, or 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. 听楼下怎么说...

于 2013-07-17T08:18:12.793 回答
3

以下解决方案似乎对我有用。即,当第一次加载 viewpager 以及来自用户滚动或 setCurrentItem(x) 调用的所有后续选择时,我在位置 0 处获得回调。我没有观察到任何不良行为。

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) {}
        });
于 2016-09-22T22:59:20.380 回答
0

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

于 2012-08-03T11:47:58.510 回答
0

ViewPager当位置从 0 更改为 0 时,您可以自行扩展和调用 Listener

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);
        }

}
于 2013-07-16T09:14:29.833 回答
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.
        }
于 2017-10-16T13:39:56.283 回答
0

最简单的解决方案是使用函数,例如

    viewpager.addOnPageChangeListener(new ViewPager.OnPageChangeListener() {

        @Override
        public void onPageScrollStateChanged(int state) {}

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

        @Override
        public void onPageSelected(int position) {
            onPage(position);
        }
    });

    // call first time
    onPage(0); 

    private void onPage(int position) {
        //...
    }
于 2018-05-04T16:07:15.050 回答
0

If the ViewPager is in a fragment, in the onViewCreated method, call mPager.setOnPageChangeListener(this)

于 2018-05-15T00:10:32.127 回答
-5

如果你不关心屏幕动画试试

pager.setCurrentItem(1);
pager.setCurrentItem(0);
于 2015-02-04T10:25:32.357 回答