viewpager - slide android studio
La vista del Fragmento de ViewPager se pierde cuando el Fragmento principal de ViewPager se oculta y luego se muestra (5)
No estás proporcionando suficiente información para tu problema específico, así que construí un proyecto de muestra que intenta reproducir tu problema: la aplicación tiene una actividad que contiene un fragmento ( PagerFragment
) dentro de un diseño relativo y debajo de este diseño tengo un botón que oculta y muestra arriba PagerFragment
. PagerFragment
tiene un ViewPager
y cada fragmento dentro del adaptador de buscapersonas simplemente muestra una etiqueta: este fragmento se llama DataFragment
. La lista de etiquetas se crea en la actividad primaria y se pasa a PagerFragment y luego a través de su adaptador a cada DataFragment
. El cambio de la visibilidad de PagerFragment
se realiza sin problemas y, cada vez que se vuelve visible, muestra la etiqueta mostrada anteriormente.
La clave del problema: ¡ utilice Fragment#getChildFragmentManager() cuando esté creando el adaptador viewpager y no getFragmentManager!
Tal vez puedas comparar este proyecto simple con lo que tienes y comprobar dónde están las diferencias. Así que aquí va (de arriba hacia abajo):
PagerActivity (la única actividad en el proyecto):
public class PagerActivity extends FragmentActivity {
private static final String PAGER_TAG = "PagerActivity.PAGER_TAG";
@Override
protected void onCreate(Bundle savedInstance) {
super.onCreate(savedInstance);
setContentView(R.layout.pager_activity);
if (savedInstance == null) {
PagerFragment frag = PagerFragment.newInstance(buildPagerData());
FragmentManager fm = getSupportFragmentManager();
fm.beginTransaction().add(R.id.layout_fragments, frag, PAGER_TAG).commit();
}
findViewById(R.id.btnFragments).setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
changeFragmentVisibility();
}
});
}
private List<String> buildPagerData() {
ArrayList<String> pagerData = new ArrayList<String>();
pagerData.add("Robert de Niro");
pagerData.add("John Smith");
pagerData.add("Valerie Irons");
pagerData.add("Metallica");
pagerData.add("Rammstein");
pagerData.add("Zinedine Zidane");
pagerData.add("Ronaldo da Lima");
return pagerData;
}
protected void changeFragmentVisibility() {
Fragment frag = getSupportFragmentManager().findFragmentByTag(PAGER_TAG);
if (frag == null) {
Toast.makeText(this, "No PAGER fragment found", Toast.LENGTH_SHORT).show();
return;
}
boolean visible = frag.isVisible();
Log.d("APSampler", "Pager fragment visibility: " + visible);
FragmentTransaction ft = getSupportFragmentManager().beginTransaction();
if (visible) {
ft.hide(frag);
} else {
ft.show(frag);
}
ft.commit();
getSupportFragmentManager().executePendingTransactions();
}
}
su archivo de diseño pager_activity.xml
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:padding="4dp" >
<Button
android:id="@+id/btnFragments"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:layout_centerHorizontal="true"
android:text="Hide/Show fragments" />
<RelativeLayout
android:id="@+id/layout_fragments"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_above="@+id/btnFragments"
android:layout_marginBottom="4dp" >
</RelativeLayout>
</RelativeLayout>
Observe que estoy agregando el PagerFragment
cuando la actividad se muestra por primera vez, y la clase PagerFragment
:
public class PagerFragment extends Fragment {
private static final String DATA_ARGS_KEY = "PagerFragment.DATA_ARGS_KEY";
private List<String> data;
private ViewPager pagerData;
public static PagerFragment newInstance(List<String> data) {
PagerFragment pagerFragment = new PagerFragment();
Bundle args = new Bundle();
ArrayList<String> argsValue = new ArrayList<String>(data);
args.putStringArrayList(DATA_ARGS_KEY, argsValue);
pagerFragment.setArguments(args);
return pagerFragment;
}
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
data = getArguments().getStringArrayList(DATA_ARGS_KEY);
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
return inflater.inflate(R.layout.pager_fragment, container, false);
}
@Override
public void onViewCreated(View view, Bundle savedInstanceState) {
pagerData = (ViewPager) view.findViewById(R.id.pager_data);
setupPagerData();
}
private void setupPagerData() {
PagerAdapter adapter = new LocalPagerAdapter(getChildFragmentManager(), data);
pagerData.setAdapter(adapter);
}
}
su diseño (solo el ViewPager que toma tamaño completo):
<android.support.v4.view.ViewPager xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/pager_data"
android:layout_width="match_parent"
android:layout_height="match_parent" />
y su adaptador:
public class LocalPagerAdapter extends FragmentStatePagerAdapter {
private List<String> pagerData;
public LocalPagerAdapter(FragmentManager fm, List<String> pagerData) {
super(fm);
this.pagerData = pagerData;
}
@Override
public Fragment getItem(int position) {
return DataFragment.newInstance(pagerData.get(position));
}
@Override
public int getCount() {
return pagerData.size();
}
}
Este adaptador crea un DataFragment
para cada página:
public class DataFragment extends Fragment {
private static final String DATA_ARG_KEY = "DataFragment.DATA_ARG_KEY";
private String localData;
public static DataFragment newInstance(String data) {
DataFragment df = new DataFragment();
Bundle args = new Bundle();
args.putString(DATA_ARG_KEY, data);
df.setArguments(args);
return df;
}
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
localData = getArguments().getString(DATA_ARG_KEY);
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
return inflater.inflate(R.layout.data_fragment, container, false);
}
@Override
public void onViewCreated(View view, Bundle savedInstanceState) {
view.findViewById(R.id.btn_page_action).setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
Toast.makeText(getActivity(), localData, Toast.LENGTH_SHORT).show();
}
});
((TextView) view.findViewById(R.id.txt_label)).setText(localData);
}
}
y el diseño de DataFragment
:
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:padding="4dp" >
<Button
android:id="@+id/btn_page_action"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:layout_centerHorizontal="true"
android:text="Interogate" />
<TextView
android:id="@+id/txt_label"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerInParent="true"
android:textAppearance="?android:attr/textAppearanceLarge" />
</RelativeLayout>
¡Disfruta la codificación!
He estado viendo un comportamiento extraño con mi ViewPager junto con mi propio FragmentStatePagerAdapter.
La jerarquía de mi vista es así:
-> (1) Fragment root view (RelativeLayout)
-> (2) ViewPager
-> (3) ViewPager''s current fragment view
Cuando el Fragmento que es responsable de la vista de raíz Fragmento (1) se oculta (usando .hide () en una transacción de fragmento) y luego se muestra (con .show ()), la vista de fragmento que se mostraba actualmente en ViewPager (3 ) se vuelve nulo, aunque el fragmento aún existe. Básicamente, mi ViewPager se vuelve completamente en blanco / transparente.
La única forma que he encontrado para solucionar esto es llamar
int current = myViewPager.getCurrentItem();
myViewPager.setAdapter(myAdapter);
myViewPager.setCurrentItem(current);
después de que se muestre el fragmento principal. Esto de alguna manera activa las vistas para ser recreadas y aparecer en la pantalla. Desafortunadamente, esto ocasionalmente ocasiona excepciones relacionadas con el adaptador de buscapersonas que llama a unregisterDataSetObserver()
dos veces en un viejo observador.
¿Hay una mejor manera de hacer esto? Creo que lo que estoy preguntando es:
¿Por qué mis vistas de fragmento dentro de mi ViewPager se destruyen cuando el fragmento principal de ViewPager está oculto?
Actualización: esto también ocurre cuando la aplicación se "minimiza" y luego se "restaura" (presionando la tecla de acción local y luego regresando).
Por solicitud, aquí está mi clase de adaptador de buscapersonas:
public class MyInfoSlidePagerAdapter extends FragmentStatePagerAdapter {
private ArrayList<MyInfo> infos = new ArrayList<MyInfo>();
public MyInfoSlidePagerAdapter (FragmentManager fm) {
super(fm);
}
public MyInfoSlidePagerAdapter (FragmentManager fm, MyInfo[] newInfos) {
super(fm);
setInfos(newInfos);
}
@Override
public int getItemPosition(Object object) {
int position = infos.indexOf(((MyInfoDetailsFragment)object).getMyInfo());
return position > 0 ? position : POSITION_NONE;
}
@Override
public CharSequence getPageTitle(int position) {
return infos.get(position).getName();
}
@Override
public Fragment getItem(int i) {
return infos.size() > 0 ? MyInfoDetailsFragment.getNewInstance(infos.get(i)) : null;
}
@Override
public int getCount() {
return infos.size();
}
public Location getMyInfoAtPosition(int i) {
return infos.get(i);
}
public void setInfos(MyInfo[] newInfos) {
infos = new ArrayList<MyInfo>(Arrays.asList(newInfos));
}
public int getPositionOfMyInfo(MyInfo info) {
return infos.indexOf(info);
}
}
He cambiado el nombre de algunas variables, pero aparte de eso, es exactamente lo que tengo.
Para mí cambié a getChildFragmentManager()
lugar de getFragmentManager()
y funciona bien. Ex:
pagerAdapt = new PagerAdapt(getChildFragmentManager());
View Pager es bastante firme en mantener sus Fragmentos frescos siempre y así optimizar el rendimiento al liberar memoria cuando no se usa un fragmento. Claramente, ese es un rasgo útil válido en un sistema móvil. Pero debido a esta desasignación persistente de recursos, el fragmento se crea cada vez que se enfoca.
mViewPager.setOffscreenPageLimit(NUMBEROFFRAGMENTSCREENS);
Aquí está la mViewPager.setOffscreenPageLimit(5)
este Old Post tiene una solución interesante para su problema. Consulte
Yo tuve el mismo problema. Mi aplicación (FragmentActivity) tiene un buscapersonas (ViewPager) con 3 framgents. Al deslizar entre los fragmentos, se destruyen y se vuelven a crear todo el tiempo. En realidad, no presenta ningún problema de funcionalidad (espere cursores no cerrados), pero también me preguntaba sobre esta cuestión.
No sé si hay una solución alternativa para cambiar el comportamiento de ViewPager, pero sugiero tener un objeto de configuración (quizás una estática myViewPager
) y antes de destruir guarde su objeto myViewPager
en el objeto de configuración.
public class App extends FragmentActivity {
static MyData data;
@Override
protected void onCreate(Bundle savedInstanceState) {
data = (MyData) getLastCustomNonConfigurationInstance();
if (data == null) {
data = new MyData();
data.savedViewPager = myViewPager;
} else {
myViewPager = data.savedViewPager;
}
}
@Override
public Object onRetainCustomNonConfigurationInstance() {
Log.d("onRetainCustomNonConfigurationInstance", "Configuration call");
return data;
}
}
public class MyData {
public ViewPager savedViewPager;
}
De esta forma, puede guardar la referencia al objeto que no se destruirá, por lo tanto, se hace referencia a él y puede volver a cargar todos sus objetos cruciales.
¡Espero que encuentres útil mi sugerencia!
tal vez ayude a mViewPager.setOffscreenPageLimit(5)
Establezca el número de páginas que deben conservarse en cualquier lado de la página actual en la jerarquía de vistas en un estado inactivo. Las páginas más allá de este límite se recrearán desde el adaptador cuando sea necesario.
Esto se ofrece como una optimización. Si sabe de antemano el número de páginas que necesitará para admitir o tiene instalados mecanismos de carga diferida en sus páginas, ajustar esta configuración puede tener beneficios en la suavidad percibida de las animaciones e interacciones de búsqueda. Si tiene un pequeño número de páginas (3-4) que puede mantener activo de una vez, se gastará menos tiempo en el diseño de los subárboles de vista recién creados a medida que el usuario va y viene.
Debe mantener este límite bajo, especialmente si sus páginas tienen diseños complejos. Esta configuración predeterminada es 1.