Since the introduction of AppBar in 2015, Android developers have spent lots of time styling and modifying it, making beautiful and unique apps. The ways of modifying Toolbar and flexible area beneath it are quite impressive. Yet, still the entry threshold is quite high for those who want to make their first steps in Material design world.
Partly, this is because of an incomplete documentation and the lack of diverse examples. I, myself struggled to make the layout I wanted and as easy as it sounds – to make it scroll the way I want to. This was the moment I decided to write this blog post, so it helps others 🙂
Maybe you want to scroll a Toolbar, so it hides completely and the only thing visible is the text? Or expand and collapse an image below the Toolbar? Or, doesn’t matter if the user is on the bottom of the layout, – you want to show him a Toolbar immediately on a scroll up action (there is a description of various scrolling techniques here). All of this is possible and easy to do with scroll flags!
Why do you need those flags in the first place? Well, when you want to have expandable Toolbar, Floating Action Button and a content to scroll over, the best option would be to put them into CoordinatorLayout and use its facilities in order to customize the behavior of each of those components. CoordinatorLayout bounds the behavior of a few views together. It makes them work as a whole – smooth and natural. You just need to put Toolbar into the AppBarLayout, which is a special version of a LinearLayout with a scrolling gestures, and put a content into NestedScrollView which then needs to have a behavior flag – app:layout_behavior
in order to notify AppBarLayout when a scroll event occurs, so they could work together. This is very nicely described in here.
In case you’ve created a layout and haven’t specified app:layout_scrollFlags
, Toolbar or whatever is inside AppBarLayout, will statically remain on top, always in an expanded state. If this is your intended behavior, then leave it as it is. If not, welcome to the rest of the blog post 😉
If you want to jump right into the source code, please check it out on the GitHub !
And so, I will discuss app:layout_scrollFlags
attribute from AppBarLayout.LayoutParams. This attribute is responsible for a scrolling behavior of AppBarLayout and its children. You can apply it directly to AppBarLayout or on the inside views, in the xml layout of your AppCompatActivity. It has to be an instance of AppCompatActivity if you want to use AppBar features. Also, the design library must be included in Gradle dependencies, like so: implementation 'com.android.support:design:26.1.0'
Basically, app:layout_scrollFlags
attribute must have one of the 5 values (or a few of them combined). In my examples I use a Toolbar with action items, so my explanations are based on it.
scroll – Toolbar scrolls with the rest of the content, just like a regular view on the layout.
<android.support.design.widget.AppBarLayout android:id="@+id/appBarLayout" android:layout_width="match_parent" android:layout_height="wrap_content" android:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar"> <android.support.v7.widget.Toolbar android:id="@+id/toolbar" android:layout_width="match_parent" android:layout_height="?attr/actionBarSize" app:layout_scrollFlags="scroll" app:popupTheme="@style/ThemeOverlay.AppCompat.Light" /> </android.support.design.widget.AppBarLayout>
enterAlways – Toolbar scrolls with the rest of the content, just like a regular view on the layout. The difference to scroll flag, is that even on the slightest scroll up, the Toolbar will immediately show up, no matter if the content is on top or not. This is a so-called “quick return” design pattern. I would recommend this flag in case there is some important and highly used item on the Toolbar, so the user has an immediate access to it.
<android.support.design.widget.AppBarLayout android:id="@+id/appBarLayout" android:layout_width="match_parent" android:layout_height="wrap_content" android:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar"> <android.support.v7.widget.Toolbar android:id="@+id/toolbar" android:layout_width="match_parent" android:layout_height="?attr/actionBarSize" app:layout_scrollFlags="scroll|enterAlways" app:popupTheme="@style/ThemeOverlay.AppCompat.Light"/> </android.support.design.widget.AppBarLayout>
enterAlwaysCollapsed – an additional flag to use with enterAlways, in cases where you have a CollapsingToolbarLayout. If you put enterAlways only, you’ll end up with an expanding layout on every scroll up action and that’s probably not what you want 🙂 With this flag, the layout is expanding only when the content has been scrolled all the way up. As for the collapsed Toolbar, it appears on every scroll up action.
Here I have to mention an app:layout_collapseMode
attribute. It’s really important to add app:layout_collapseMode="pin"
to the Toolbar, otherwise the action items won’t show when the layout is scrolled. I recommend putting app:layout_collapseMode="parallax"
for an ImageView in order to have a nice scrolling effect.
<android.support.design.widget.AppBarLayout android:id="@+id/appBarLayout" android:layout_width="match_parent" android:layout_height="wrap_content" android:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar"> <android.support.design.widget.CollapsingToolbarLayout android:id="@+id/collapsingToolbarLayout" android:layout_width="match_parent" android:layout_height="match_parent" app:contentScrim="?attr/colorPrimary" app:layout_scrollFlags="scroll|enterAlways|enterAlwaysCollapsed"> <ImageView android:id="@+id/imageViewCollapsing" android:layout_width="match_parent" android:layout_height="match_parent" android:scaleType="centerCrop" android:src="@drawable/winterscenery" app:layout_collapseMode="parallax" /> <android.support.v7.widget.Toolbar android:id="@+id/toolbar" android:layout_width="match_parent" android:layout_height="?attr/actionBarSize" app:layout_collapseMode="pin" app:popupTheme="@style/ThemeOverlay.AppCompat.Light" /> </android.support.design.widget.CollapsingToolbarLayout> </android.support.design.widget.AppBarLayout>
exitUntilCollapsed – the name of this flag says for itself. On scroll down, CollapsingToolbarLayout hides only till collapsed state, which is based on the min height. So, in our case it’s Toolbar’s height. This way, it will always be visible and when scrolled all the way up – will expand the flexible area beneath it (in our case – ImageView).
This flag is probably the most common and suitable for a Details view, with ImageView and CardViews below. Again, you need to add app:layout_collapseMode="pin"
on the Toolbar, so the action items are shown on scroll.
<android.support.design.widget.AppBarLayout android:id="@+id/appBarLayout" android:layout_width="match_parent" android:layout_height="wrap_content" android:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar"> <android.support.design.widget.CollapsingToolbarLayout android:id="@+id/collapsingToolbarLayout" android:layout_width="match_parent" android:layout_height="match_parent" app:contentScrim="?attr/colorPrimary" app:layout_scrollFlags="scroll|exitUntilCollapsed"> <ImageView android:id="@+id/imageViewCollapsing" android:layout_width="match_parent" android:layout_height="match_parent" android:scaleType="centerCrop" android:src="@drawable/winterscenery" app:layout_collapseMode="parallax" /> <android.support.v7.widget.Toolbar android:id="@+id/toolbar" android:layout_width="match_parent" android:layout_height="?attr/actionBarSize" app:layout_collapseMode="pin" app:popupTheme="@style/ThemeOverlay.AppCompat.Light" /> </android.support.design.widget.CollapsingToolbarLayout> </android.support.design.widget.AppBarLayout>
snap – this flag provides a “sticky” scroll behavior. Based on how far from the top the AppBarLayout is, it will either fast scroll to hide or show completely. Imagine there’s a line in the middle of a Toolbar, exactly on 50% of its height. If you scroll up, so 51% of Toolbar is invisible, it will “jump up” to hide, if 49% is invisible and you scroll down, it will fully be shown. The snap flag can be used with other flags as a further customization.
<android.support.design.widget.AppBarLayout android:id="@+id/appBarLayout" android:layout_width="match_parent" android:layout_height="wrap_content" android:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar"> <android.support.v7.widget.Toolbar android:id="@+id/toolbar" android:layout_width="match_parent" android:layout_height="?attr/actionBarSize" app:layout_scrollFlags="scroll|snap" app:popupTheme="@style/ThemeOverlay.AppCompat.Light" /> <android.support.design.widget.TabLayout android:id="@+id/tabLayout" android:layout_width="match_parent" android:layout_height="wrap_content"> <android.support.design.widget.TabItem android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="One" /> <android.support.design.widget.TabItem android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="Two" /> <android.support.design.widget.TabItem android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="Three" /> </android.support.design.widget.TabLayout> </android.support.design.widget.AppBarLayout>
Important thing to mention, is that scroll flag should always be specified, as a first value, i. e. “scroll|enterAlways”. When you check the source code of AppBarLayout, you’ll see there is a check for a scroll flag, if it’s not there – everything else is ignored.
To simplify the decision of which flag to choose for your own need, I’ve made this comparison table:
scroll | enterAlways | enterAlwaysCollapsed | exitUntilCollapsed | snap | |
---|---|---|---|---|---|
Scroll Up | the view becomes visible when the layout's been scrolled all the way up | the view becomes visible on every scroll up action, even if there's still a lot of content to scroll up | the collapsed version of the view (e.g. Toolbar) becomes visible on every scroll up action, and it expands (e.g. Toolbar with an ImageView) only when scrolled all the way up | the view is always visible, provided its height is > 0 and the expanded version (e.g. Toolbar with an ImageView) will become visible when scrolled all the way up | fast scrolls up or down based on how much of the view is visible - if more than 50% - the view will scroll down, showing itself, if less - the view will hide; used with other flags as a further customization |
Scroll Down | the view scrolls with the rest of the content like it's a part of it; will hide if the layout's height is bigger than the screen's one | the view scrolls with the rest of the content like it's a part of it; will hide if the layout's height is bigger than the screen's one | the view collapses and then hides, if the layout's height is bigger than the screen's one | the view scrolls with the rest of the layout's content, but only till its collapsed state (hence - "exit until collapsed"), so in case of a Toolbar with a fixed height, it will always be visible on the top | fast scrolls up or down based on how much of the view is visible - if more than 50% - the view will scroll down, showing itself, if less - the view will hide; used with other flags as a further customization |
Does it make sense now? 🙂 I hope you understand more about scroll flags after reading this post. Please write a comment if something’s unclear. Thanks!
Source code:
On GitHub 🙂
Read more:
Scrolling Behavior for Appbars in Android
Handling Scrolls with CoordinatorLayout
Thanks for your contribution Tonia 🙂 It’s really useful!
Thanks it helped me alot
thanks Tonia. very well written article!
but I think, what you mean by scroll up is basically the user dragging his finger towards the bottom, so I guess that should be scroll down, right?
I have included webview in this, my webpage is not scrollable now, what to do pls inform ..