1

I have a recycler view. I want to add a header to the recycler view so that it scrolls along with the recycler view. Years ago, the options were either:

  1. Nest the recycler view and header layout inside a NestedScrollView. The downside to this is that it means the recycler view will not behave as it's supposed to.
  2. Modify the recycler view so that it handles two view types, one for the header and one for the regular recycler view items.

Where are we in 2020? Are these still the two options? If so, is #2 still the recommended option?

Thanks.

user4165123
  • 153
  • 1
  • 9

2 Answers2

9
  • You should never use Option 1 if you want to display long lists in RecyclerView. Placing RecyclerView in NestedScrollView will force RecyclerView to create all the items at once. You will lose recycling and your app will probably freeze in attempt to create all ViewHolders. It will also eat up a lot of memory. read more

  • Option 2 was the main way to implement lists with different layout types in it. But it makes the part of creating a list more complex. It would at least not work with Paging library 2.

Luckily, we now have a better alternative.

Starting with RecyclerView version 1.2.0-alpha02 there is a new tool that can be used to easily create complex lists with different items in them. It is called ConcatAdapter. You can read more about it in a great article by Florina Muntenescu on Medium.

As of 5/10/20, latest version of library is 1.2.0-alpha06. Despite library is still in alpha version, ConcatAdapter is a great tool and I have been using it since it was first introduced. I never run into any problems so far. It works great and everything is pretty stable.

From my experience, I would say that this is probably the new best practice for adding headers and footers (and mixed type lists) in RecyclerView.

ConcatAdapter is also used in Paging library version 3. In this codelab they add header and footer to adapter natively.

binding.list.adapter = adapter.withLoadStateHeaderAndFooter(
        header = ReposLoadStateAdapter { adapter.retry() },
        footer = ReposLoadStateAdapter { adapter.retry() }
)

And adapter extends PagingDataAdapter.

And if you go to the source code you will see that withLoadStateHeaderAndFoote uses ConcatAdapter under the hood.

/**
 * Create a [ConcatAdapter] with the provided [LoadStateAdapter]s displaying the
 * [LoadType.PREPEND] and [LoadType.APPEND] [LoadState]s as list items at the start and end
 * respectively.
 *
 * @see LoadStateAdapter
 * @see withLoadStateHeader
 * @see withLoadStateFooter
 */
fun withLoadStateHeaderAndFooter(
    header: LoadStateAdapter<*>,
    footer: LoadStateAdapter<*>
): ConcatAdapter {
    addLoadStateListener { loadStates ->
        header.loadState = loadStates.prepend
        footer.loadState = loadStates.append
    }
    return ConcatAdapter(header, this, footer)
}

All of these shows that ConcatAdapter is starting to be heavily used and proves to be the best solution for multi-type lists.

Marat
  • 6,142
  • 6
  • 39
  • 67
0

I recently struggled with the same problem and after research I have not found other options. Both are fine and have advantages and disadvantages.

#1 First one is definately easier, and if you want a header (unlike sth below) there shouldn't be any problems with it, scrolling should be fine and animations also. (If you want sth below the RecyclerView you can add both the RecyclerView and the other one in the LinearLayout and in the NestedScrollView. It will be working fine, but if there are animations when the item is added and deleted, the view won't be animated and that has to be taken into account.

#2 Second option generates more code and is more complex but it gives you fluent animations.

All things considered, if you want sth quick and easy I would suggest the first option (if its just one header on top of the RecyclerView there should be no problems with the animations also.

baltekg
  • 985
  • 9
  • 31