studio recyclerview hacer como android listview android-fragments android-viewpager swiperefreshlayout

android - recyclerview - Instantánea congelada de la lista procesada con SwipeRefreshLayout en ViewPager



refresh layout android studio (2)

Considere una actividad de Android que es la subclase de android.support.v4.app.FragmentActivity . Contiene varias aplicaciones administradas por FragmentStatePagerAdapter . Cada página contiene un ListView envuelto por android.support.v4.widget.SwipeRefreshLayout . La siguiente captura de pantalla muestra el estado inicial de esta actividad.

Ahora, deslizo hacia abajo para actualizar la lista en la página 0. Aparece la animación de actualización. Ahora, deslicemos hacia la derecha en la página 2 y luego regresemos a la página 0.

La animación de actualización aún está visible. Esto me parece extraño ya que la página 0 fue destruida y creada nuevamente. Además, si deslizo hacia arriba (intentando desplazarme hasta el final de la lista en la página 0), se representa una capa extraña sobre la página que parece contener el estado anterior de la página desde el momento en que se destruyó.

No tengo idea de por qué sucede esto y cómo solucionarlo. Gracias por cualquier ayuda.

Aquí está el código fuente de una aplicación mínima que consta de 3 archivos de diseño, una clase de actividad, una clase de fragmento, un archivo de manifiesto y un script de compilación.

swipeandroid / src / main / res / layout / service_schedule_activity.xml

<?xml version="1.0" encoding="utf-8"?> <android.support.v4.view.ViewPager xmlns:android="http://schemas.android.com/apk/res/android" android:id="@+id/servicePager" android:layout_width="match_parent" android:layout_height="match_parent"> <android.support.v4.view.PagerTabStrip android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_gravity="top"/> </android.support.v4.view.ViewPager>

swipeandroid / src / main / res / layout / service_schedule_tab_fragment.xml

<?xml version="1.0" encoding="utf-8"?> <android.support.v4.widget.SwipeRefreshLayout xmlns:android="http://schemas.android.com/apk/res/android" android:id="@+id/serviceRefreshLayout" android:orientation="vertical" android:layout_width="match_parent" android:layout_height="match_parent"> <ListView android:id="@+id/timeSlots" android:layout_width="match_parent" android:layout_height="match_parent"/> </android.support.v4.widget.SwipeRefreshLayout>

swipeandroid / src / main / res / layout / service_schedule_row.xml

<?xml version="1.0" encoding="utf-8"?> <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="wrap_content"> <TextView android:id="@+id/time" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_alignParentLeft="true" android:layout_alignParentTop="true"/> </RelativeLayout>

swipeandroid / src / main / java / com / swipetest / ServiceScheduleActivity.java

