Android: CollapsingToolbarLayout y SwipeRefreshLayout se atascan

Uso CollapsingToolbarLayout, RecyclerView y SwipeRefreshLayout juntos:

Xml:

<android.support.v4.widget.DrawerLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" android:id="@+id/drawer_layout" android:layout_width="match_parent" android:layout_height="match_parent" android:fitsSystemWindows="true"> <android.support.design.widget.CoordinatorLayout android:id="@+id/coordinator_layout" android:layout_width="match_parent" android:layout_height="match_parent" android:fitsSystemWindows="true"> <android.support.design.widget.AppBarLayout android:id="@+id/appbar" android:layout_width="match_parent" android:layout_height="@dimen/collapse_toolbar_height" android:fitsSystemWindows="true" android:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar"> <android.support.design.widget.CollapsingToolbarLayout android:id="@+id/collapsing_toolbar" android:layout_width="match_parent" android:layout_height="match_parent" app:contentScrim="?attr/colorPrimary" android:fitsSystemWindows="true" app:expandedTitleMarginStart="48dp" app:expandedTitleMarginEnd="64dp" app:layout_scrollFlags="scroll|exitUntilCollapsed"> <ImageView android:id="@+id/toolbar_image" android:layout_width="match_parent" android:layout_height="match_parent" android:scaleType="centerCrop" android:fitsSystemWindows="true" app:layout_collapseMode="parallax" /> <include layout="@layout/activity_main_toolbar"/> </android.support.design.widget.CollapsingToolbarLayout> </android.support.design.widget.AppBarLayout> <android.support.v4.widget.SwipeRefreshLayout android:id="@+id/swipe_container" android:layout_width="match_parent" android:layout_height="match_parent" app:layout_behavior="@string/appbar_scrolling_view_behavior"> <cz.yetanotherview.webcamviewer.app.helper.EmptyRecyclerView android:id="@+id/mainList" android:layout_width="match_parent" android:layout_height="match_parent" android:scrollbars="vertical" /> </android.support.v4.widget.SwipeRefreshLayout> <android.support.design.widget.FloatingActionButton android:id="@+id/floating_action_button" android:layout_height="wrap_content" android:layout_width="wrap_content" app:layout_anchor="@id/appbar" app:layout_anchorGravity="bottom|right|end" android:layout_margin="16dp" app:fabSize="mini" android:src="@drawable/ic_action_edit" android:onClick="assignSelectedWebCamsToCategory"/> <com.github.clans.fab.FloatingActionMenu android:id="@+id/floating_action_menu" android:layout_width="match_parent" android:layout_height="match_parent" android:layout_gravity="bottom|end" android:paddingRight="10dp" android:paddingBottom="8dp" android:paddingLeft="10dp" fab:menu_shadowColor="#37000000" fab:menu_colorNormal="#DA4336" fab:menu_colorPressed="#E75043" fab:menu_colorRipple="#99FFFFFF" fab:menu_icon="@drawable/fab_add" fab:menu_buttonSpacing="10dp" fab:menu_labels_textColor="@color/very_dark_grey" fab:menu_labels_textSize="14sp" fab:menu_labels_colorNormal="@color/white" fab:menu_labels_colorPressed="@color/next_grey" fab:menu_labels_colorRipple="#99FFFFFF" fab:menu_labels_margin="8dp" fab:menu_backgroundColor="@color/black_transparent"> <com.github.clans.fab.FloatingActionButton android:layout_width="wrap_content" android:layout_height="wrap_content" android:src="@drawable/ic_action_content_import" fab:fab_size="mini" fab:fab_label="@string/pref_import_from_server" fab:fab_colorNormal="@color/white" app:fab_colorPressed="@color/next_grey" app:fab_colorRipple="#99FFFFFF" android:onClick="showSelectionDialog"/> <com.github.clans.fab.FloatingActionButton android:layout_width="wrap_content" android:layout_height="wrap_content" android:src="@drawable/ic_action_content_manually" fab:fab_size="mini" fab:fab_label="@string/create_manually" fab:fab_colorNormal="@color/white" app:fab_colorPressed="@color/next_grey" app:fab_colorRipple="#99FFFFFF" android:onClick="showAddDialog"/> <com.github.clans.fab.FloatingActionButton android:layout_width="wrap_content" android:layout_height="wrap_content" android:src="@drawable/ic_action_content_suggestion" fab:fab_size="mini" fab:fab_label="@string/submit_suggestion" fab:fab_colorNormal="@color/white" app:fab_colorPressed="@color/next_grey" app:fab_colorRipple="#99FFFFFF" android:onClick="showSuggestionDialog"/> </com.github.clans.fab.FloatingActionMenu> </android.support.design.widget.CoordinatorLayout> <include layout="@layout/activity_main_drawer"/> </android.support.v4.widget.DrawerLayout> 

