Android TV Leanback: HeadersSupportFragment — A Detailed Guide

Photo by Nabil Saleh on Unsplash

Understanding the internals of the Leanback APIs is sometimes quite tricky, but it’s something we, as developers, must do to make sure we’re able to create apps that look and behave correctly to our users. In this post, we’ll dive deep into the HeadersSupportFragment, which is part of the BrowseSupportFragment, and almost always, the first piece of content users see in an Android TV app. We will learn about its creation, how it behaves, and how we can customize it.

As stated in the introduction, the HeadersSupportFragment is part of the BrowseSupportFragment. The BrowseSupportFragment is often the first screen that a user sees when opening an Android TV app, and it’s where the user can browse and discover content.

BrowseSupportFragment with visible headers

HeadersSupportFragment creation and configuration

The BrowseSupportFragment has a function called onCreateHeadersSupportFragment() which is responsible for returning an instance of HeadersSupportFragment to be used inside it. It is a public function, so it is possible to override it if you want to provide a custom implementation of your own HeadersSupportFragment.

public HeadersSupportFragment onCreateHeadersSupportFragment() 
return new HeadersSupportFragment();

After that, still inside the BrowseSupportFragment.onCreateView() the HeadersSupportFragment is added to its container by a FragmentTransaction performed by the BrowseSupportFragment. Then, the following steps happen:

  • Update HeadersSupportFragment visibility based on the state passed to BrowseSupportFragment.setHeaderState(state). The available states are:
/** The headers fragment is enabled and shown by default. */
public static final int HEADERS_ENABLED = 1;
/** The headers fragment is enabled and hidden by default. */
public static final int HEADERS_HIDDEN = 2;
/** The headers fragment is disabled and will never be shown. */
public static final int HEADERS_DISABLED = 3;
  • Calls HeadersSupportFragment.setPresenterSelector() passing the PresenterSelector provided to BrowseSupportFragment.setHeaderPresenterSelector(). This PresenterSelector should support at least three types of items. Which are, DividerRow, SectionRow, and Row.

Note: The HeadersSupportFragment already have out-of-the-box implementations for these Row types, but we can provide custom implementations. As a HeaderSupportFragment is a subclass of BaseRowSupportFragmeent, customizing its rows, it’s just a matter of having a custom Presenter for its items.

  • The HeadersSupportFragment has its adapter, OnHeaderViewSelectedListener and OnHeaderClickedListener set. The adapter is responsible for providing the items. The default implementation for its OnHeaderViewSelectedLister changes or selects the content of the BrowseSupportFrament. As for the OnHeaderClickedListener, its default implementation hides the HeaderSupportFragment when an item is clicked.
  • The background color of the HeadersSupportFragment is set using the color provided to the BrowseSupportFragment.setBrandColor(). For example:
override fun onCreateHeadersSupportFragment(): HeadersSupportFragment 
// This can also be done on the onViewCreated()
brandColor = Color.RED
return super.onCreateHeadersSupportFragment()
  • At this point, the BrowseSupportFragment.onViewCreated() finished and the BrowseSupportFragment.onStart() will be called. Inside the onStart() the alignment of the HeadersSupportFragment will be set based on a Leanback theme property called browseRowsMarginTop. This property, as its name suggests, is also used by the BrowseSupportFragment to set the top margin of its first row.
  • If you want to change the HeadersSupportFragment items alignment, you need to do so after the call to super.onCreate()
override fun onStart() 
super.onStart()
headersSupportFragment.setAlignment(400)

Note: The idea of bothHeadersSupportFragment and BrowseSupportFragment using the same value from browseRowsMarginTop to set their top margin helps them to better align the selected row on the header with the selected row on the BrowseSupportFragment when the BrowseSupportFragment is used to display only ListRows. If the BrowseSupportFragment is displaying a PageRow this alignment doesn’t matter as the PageRow content will fill the entire fragment.

