with viewpager studio fragments example android android-viewpager position adapter

viewpager - view pager adapter android studio



Adaptador de Viewpager getItem siempre pidió el índice 0 y 1 (4)

Sí, este es el comportamiento normal de ViewPager, porque siempre intentará mantenerse por delante del usuario al mostrar pestañas que limitan con el área de dibujo. Personalmente, no recomiendo crear un ViewPager personalizado, ya que casi seguramente romperá la funcionalidad a menos que realmente sepa lo que está haciendo. Su clase de adaptador debería verse más o menos así:

public class YourCustomPagerAdapter extends FragmentStatePagerAdapter { private List<Fragment> fragmentList = new ArrayList<>(); private List<String> titleList = new ArrayList<>(); public WizardPagerAdapter(FragmentManager fm) { super(fm); } public void addFragment(Fragment fragment, String title) { fragmentList.add(fragment); titleList.add(title); } @Override public Fragment getItem(int position) { return fragmentList.get(position); } @Override public CharSequence getPageTitle(int position) { super.getPageTitle(position); return titleList.get(position); } @Override public int getCount() { return fragmentList.size(); } }

y deberías agregar tus fragmentos como tales:

@Override public void onCreate(Bundle savedInstanceState) { ... YourCustomPagerAdapter adapter = new YourCustomPagerAdapter (getSupportFragmentManager()); adapter.addFragment(FragmentOne.newInstance(), "Frag 1"); adapter.addFragment(FragmentTwo.newInstance(), "Frag 2"); viewPager.setAdapter(adapter); ... }

Me preguntaba si es el comportamiento normal de viewpager y su adaptador llamar siempre al método getItem() para el índice 0 y 1, incluso si configuro inmediatamente una posición actual.

Aquí está mi código:

mNewsPagerAdapter = new NewsDetailPagerAdapter(getChildFragmentManager()); mNewsPagerAdapter.updateNewsList(news); mViewPager = (ViewPager) mView.findViewById(R.id.horizontal_view_pager); mViewPager.setPageMargin(2); mViewPager.setPageMarginDrawable(R.color.black); mViewPager.setAdapter(mNewsPagerAdapter); mViewPager.setCurrentItem(mCurrentPositionPager, false);

Si cambio de mi actividad general a mi actividad detallada con este viewpager , el adaptador siempre llama al método getItem() para la posición 0 y 1 y luego al método getItem() para la posición de mOriginalPosition y sus vecinos. Me preguntaba si este es el comportamiento correcto o si me perdí algo para implementarlo de manera correcta. Gracias por tu ayuda :)

Editar: Agregué mi código de adaptador

public class NewsDetailPagerAdapter extends FragmentStatePagerAdapter { private SparseArray<Fragment> mPageReferenceMap = new SparseArray<Fragment>(); private ArrayList<News> mNewsList; public NewsDetailPagerAdapter(FragmentManager fm) { super(fm); } /** * Setzt die neuen News. **/ public void updateNewsList(ArrayList<News> list) { mNewsList = list; } @Override public Fragment getItem(int position) { Log.d("debug", "getItem position:" + position); News newsItem = mNewsList.get(position); NavigationFragment fragment = new NavigationFragment(); mPageReferenceMap.put(position, fragment); return fragment; } @Override public int getCount() { return mNewsList.size(); } @Override public int getItemPosition(Object object) { return POSITION_NONE; } public Fragment getFragment(int position) { return mPageReferenceMap.get(position); }

}


Creo que el error es el adaptador:

/** * Setzt die neuen News. **/ public void updateNewsList(ArrayList<News> list) { //mNewsList = list; mNewsList.clear(); mNewsList.addAll(list); /** * Notifies the attached observers that the underlying data has been changed * and any View reflecting the data set should refresh itself. */ this.notifyDataSetChanged(); }

Razón de error: esta lista es entidad diferida para ese adaptador.


Es normal (e inteligente en mi opinión). La clase ViewPager tiene una propiedad llamada mOffscreenPageLimit con un valor predeterminado de 1. Este número determina cuántas páginas a la izquierda y a la derecha de la página actual cargará Viewpager. Por ejemplo, tiene 10 páginas, la posición actual es 5 y mOffcreenPageLimit es 1, la página en la posición 4 y 6 se cargará.

Puede cambiar esta propiedad llamando a este método

viewpager. setOffscreenPageLimit(int)

Si pasa un número entero menor que 1, no tiene efecto.


En realidad, este es el comportamiento normale. De hecho, en la medida en que asocie ViewPager con el adaptador, el adaptador crea el primer diseño visibile (índice 0) y el siguiente (índice 1). Esto se hace de forma predeterminada en el "setAdapter". Luego, cuando establece una posición diferente, el adaptador instanciará el fragmento en el índice seleccionado, el anterior y el siguiente.

Este es el código setAdapter de ViewPager habitual:

public void setAdapter(PagerAdapter adapter) { if (mAdapter != null) { mAdapter.setViewPagerObserver(null); mAdapter.startUpdate(this); for (int i = 0; i < mItems.size(); i++) { final ItemInfo ii = mItems.get(i); mAdapter.destroyItem(this, ii.position, ii.object); } mAdapter.finishUpdate(this); mItems.clear(); removeNonDecorViews(); mCurItem = 0; scrollTo(0, 0); } final PagerAdapter oldAdapter = mAdapter; mAdapter = adapter; mExpectedAdapterCount = 0; if (mAdapter != null) { if (mObserver == null) { mObserver = new PagerObserver(); } mAdapter.setViewPagerObserver(mObserver); mPopulatePending = false; final boolean wasFirstLayout = mFirstLayout; mFirstLayout = true; mExpectedAdapterCount = mAdapter.getCount(); if (mRestoredCurItem >= 0) { mAdapter.restoreState(mRestoredAdapterState, mRestoredClassLoader); setCurrentItemInternal(mRestoredCurItem, false, true); mRestoredCurItem = -1; mRestoredAdapterState = null; mRestoredClassLoader = null; } else if (!wasFirstLayout) { populate(); } else { requestLayout(); } } if (mAdapterChangeListener != null && oldAdapter != adapter) { mAdapterChangeListener.onAdapterChanged(oldAdapter, adapter); } }

Para cambiar el comportamiento de ViewPager, puede ampliar el clásico ViewPager anulando el método setAdapter y establecer mCurrItem en la posición deseada.

Espero que haya ayudado

Editar:

Después de diferentes pruebas, encontramos una solución.

Si el adaptador ViewPager se establece después de que el diseño de ViewPager se vuelva visible, los elementos 0 y 1 se cargan. Si desea evitar este comportamiento pero no puede configurar el adaptador antes de que el diseño se vuelva visible (porque está esperando datos), entonces puede usar esta solución alternativa:

1) Establezca la visibilidad de ViewPager inicialmente en GONE

2) Después de recibir todos los datos, actualiza el adaptador y establece el valor actual del artículo

3) Finalmente configura la visibilidad de ViewPager en VISIBLE

Aquí puedes encontrar un ejemplo:

@Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { View v = inflater.inflate(R.layout.detail_overview_fragment, container, false); final int position = getArguments().getInt("position"); final ViewPager viewPager = (ViewPager) v.findViewById(R.id.viewpager); viewPager.setVisibility(View.GONE); Handler handler = new Handler(); handler.postDelayed(new Runnable() { @Override public void run() { viewPager.setAdapter(new PagerAdapter(getChildFragmentManager())); viewPager.setCurrentItem(position); viewPager.setVisibility(View.VISIBLE); } },5000); return v; }