AppBarLayout scroll behavior with layout_scrollFlags

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.

scroll flag behavior

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

enterAlways flag behavior

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

enterAlwaysCollapsed flag behavior

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

exitUntilCollapsed flag behavior

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

snap flag behavior

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

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

Material Scrolling techniques

Material Design Components

AppBarLayout documentation

AppBarLayout Oreo source code

Like and share:

Published by

Tonia Tkachuk

I'm an Android Developer, writing code for living and for fun. Love beautiful apps with a clean code inside. Enjoy travelling and reading.