viewpager studio fragments example android android-viewpager

android - studio - onPageSelected no se activa al llamar a setCurrentItem(0)



view pager adapter android studio (8)

Tengo una actividad con un ViewPager que muestra un montón de imágenes. Cuando comienza, la posición de ViewPager se establece en función de lo que el usuario seleccionó en una actividad previa. Similar a una galería.

Quiero que se llame a onPageSelected cada vez que se selecciona una nueva página, es decir, cuando se abre la Actividad por primera vez o cuando el usuario se desliza a una página nueva.

Establecí el punto de partida así:

mPager.setCurrentItem(index);

Todo funciona, excepto cuando setCurrentItem llamado con el índice establecido en 0 ya que no se activará en la página seleccionada.

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

Entonces mi pregunta es; ¿Es esto un error, y si es así, qué puedo hacer al respecto?


En realidad, creo que esto es un ERROR. Revisé el código fuente de ViewPager y encontré el único activador de onPageSelected :

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

Arriba, el envío variable seleccionado se determina por código:

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

Y, la variable mCurItem se define e inicializa como:

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

Por lo tanto, mCurItem tiene el valor predeterminado 0. Al llamar a setCurrentItem (0), dispatchSelected será falso y onPageSelected () no se enviará.

Ahora debemos entender por qué llamar setCurrentItem (0) es un problema mientras setCurrentItem (1, o 2, 3 ...) no lo es.

Cómo resolver este problema:

  1. Copie el código de ViewPager a su propio proyecto y corríjalo:

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

    luego usa tu propio ViewPager.

  2. Como ha llamado conscientemente a setCurrentItem (0) y tiene una referencia al OnPageChangedListener, envíe el onPageSelected () solo.

  3. 听 楼下 怎么 说 ...


La siguiente solución parece funcionar para mí. es decir, obtengo una devolución de llamada en la posición 0 cuando se carga el viewpager por primera vez y para todas las selecciones posteriores, ya sea desde el desplazamiento del usuario o desde una llamada setCurrentItem (x). No he observado ningún comportamiento no deseado.

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


La solución más limpia que he encontrado hasta ahora es tomar una referencia al onPageChangeListener que configuraste en ViewPager (ya que no creo que haya un método ViewPager.getOnPageChangeListener ()), luego de haber configurado el adaptador de ViewPager , llamada:

onPageChangeListener.onPageSelected(viewPager.getCurrentItem());

Sin embargo, el fragmento para la página en el índice actual no habrá sido instanciado todavía (al menos si está usando FragmentStatePagerAdapter), por lo que es posible que deba envolverlo en un archivo ejecutable, ala:

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

Además, si dentro del controlador onPageSelected necesitas una referencia al fragmento, tendrás que hacerlo tú mismo. Utilizo una clase base abstracta para mi FragmentStatePagerAdapter que anula los métodos de creación de instancias y destrucción, y agrega / elimina los fragmentos de un SparseArray.


Ok, entonces no he podido averiguar si esto es un error (o una característica). Pero pensé en compartir cómo se vería una posible solución al problema.

Escriba la funcionalidad que desea realizar en un método en la Actividad y luego llámelo en el método onPageSelected.

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

Y luego, justo después de llamar

setCurrentItem(index);

en la actividad, agregue la siguiente instrucción if

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

No es súper bonito, pero espero que ayude a alguien :)


Puede extender ViewPager y llamar al Listener por su cuenta cuando la posición cambia de 0 a 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); } }


si no te importa la animación de la pantalla prueba

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


onPageSelected no se activa para la página que se abre primero. Para este caso, realizo manualmente todas las acciones necesarias. Además, supongo que esa llamada a onPageSelected(0) debería funcionar también.


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