Código:

  swipeRefreshLayout = (SwipeRefreshLayout) findViewById(R.id.swipe_container); swipeRefreshLayout.setOnRefreshListener(this); 

¿Cómo permitir la acción de refresco de swipe sólo cuando se despliega la disposición de la barra de herramientas está totalmente expandido y scrollview (recyclerview) en la parte superior ? El comportamiento similar al de Google+ o de la aplicación Bandeja de entrada.

Incorrecto:

Introduzca aquí la descripción de la imagen

Bueno:

Introduzca aquí la descripción de la imagen

Actualización: este problema se ha resuelto en la última versión de la biblioteca de soporte (23.1.1+). Si está utilizando una versión anterior de la biblioteca de soporte, actualice o continúe leyendo.

Si está utilizando una versión anterior de la biblioteca de soporte, agregue un oyente de cambio de desplazamiento a su AppBarLayout para habilitar o deshabilitar su desplazamiento para actualizar el diseño en consecuencia. Código adicional disponible aquí:

https://gist.github.com/blackcj/001a90c7775765ad5212

Cambios relevantes:

 public class MainActivity extends AppCompatActivity implements AppBarLayout.OnOffsetChangedListener { ... private AppBarLayout appBarLayout; private SwipeRefreshLayout mSwipeRefreshLayout; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); ... mSwipeRefreshLayout = (SwipeRefreshLayout) findViewById(R.id.contentView); appBarLayout = (AppBarLayout) findViewById(R.id.appBarLayout); } @Override public void onOffsetChanged(AppBarLayout appBarLayout, int i) { //The Refresh must be only active when the offset is zero : mSwipeRefreshLayout.setEnabled(i == 0); } @Override protected void onResume() { super.onResume(); appBarLayout.addOnOffsetChangedListener(this); } @Override protected void onPause() { super.onPause(); appBarLayout.removeOnOffsetChangedListener(this); } } 

Finalmente,

He encontrado que SwipeRefreshLayout funciona sin ningún "hacks" de la Biblioteca de Soporte versión 23.1.1 .

Simplemente use en su diseño:

  <android.support.v4.widget.SwipeRefreshLayout android:id="@+id/swipe_refresh_layout" android:layout_width="match_parent" android:layout_height="match_parent" app:layout_behavior="@string/appbar_scrolling_view_behavior"> <android.support.v7.widget.RecyclerView android:id="@+id/recycler_view" android:layout_width="match_parent" android:layout_height="match_parent" android:scrollbars="vertical" /> </android.support.v4.widget.SwipeRefreshLayout> 

Y en código:

 SwipeRefreshLayout swipeRefreshLayout = (SwipeRefreshLayout) findViewById(R.id.swipe_refresh_layout); swipeRefreshLayout.setColorSchemeResources(R.color.green, R.color.red, R.color.yellow); swipeRefreshLayout.setOnRefreshListener(new SwipeRefreshLayout.OnRefreshListener() { @Override public void onRefresh() { //Your refresh code here } }); 

Y no se olvide de usar:

 swipeRefreshLayout.setRefreshing(false); 

Después de usar su lógica de código;)

Si lo entiendo correctamente, desea iniciar la actualización sólo después de expandir la barra de herramientas, ¿verdad? Así que primero debemos abrir el CollapsingToolbarLayout y luego empezar a refrescar. Lo conseguí con el código siguiente:

  <android.support.design.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" android:id="@+id/coordinator_layout" android:layout_width="match_parent" android:layout_height="match_parent" android:fitsSystemWindows="true"> <android.support.design.widget.AppBarLayout android:id="@+id/app_bar_layout" android:layout_width="match_parent" android:layout_height="wrap_content" android:fitsSystemWindows="true" android:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar"> <android.support.design.widget.CollapsingToolbarLayout android:id="@+id/collapsing_toolbar" android:layout_width="match_parent" android:layout_height="wrap_content" android:fitsSystemWindows="true" app:layout_scrollFlags="scroll|enterAlways|enterAlwaysCollapsed"> <LinearLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:orientation="vertical"> <!--PUT HERE WHAT EVER YOU WANT TO COLLAPSE, A TOOLBAR, ETC...--> </LinearLayout> </android.support.design.widget.CollapsingToolbarLayout> </android.support.design.widget.AppBarLayout> <android.support.v4.widget.SwipeRefreshLayout android:id="@+id/swipe_refresh_layout" android:layout_width="match_parent" android:layout_height="match_parent" app:layout_behavior="@string/appbar_scrolling_view_behavior"> <android.support.v7.widget.RecyclerView android:id="@+id/recycler_view" android:layout_width="match_parent" android:layout_height="match_parent" android:clipToPadding="false" android:fadeScrollbars="false" android:scrollbars="vertical" app:layout_behavior="@string/appbar_scrolling_view_behavior" /> </android.support.v4.widget.SwipeRefreshLayout> </android.support.design.widget.CoordinatorLayout> 

Y luego, en tu fragmento / actividad haz que implemente AppBarLayout.OnOffsetChangedListener (Ahora la actualización está habilitada cuando la barra de herramientas está completamente expandida):

  @Override public void onOffsetChanged(AppBarLayout appBarLayout, int verticalOffset) { if (collapsingToolbarLayout.getHeight() + verticalOffset < 2 * ViewCompat.getMinimumHeight(collapsingToolbarLayout)) { swipeRefreshLayout.setEnabled(false); } else { swipeRefreshLayout.setEnabled(true); } } 

Anular onPause () & onResume () como en @blackcj respuesta:

  @Override public void onResume() { super.onResume(); appBarLayout.addOnOffsetChangedListener(this); } @Override public void onPause() { super.onPause(); appBarLayout.removeOnOffsetChangedListener(this); } 

A continuación, establezca LinearLayoutManager a su recicladorVer:

  LinearLayoutManager layoutManager = new LinearLayoutManager(getActivity()); layoutManager.setOrientation(LinearLayoutManager.VERTICAL); recyclerView.setLayoutManager(layoutManager); 

Para mí esto funcionó como un encanto, primer appBarlayout se amplía y sólo entonces swipeRefreshLayout dispara la actualización.

Tuve que hacer que el RecyclerView el hijo principal de la SwipeRefreshLayout con el fin de eliminar el problema utilizando la biblioteca de soporte 23.2.0. No se pudo corregirlo con un diseño de inclusión dentro de SwipeRefreshLayout

 <android.support.v4.widget.SwipeRefreshLayout android:id="@+id/my_swipeRefreshLayout" android:layout_width="match_parent" android:layout_height="match_parent"> <!--<include layout="@layout/my_RecyclerView_layout"/> issue for me here --> <android.support.v7.widget.RecyclerView android:id="@+id/my_recyclerView" android:layout_width="match_parent" android:layout_height="match_parent"> </android.support.v7.widget.RecyclerView> </android.support.v4.widget.SwipeRefreshLayout> 

La respuesta anterior es perfecta para AppCompatActivity pero si se utiliza Fragment continuación, el siguiente fragmento le ayudará.

Sólo tiene que poner NestedScrollView en xml de fragment

 <android.support.v4.widget.NestedScrollView xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" android:layout_gravity="fill_vertical" android:clipToPadding="false" android:isScrollContainer="false" app:layout_behavior="@string/appbar_scrolling_view_behavior"> <!-- A RecyclerView with some commonly used attributes --> <android.support.v4.widget.SwipeRefreshLayout xmlns:android="http://schemas.android.com/apk/res/android" android:id="@+id/album_timeline_swipe_refresh_layout" android:layout_width="match_parent" android:layout_height="match_parent"> <android.support.v7.widget.RecyclerView android:id="@+id/album_timeline_recyclerview" android:layout_width="match_parent" android:layout_height="match_parent" android:clickable="true" /> </android.support.v4.widget.SwipeRefreshLayout> </android.support.v4.widget.NestedScrollView> 
FlipAndroid es un fan de Google para Android, Todo sobre Android Phones, Android Wear, Android Dev y Aplicaciones para Android Aplicaciones.