Android: CollapsingToolbarLayout and SwipeRefreshLayout stuck

I use CollapsingToolbarLayout, RecyclerView and SwipeRefreshLayout together:

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> 

The code:

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

How to allow opaque updates only when expanding the layout of the toolbar is fully expanded and scrollview (recyclerview) is on top ? Similar behavior, for example, in the Google+ app or Inbox.

Wrong:

enter image description here

Good:

enter image description here

+44
android collapsingtoolbarlayout swiperefreshlayout
Jun 11 '15 at 11:35
source share
5 answers

Finally,

I found that SwipeRefreshLayout works without any β€œhacks” from the Support Library version 23.1.1 .

Just use in your layout:

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

and in code:

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

And don't forget to use:

 swipeRefreshLayout.setRefreshing(false); 

after using your code logic;)

+22
Nov 18 '15 at 9:45
source share

Update:. This problem was resolved in the latest version of the support library (23.1.1+). If you are using an older version of the support library, upgrade or continue reading.

If you are using an older version of the support library, add an offset change listener to the AppBarLayout to enable or disable your swipe to update the layout accordingly. Additional code is available here:

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

According changes:

 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); } } 
+77
Jun 11 '15 at 15:59
source share

If you understand correctly, you want to start updating only after the toolbar is expanded, right? Therefore, you must first open CollapsingToolbarLayout, and then start the update. I managed to do this with the following code:

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

And then in your fragment / activity make it implement AppBarLayout.OnOffsetChangedListener (now the update is activated when the toolbar is fully expanded):

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

Override onPause () and onResume (), as in @blackcj answer:

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

Then set LinearLayoutManager to your recyclerView:

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

For me, it worked like a charm, first the appBarlayout expands, and only then the swipeRefreshLayout triggers are updated.

+4
Nov 13 '15 at 14:13
source share

I had to make RecyclerView the primary descendant of SwipeRefreshLayout in order to remove the problem using Support Library 23.2.0. Failed to commit it with enable layout inside 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> 
0
Mar 17 '16 at 15:16
source share

The above answer is perfect for AppCompatActivity , but if you are using Fragment , then the following snippet will help you.

Just put NestedScrollView in xml 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> 
-one
Dec 09 '15 at 13:29
source share



All Articles