Skip to main content

Introducing Sticky Grid Headers

Recently, I came across a library by +Emil Sjölander called StickyListHeaders. It is an implementation of an Android list view with integrated section headers that conveniently stick to the top of the view while part of the section is still displayed. The library is also very easy to use and as such has gained a lot of popularity.

Unfortunately, for a project I am currently working on I needed such a thing with multiple columns. Android provides a grid view which satisfies the multiple columns problem, but like the standard list view, it doesn't support section headers. So, inspired by Emil's approach, I've written StickyGridHeaders.

 

Usage

StickyGridHeadersGridView is largely a drop in replacement for the normal GridView. You just need to add the library as a dependency to your project and you can use it in the same manner you would use the normal grid view. There are slight changes you will need to make to your ListAdapters as they will need to implement one of the two adapter interfaces provided by StickyGridHeaders.

To make StickyGridHeaders easy to use there is a simple adapter interface (StickyGridHeadersSimpleAdapter). This interface matches that in StickListHeaders so if you are using that library you can easily adopt this one too. Additionally, there is a slightly more complex adapter (StickyGridHeadersBaseAdapter). The difference is that the simple adapter will process your data set to generate all the information needed to insert all those extra items. If you want to control that process just use the base adapter and provide the information yourself. You can refer to the example included in the github repository.

 

How it works

There were a number of problems to solve in writing StickyGridHeaders, displaying items in discrete sections, displaying headers above each section, and making the headers stick to the top of the view. Along the way I also made each row match the height of the largest item in the row.

Since third parties can't modify how GridView works we have to consider how to use its existing behaviour make it display items separated into sections. In order to demonstrate assume for a moment that we want a grid view with 3 columns. Normally we would have a list of items,
[ A, A, A, A, B, B, B ]
which will display in a three column grid.
A A A
A B B
However if we use a list of items,
[ A, A, A, A, _, _, B, B, B ]
the grid will display as such,
A A A
A _ _
B B B
and so it becomes obvious that we have to transform our list of items before it gets to the grid view. This can easily be done by wrapping the adapter which provides the list of items and using the wrapper to insert items in the appropriate places. It is also trivial to extend this to support making a row in front of each section which is where the headers will be drawn.
. . .
A A A
A _ _
. . .
B B B
Now we have the correct structure in the grid view we just need to draw our headers in the right places. To make it easy the headers are hidden in the header row spacers. We just wait until the grid view has drawn itself and draw the hidden headers in their places over the top. We have to do this because, if the headers were to be drawn by the spacer, the canvas area allotted to the spacer is, depending on the number of columns, smaller than the width of the row and we want to draw our header across the entire width of the row.

To implement the sticky behaviour of the headers we track the current section intersecting with the top of the visible area and we just keep a reference to the header for that section and draw it at the top of the view. Finally we track the scrolling of the grid so that we can animate the switching of the current stickied header, with the incoming header bumping the stickied header off the screen until the incoming becomes the stickied.

Comments