onPageSelected не запускается при вызове setCurrentItem(0)


у меня есть деятельность с ViewPager, который отображает кучу фотографий. Когда он запускается, позиция ViewPager устанавливается на основе того, что пользователь выбрал в предыдущем действии. Похоже на галерею.

Я хочу, чтобы onPageSelected вызывался каждый раз при выборе новой страницы, т. е. при первом открытии действия или при переходе пользователя на новую страницу.

Я установил начальную точку следующим образом:

 mPager.setCurrentItem(index);

все работает, кроме тех случаев, когда setCurrentItem вызывается с индексом, установленным в 0, так как это не вызовет onPageSelected.

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

Итак, мой вопрос: это ошибка, и если да, то что я могу с этим поделать?

10 56

10 ответов:

самое чистое решение, которое я нашел для этого до сих пор, - это ссылка на onPageChangeListener, которую вы установили на ViewPager (так как я не думаю, что есть ViewPager.getOnPageChangeListener () метод), а затем после установки адаптера ViewPager, вызовите:

onPageChangeListener.onPageSelected(viewPager.getCurrentItem());

однако фрагмент для страницы с текущим индексом еще не был создан (по крайней мере, если вы используете FragmentStatePagerAdapter), поэтому вам может потребоваться обернуть его в runnable, Ала:

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

кроме того, если в обработчике onPageSelected вам нужна ссылка на фрагмент, вам придется сделать это самостоятельно. Я использую абстрактный базовый класс для моего FragmentStatePagerAdapter, который переопределяет методы instantiate и destroy и добавляет/удаляет фрагменты из SparseArray.

хорошо, поэтому я не смог выяснить, является ли это ошибкой (или функцией). Но я подумал, что поделюсь тем, как может выглядеть возможное решение проблемы..

напишите функциональность, которую вы хотите выполнить в методе в действии, а затем вызовите ее в методе onPageSelected.

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

а потом сразу после звонка

setCurrentItem(index);

в упражнении добавьте следующий оператор if

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

это не очень красиво, но я надеюсь, что это кому-то помогает:)

на самом деле я думаю, что это ошибка. Я проверил исходный код 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, или 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) тоже должен работать.

следующее решение, кажется, работает для меня. т. е. я получаю обратный вызов в позиции 0 при первой загрузке viewpager и для всех последующих выборов либо из прокрутки пользователя, либо из вызова setCurrentItem(x). Я не наблюдал никакого нежелательного поведения.

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

Вы можете продлить ViewPager и вызвать слушателя самостоятельно, когда позиция изменяется от 0 до 0

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.
        }

самым простым решением будет использование функции, например,

    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) {
        //...
    }

Если ViewPager находится во фрагменте, в методе onViewCreated вызовите mPager.setOnPageChangeListener(это)

Если вам все равно анимация экрана попробуйте

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