We’ll cover PageRows and the details of the BrowseSupportFragmenton another post. Make sure to follow me to be notified when it’s released!

  • You can enable or disable the headers of a BrowseSupportFragment by setting calling BrowseSupportFragment.setHeaderState(state) and passing the desired state.
  • Change HeadersSupportFragment background-color by calling HeadersSupportFragment.setBrandColor(color).
  • Change or provide new types of Presenter to your HeadersSupportFragment.
  • Change the OnHeaderViewSelectedListener and OnHeaderClickListener implementations of you HeadersSupportFragment.

As we saw earlier, the HeadersSupportFragment should support three different types of items: DividerRow, SectionRow, and Row. Take a look at how these items are displayed with their default Presenter implementations.

BrowseSupportFragment with three types of items in HeadersSupportFragment

IconSectionRow and IconSectionPresenter

To show how we can customize the items of a HeadersSupportFragment, we will create a IconSectionPresenter which will render a SectionRow with an image on the left of its text.

Let’s start by creating a subclass of SectionRow that holds the id of a drawable to be used on the row.

class IconSectionRow(
@DrawableRes val icon: Int,
headerItem: HeaderItem
) : SectionRow(headerItem)

After that, we need to create a Presenter capable of performing the creation and binding of an IconSectionRow. We’ll do that by extending the RowHeaderPresenter and adding just a few lines.

And here’s the R.layout.icon_section_row.

Note: When creating layouts for non-focusable rows, like dividers and sections, disable the focus on its root view. Otherwise, they will be able to receive focus, and sometimes this can lead to a ClassCastException depending on the type of your item and ViewHolderused for it as the HeadersSupportFragment tries to cast the selected items ViewHolders to RowHeaderPresenter.ViewHolder.

DividerRow and SpaceDividerPresenter

Similar to how we created a custom Presenter for theSectionRow, we’ll create one for the DividerRow. We’ll build a presenter that displays the divider as a space instead of a 1dp line. In this case, we only need a custom presenter, as the item, the DividerRow, does not need to hold any extra information (like the icon from the IconSectionRow).

Adding Custom Presenters

Last, we must add both newly created presenters to the HeadersSupportFragment presenter selector. Make sure you are doing this only after the call to BrowseSupportFragment.onCreateView() finished, as the HeadersSupportFragment is only instantiated inside it.

Inside your BrowseSupportFragment, or in your custom implementation of HeadersSupportFragment, do the following:

Theme Managed Attributes

A few attributes from the HeadersSupportFragment are provided by your app theme. When creating a theme for an Android TV app, you should extend from Theme.Leanback. This base theme has all properties the Leanback components use to set sizes, margins, paddings, colors, and more. Below is a list of the attributes that are used by the HeadersSupportFragment.

  • lb_browse_headers_width: The width of the HeadersSupportFragment.
  • lb_browse_headers_paddding_end: HeadersSupportFragment padding end.
  • lb_browse_headers_z: Elevation of the HeadersSupportFragment root view.
  • lb_browse_header_fading_length: Fading edge width. The fading edge covers the end of a header text when the text is too long.
  • lb_headers_right_fading: Background drawable used by the fading edge.
  • headersVerticalGridStyle: Style for the VerticalGridView of the HeadersSupportfragment. The default theme is configured as shown below:
  • lb_section_header & lb_header: Default layout file for the SectionRow and Row views, respectively.

Note: On the sample app, none of these theme properties were changed.

Thanks for reading this post! Make sure to check the sample app created especially for this article. Take a look at the official documentation on HeadersSupportFragment.

Also, check this list I created with my Android TV Leanback series articles:

Ademir Queiroga

📺 Android TV Leanback Guide

You can also connect with me on Twitter.

Next Post

The ROI of Digital Accessibility

The author’s views are fully his or her have (excluding the unlikely event of hypnosis) and may perhaps not often mirror the views of Moz. In a recent AudioEye study of 500 enterprise leaders and world wide web professionals, 70% stated that “cost” was their most important worry when it […]
The ROI of Digital Accessibility

You May Like