package com.swipetest; import android.os.Bundle; import android.support.v4.app.Fragment; import android.support.v4.app.FragmentActivity; import android.support.v4.app.FragmentStatePagerAdapter; import android.support.v4.view.ViewPager; public class ServiceScheduleActivity extends FragmentActivity { @Override protected void onCreate(final Bundle inState) { // call super class super.onCreate(inState); // set content setContentView(R.layout.service_schedule_activity); // set up service pager ((ViewPager) findViewById(R.id.servicePager)).setAdapter(new ServiceFragmentPagerAdapter()); } private class ServiceFragmentPagerAdapter extends FragmentStatePagerAdapter { public ServiceFragmentPagerAdapter() { super(getSupportFragmentManager()); } @Override public int getCount() { return 5; } @Override public Fragment getItem(final int position) { return ServiceScheduleTabFragment.newInstance(position); } @Override public CharSequence getPageTitle(final int position) { return String.format("page %d", position); } } }

swipeandroid / src / main / java / com / swipetest / ServiceScheduleTabFragment.java

package com.swipetest; import android.os.Bundle; import android.support.v4.app.Fragment; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.widget.BaseAdapter; import android.widget.ListView; import android.widget.TextView; public class ServiceScheduleTabFragment extends Fragment { private static final String TAB_POSITION_ARGUMENT = "tabPosition"; public static ServiceScheduleTabFragment newInstance(final int tabPosition) { // prepare arguments final Bundle arguments = new Bundle(); arguments.putInt(TAB_POSITION_ARGUMENT, tabPosition); // create fragment final ServiceScheduleTabFragment fragment = new ServiceScheduleTabFragment(); fragment.setArguments(arguments); return fragment; } @Override public View onCreateView(final LayoutInflater layoutInflater, final ViewGroup parent, final Bundle inState) { // create fragment root view final View rootView = layoutInflater.inflate(R.layout.service_schedule_tab_fragment, parent, false); // initialize time slot list view final ListView timeSlotListView = (ListView) rootView.findViewById(R.id.timeSlots); timeSlotListView.setAdapter(new TimeSlotListAdapter()); // return fragment root view return rootView; } private int getTabPosition() { return getArguments().getInt(TAB_POSITION_ARGUMENT); } private static class TimeSlotRowViewHolder { private final TextView timeView; public TimeSlotRowViewHolder(final View rowView) { timeView = (TextView) rowView.findViewById(R.id.time); } public TextView getTimeView() { return timeView; } } private class TimeSlotListAdapter extends BaseAdapter { @Override public int getCount() { return 80; } @Override public Object getItem(final int position) { return position; } @Override public long getItemId(final int position) { return position; } @Override public View getView(final int position, final View convertView, final ViewGroup parent) { // reuse or create row view final View rowView; if (convertView != null) { rowView = convertView; } else { rowView = LayoutInflater.from(getContext()).inflate(R.layout.service_schedule_row, parent, false); rowView.setTag(new TimeSlotRowViewHolder(rowView)); } // fill data final TimeSlotRowViewHolder rowViewHolder = (TimeSlotRowViewHolder) rowView.getTag(); rowViewHolder.getTimeView().setText(String.format("tab %d, row %d", getTabPosition(), position)); return rowView; } } }

swipeandroid / src / main / AndroidManifest.xml

<?xml version="1.0" encoding="utf-8"?> <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.swipetest" android:versionCode="1" android:versionName="1.0"> <uses-sdk android:minSdkVersion="16" android:targetSdkVersion="23"/> <application android:name="android.app.Application" android:label="Swipe Test" android:allowBackup="false"> <activity android:name="com.swipetest.ServiceScheduleActivity"> <intent-filter> <action android:name="android.intent.action.MAIN"/> <category android:name="android.intent.category.LAUNCHER"/> </intent-filter> </activity> </application> </manifest>

swipeandroid / build.gradle

buildscript { repositories { mavenCentral() } dependencies { classpath ''com.android.tools.build:gradle:1.5.0'' } } apply plugin: ''com.android.application'' repositories { mavenCentral() } dependencies { compile "com.android.support:support-v4:23.1.1" } android { compileSdkVersion 23 buildToolsVersion "23.0.2" buildTypes { debug { debuggable true minifyEnabled false } } }


Intente borrar la lista y luego cargue los datos nuevos en la actualización de barrido.

Como se menciona en el comentario.


Finalmente, descubrí una solución que es muy simple de implementar y soluciona el problema.

Simplemente SwipeRefreshLayout FrameLayout por ejemplo, mediante FrameLayout . Parece que a ViewPager no le gusta que SwipeRefreshLayout sea ​​la raíz de la jerarquía de vistas de un fragmento de página.

De todos modos, este problema parece un error en la Biblioteca de soporte de Android. Ver https://code.google.com/p/android/issues/detail?id=194957

También probé otras soluciones alternativas que no funcionan:

  • Reemplazar FragmentStatePagerAdapter por `FragmentPagerAdapter no ayudará.
  • Llamar a mySwipeRefreshLayout.setRefreshing(false) en onPause no ayudará.
  • Modificar el FragmentStatePagerAdapter para que no recuerde los estados de las páginas destruidas no ayudará.

Las siguientes soluciones alternativas pueden ayudar de alguna manera, pero prefiero el SwipeRefreshLayout sugerido de SwipeRefreshLayout todos modos:

  • Borrar los datos (para que ListView no contenga filas) en SwipeRefreshLayout.OnRefreshListener#onRefresh() solo ayuda si ListView tiene fondo transparente. La instantánea no deseada probablemente aún se muestra en la primera página, pero es completamente transparente.
  • No puede permitir la paginación para el momento de la animación de actualización. Sin embargo, esto requiere un poco de esfuerzo ya que debe subclasificar tanto ViewPager como PagerTabStrip y evitar eventos de IU apropiados en sus subclases.
  • Por supuesto, puede evitar el uso de SwipeRefreshLayout en ViewPager completo, pero esto no parece ser necesario.