Implementing a Collapsing Toolbar with Android Material Design
Recently, Mindgrub was tasked with implementing a user profile view in an Android app. This profile view would fill the top of the screen with a profile picture and then collapse into a “normal” toolbar when scrolling to the bottom of the screen.
Here’s an example:
Initially, we were worried that we would have to go out and find a third-party library that implemented this collapsing toolbar (or write it ourselves). Luckily, Google provided developers with the Android Design Support Library, and this kind of animation could be created with new widgets introduced in this library.
Here’s the code for an extremely simple demo of this behavior:
<android.support.design.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" android:layout_width="match_parent" android:layout_height="match_parent"> <android.support.design.widget.AppBarLayout android:id="@+id/app_bar_layout" android:layout_width="match_parent" android:layout_height="wrap_content"> <android.support.design.widget.CollapsingToolbarLayout android:id="@+id/collapsing_toolbar" android:layout_width="match_parent" android:layout_height="match_parent" app:layout_scrollFlags="scroll|exitUntilCollapsed" app:contentScrim="?attr/colorPrimary"> <ImageView android:id="@+id/expandedImage" android:layout_width="match_parent" android:layout_height="200dp" android:src="@drawable/beach_scene" android:scaleType="centerCrop" app:layout_collapseMode="parallax" app:layout_collapseParallaxMultiplier="0.7" /> <android.support.v7.widget.Toolbar android:id="@+id/toolbar" android:layout_width="match_parent" android:layout_height="?attr/actionBarSize" app:layout_collapseMode="pin" > </android.support.v7.widget.Toolbar> </android.support.design.widget.CollapsingToolbarLayout> </android.support.design.widget.AppBarLayout> <android.support.v4.widget.NestedScrollView android:layout_width="match_parent" android:layout_height="match_parent" android:background="@android:color/white" app:layout_behavior="@string/appbar_scrolling_view_behavior"> <TextView android:layout_width="fill_parent" android:layout_height="wrap_content" android:text="@string/sample_string"/> </android.support.v4.widget.NestedScrollView> </android.support.design.widget.CoordinatorLayout>
Simple, right? Well, maybe not at first glance – but it’s not too difficult to understand once you break it down. Let’s analyze each XML element piece-by-piece:
COORDINATORLAYOUT
<android.support.design.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" android:layout_width="match_parent" android:layout_height="match_parent">
This should be the top-level element in your fragment or activity. The CoordinatorLayout is a new type of element introduced in the Design Library – basically it “coordinates” behavior between its child views. The behavior is specified by attributes set in its child views that are specific to the coordinator layout.
APPBARLAYOUT
<android.support.design.widget.AppBarLayout android:id="@+id/app_bar_layout" android:layout_width="match_parent" android:layout_height="wrap_content">
This is another new element from the Design Library that declares a layout for the toolbar. The children of this element will define the behavior of the elements within the Toolbar.
AppBarLayouts are actually required to be children of CoordinatorLayouts, and are also required to have a sibling element that has the “layout_behavior” attribute set to “AppBarLayout.ScrollingViewBehavior”. Setting this attribute on the sibling element binds that element to the AppBarLayout, which lets it know when it should scroll. We bind the AppBarLayout to the NestedScrollView, which is discussed further below.
COLLAPSINGTOOLBARLAYOUT
<android.support.design.widget.CollapsingToolbarLayout android:id="@+id/collapsing_toolbar" android:layout_width="match_parent" android:layout_height="match_parent" app:layout_scrollFlags="scroll|exitUntilCollapsed" app:contentScrim="?attr/colorPrimary">
This element is the child of the “AppBarLayout” and declares the “Collapsing” behavior we want. The children of this element will declare how the toolbar is collapsing.
IMAGEVIEW
<ImageView android:id="@+id/expandedImage" android:layout_width="match_parent" android:layout_height="200dp" android:src="@drawable/beach_scene" android:scaleType="centerCrop" app:layout_collapseMode="parallax" app:layout_collapseParallaxMultiplier="0.7" />
Just a normal ImageView, with a few exceptions: we are setting the “layout_collapseMode” to “parallax”, which causes the ImageView to move as the user scrolls at a specific ratio. You can set this ratio with the (optional) “layout_collapseParallaxMultiplier” setting.
TOOLBAR
<android.support.v7.widget.Toolbar android:id="@+id/toolbar" android:layout_width="match_parent" android:layout_height="?attr/actionBarSize" app:layout_collapseMode="pin" > </android.support.v7.widget.Toolbar>
Again, this is just a normal element you’ve seen before, except for the layout behavior set by the “layout_collapseMode” property. For this element, we are setting it to “pin” which causes it to stick to the top when the user scrolls the view up.
NESTEDSCROLLVIEW
<android.support.v4.widget.NestedScrollView android:layout_width="match_parent" android:layout_height="match_parent" android:background="@android:color/white" app:layout_behavior="@string/appbar_scrolling_view_behavior">
This is the sibling element to the “AppBarLayout” mentioned above. This is just a normal NestedScrollView, with the exception of the “layout_behavior” attribute set. As mentioned above, setting this attribute binds it to its sibling element, the AppBarLayout.
TEXTVIEW
<TextView android:layout_width="fill_parent" android:layout_height="wrap_content" android:text="@string/sample_string"/>
This is simply the scrollable content. This doesn’t have to be a TextView – it can be any kind of layout, RecyclerView, etc. I used a TextView here for simplicity’s sake.
So after understanding all that, you should be all set to implement your own collapsing-toolbar view! Check out the code from our example on Github.