Update - Please Note
Since this article was written 2 years ago, more robust solutions are available in open source libraries. For example, see the Flexible Adapter among others.
Recycler View
The ListView widget has been around since Android 1.0 in 2009. It has been the backbone of any list-driven user interface. However, over the years the ListView has taken on too much responsibility and layer on layer of functionality has turned it into a beast. Just check the ListView Source Code. That’s 4,000 lines of state management and conditional logic just to handle a list of things. The RecyclerView is the next generation widget for presenting a list (or grid) of items. It is more lightweight and flexible, but also therefore requires more application code to craft it to do specifically what’s needed.
Tracking Selection State
One such example of where the ListView handled functionality (but the RecyclerView leaves it to the application code) is for tracking selection. The ListView will automatically keep track of a selected item (or items) and handle keyboard presses and touch events to automatically select and deselect items for you.
The RecyclerView does not attempt to do this. If you want to select an item, do it yourself. It’s not that much code, but could be tricky to get it right. First create a custom class derived from RecyclerView Adapter which uses a custom ViewHolder. This class will perform two major functions:
- Select an item when the item is clicked
- Select next/previous item when the keyboard arrow keys are clicked
To select items when they are clicked, the ViewHolder constructor attaches a click listener:
One interesting thing to note here is the user of notifyItemChanged. Instead of calling notifyDataSetChanged, which rebuilds everything in view, the notifyItemChanged method allows more fine-grained control of what gets updated. This helps improve performance. To navigate the selection from item to item using the keyboard, the adapter attaches a keyboard event listener to the view and tries to select a different item using this helper function:
The interesting thing here is the call to the LayoutManager’s scrollToPosition method. I was very happily surprised to see this method does just what I wanted. If the item is already visible, the view does not scroll. The view only scrolls enough to bring the item into view if it was offscreen. The ListView implementation, on the other hand, scrolls the item to the top - if you wanted to keep the list from scrolling, you had to do a bunch of math with offsets and call selectItemFromTop. And that’s it - the only other key point is that the adapter sets the itemView selection state based on the selected item position. You need to use a state list drawable on the item background to visually indicate the selected item. Here’s the whole class:
Having fun with the RecyclerView? Leave a comment below.