Collapsing AppBarLayout on Android TV

Ataul is a Google Developer Expert for Android focusing on inclusive design for mobile platforms and loves facilitating the production of universally useable apps. Also, he watches a lot of movies.

CoordinatorLayout has really made it easy to perform animations for elements that are dependent on one another, but not all of the behaviours work out of the box for Android TV.

There are some compelling use cases for CoordinatorLayout - Behaviors are a neat (as in "neat-o") way to encapsulate view logic that involves multiple elements - like the simple app bar collapsing behaviour:

animated gif showing a collapsing app bar as user scrolls down

Excellent, and took less than ten minutes to implement. Let's test it works for keyboard users, :shipit: and lunchtime!

But... not so fast. Here's what it looks like on a Nexus Player (or any device with non-touch input):

animated gif showing a listview with the last item obscured as the user scrolls down with dpad input

We could live with the first one, but the second actually degrades the user's experience (compared to not using this Behavior).

The app bar doesn't react to scrolling of the RecyclerView as you navigate down with a directional pad so the scrolling view is still the same size of the viewport, but its offset isn't adjusted. We can fix this. We have the technology.

Beginning with version 23 of the design support library, AppBarLayout includes a new show/hide API: setExpanded(boolean expand, boolean animate).

When a d-pad is used to scroll the view, we can trigger that behaviour ourselves:

public interface AppBarExpander {

    void expandAppBar();

    void collapseAppBar();

public class SeasonsActivity extends AppCompatActivity implements AppBarExpander {  

    public void expandAppBar() {
        boolean animate = true;
        appBarLayout.setExpanded(true, animate);

    public void collapseAppBar() {
        boolean animate = true;
        appBarLayout.setExpanded(false, animate);

The scrollVerticallyBy(int dy, ...) method in RecyclerView.LayoutManager is called whenever the RecyclerView is scrolled - in both touch and non-touch mode.

We can override this method, and if we're in non-touch mode (i.e. using a d-pad), then we can notify our AppBarExpander:

AppBarExpander appBarExpander;  

final RecyclerView view = (RecyclerView) layoutInflater.inflate(R.layout.view_season_page, container, false);  
view.setLayoutManager(new LinearLayoutManager(container.getContext()) {

    public int scrollVerticallyBy(int dy, RecyclerView.Recycler recycler, RecyclerView.State state) {
        if (!view.isInTouchMode()) {
        return super.scrollVerticallyBy(dy, recycler, state);

    private void onScrollWhenInNonTouchMode(int dy) {
        if (dy > 0) {
        } else {


And here's the end result (or as I like to call it, lunchtime):

animated gif showing a listview with the last item fully visible and the app bar hiding as user scrolls down with dpad input

2 September 2015: you can also use this technique by adding a RecyclerView.OnScrollListener to the RecyclerView directly, which should be more robust (at least in terms of switching LayoutManagers).

About Novoda

We plan, design, and develop the world’s most desirable Android products. Our team’s expertise helps brands like Sony, Motorola, Tesco, Channel4, BBC, and News Corp build fully customized Android devices or simply make their mobile experiences the best on the market. Since 2008, our full in-house teams work from London, Liverpool, Berlin, Barcelona, and NYC.

Let’s get in contact