Skip to content

Add sticky headers to a ListView

Introduction

In this article we look at how to add 'sticky headers' to a ListView in NativeScript. By default, the NativeScript ListView does not have a sticky header feature. However, it is possible to simulate that feature as we'll see in this article.

Ingredients

We'll need:

  • ListView( of course)
  • Label
  • GridLayout

Add the sticky headers

To achieve the sticky header effect, we'll need to do the following:

  • Add the headers' texts to the ListView items array such that they appear at the beginning of each section of the ListView. That is, the first item in the array will be the first header, the second header will be after the last item of the first section, the third header will be after the last item of the second section, and so on.

  • Wrap the ListView and the Label that will act as the sticky header in a GridLayout

    • The GridLayout will have one row and one column. We add the ListView first and the Label second so that the Label will appear above the ListView.
    • The Label starts off with the text for the first header. We update the text of the Label with other headers as the user scrolls through the ListView.
  • Listen to native scroll events and update the sticky header's text accordingly.

    • iOS: To listen to the scroll event on iOS, we'll need to implement the scrollViewDidScroll method of the UITableViewDelegate. See (list-scroll.ios)[]. We obtain and extend the delegate already set on the ListView by the NativeScript Core team with the scrollViewDidScroll method implementation.

    • Android: To listen to the scroll event, we'll need to implement the onScroll method of the AbsListView.OnScrollListener. See (list-scroll.android)[].

    On both platforms after each scroll, we'll need to do the following for each direction of scrolling:

    • Downward scrolling: check if any of the headers is the first in the list of visible items. If so, update the Label text to the text of the header that is first in the list of visible items.
      • On Android: the list of visible items is obtained by calling view.getChildCount() and view.getChildAt(i) where view is the ListView.
      • On iOS: the list of visible items is obtained by calling const indexPathsForVisibleRows = this._owner.get().ios.indexPathsForVisibleRows;.
  • Upward scrolling: check if any of the headers is in the list of visible items but not the first. If so, update the text of the Label to the text of the header that is before the header that is visible but not the first.

For both up and down scrolling, we'll have to emit an event to notify the header Label that the text has changed.