Android List Headers using Decorators

Matthew Palsich
7shifts Back of House
3 min readJun 17, 2019

Adding headers to a RecyclerView requires considerable changes to its adapter, and — worst of all — you now have multiple view types. Headers exist to visually group list items. Something so decorative deserves a more superficial implementation. SideHeaderDecorator introduces a simple way to add sticky side headers to a RecyclerView without touching your adapter.

Read on to see how simple SideHeaderDecorator is to use, and check it out on GitHub!

Modern Android apps use RecyclerView to efficiently display lists. Data is bound to the list using an adapter class which adapts each data item to a view in the list. Creating views is expensive and each list item has the same layout, so RecyclerView creates just enough views to fill the screen, plus a couple extra. When one view scrolls off the top, it gets populated with new data then comes back in the bottom. Hence, the views are recycled.

Adding headers to a list means items no longer all have the same layout. The RecyclerView adapter must determine if the data at each position is a regular item or a header, then return the correct view to populate. So, adding headers requires changing the underlying dataset and mechanics of the list.

What about trivial changes to list appearance? Something as simple as inserting item dividers shouldn’t require complex adapter changes. For cosmetic changes, RecyclerView provides decorators.

Unlike adapters, which determine what is displayed in the list, decorators change how what is already displayed appears on screen. Instead of affecting the view recycling process, RecyclerView decorators are drawn over existing list items. A decorator would be used, for example, to draw list item dividers, or change the transparency of items as they scroll. However, decorators can also be leveraged to draw headers.

SideHeaderDecorator draws sticky headers on the side of a list, bringing a header in with the first item in a group, sticking it to the top of the list, then scrolling it off with the last item in a group. Its implementation is simple and only requires two steps to use:

  • First, items are mapped to header models. Sequential items mapping to the same header model are considered a group.
interface HeaderProvider<H> {
fun getHeader(position: Int): H
}
  • Second, given some header model, a header view is created.
abstract fun getHeaderView(header: H, parent: RecyclerView): View

SideHeaderDecorator then shifts the list content over to make room and draws the header views beside the items.

The advantage of using a decorator for headers is that it’s noninvasive. Unlike adding a header view type to the adapter, a decorator is purely cosmetic and does not impact the underlying mechanics or structure of the list. Thus, it is easy to add and easy to remove.

You may have noticed a downside to this application of decorators. Because they bypass the view recycling mechanism, they are of course not recycled. Instead, we rely on the garbage collector to free up memory allocated to headers no longer visible in the list. Thankfully, lists usually don’t have too many headers and the garbage collector is fairly attentive.

Header decorators make it easy to add headers to a list without having to rip apart your adapter. In 7shifts, we used SideHeaderDecorator to quickly apply headers to multiple lists even though they have unique header views. Because decorator header views are not recycled by the RecyclerView, it would be worthwhile to investigate how memory usage is affected for lists with many headers. However, our header usages are performant while relying on the garbage collector to dispose of headers as you scroll.

Thanks for reading! We’d appreciate your feedback, and invite you to help improve this library. Full source code can be found on the SideHeaderDecorator GitHub page.

--

--