RecyclerView

RecyclerView display large sets of data. You supply the data and define how each item looks.

When an item scrolls off the screen, RecyclerView doesn't destroy its view. Instead, RecyclerView reuses the view for new items that have scrolled onscreen. This reuse vastly improves performance, improving your app's responsiveness and reducing power consumption.

Add dependency
implementation("androidx.recyclerview:recyclerview:1.2.1")
// For control over item selection of both touch and mouse driven selection
implementation("androidx.recyclerview:recyclerview-selection:1.1.0")

adapter

RecyclerView.Adapter and RecyclerView.ViewHolder define how your data is displayed.

Custom adapter

You can use different views for different data types. For this define the view holders and override adapter methods:

  • getItemViewType() - return the view type of the item at position for the purposes of view recycling
  • onCreateViewHolder() - now you should take in account type of data
  • onBindViewHolder- now you should take in account type of data. You can create base class for your holders with method bind()
Aldapter with multiple views

Data set of adapter can be mutable. In this case adapter must invoke notifyDataSetChanged() method or more precision methods like notifyItemRangeInserted().

Adapter with mutable data

layout manager

By default items layout as vertical list. You can set other layout manager:

  • LinearLayoutManager - arranges the items in a one-dimensional list
  • GridLayoutManager - arranges all items in a two-dimensional grid
  • StaggeredGridLayoutManager - similar to GridLayoutManager, but it does not require that items in a row have the same height (for vertical grids) or items in the same column have the same width (for horizontal grids).
Set horizontal layout
override fun onCreate(savedInstanceState: Bundle?) {
    // ...

    val layoutManager = LinearLayoutManager(
                            requireContext(),
                            LinearLayoutManager.HORIZONTAL, 
                            false)

    val lst = findViewById(R.id.recycler_view) as RecyclerView
    lst.layoutManager = layoutManager
}

Also you can specify a layout manager in the xml resource

Grid layout manager
<androidx.recyclerview.widget.RecyclerView
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    app:layoutManager="androidx.recyclerview.widget.GridLayoutManager"
    android:orientation="horizontal"
    app:spanCount="2"
    >

</androidx.recyclerview.widget.RecyclerView>

snapping

The SnapHelper Class intended to support snapping for a RecyclerView.

SnapHelper tries to handle fling as well but for this to work properly, the RecyclerView.LayoutManager must implement the RecyclerView.SmoothScroller.ScrollVectorProvider interface or you should override onFling(int, int) and handle fling manually.

Android provides two default implementation:

  • LinearSnapHelper - snaps the center of the target child view to the center of the attached RecyclerView. If you intend to change this behavior then override SnapHelper.calculateDistanceToFinalSnap(RecyclerView.LayoutManager, View)
  • PagerSnapHelper - allows to achieve a similar behavior to ViewPager. Additionally you need to set both RecyclerView and the items of the RecyclerView.Adapter to have ViewGroup.LayoutParams.MATCH_PARENT height and width.
myRecyclerView.setLayoutManager(
            LinearLayoutManager(context,LinearLayoutManager.HORIZONTAL, false)
        )

val snapHelper: SnapHelper = PagerSnapHelper()
snapHelper.attachToRecyclerView(myRecyclerView)

decorations

An ItemDecoration class allows the application to add a special drawing and layout offset to specific item views from the adapter's data set. This can be useful for drawing dividers between items, highlights, visual grouping boundaries and more.

All ItemDecorations are drawn in the order they were added.

method description
getItemOffsets(outRect, view, recyclerView, state) Retrieves any offsets for the given item.
onDraw(canvas, recyclerView, state) Draws any appropriate decorations into the Canvas supplied to the RecyclerView.
onDrawOver(canvas, recyclerView, state) Draws any appropriate decorations into the Canvas supplied to the RecyclerView (after drawing ViewHolder).
// usage of built-in divider in activity
val dividerItemDecoration = DividerItemDecoration(this, layoutManager.getOrientation())
 
//dividerItemDecoration.setDrawable(resources.getDrawable(R.drawable.divider_drawable))        

recyclerView.addItemDecoration(dividerItemDecoration)
Vertical space

Don't use view as divider, more efficient to use ItemDecoration

Custom divider

item gestures

ItemTouchHelper allows to add swipe to dismiss and drag&drop support to RecyclerView.

ItemTouchHelper.Callback class is the contract between ItemTouchHelper and your application. It lets you control which touch behaviors are enabled per each ViewHolder and also receive callbacks when user performs these actions.

ItemTouchHelper.SimpleCallback is a simple implementation of ItemTouchHelper.Callback. You should still override onMove() or onSwiped() methods depending on your use case.

Add reordering items and delete item on swipe
val itemTouchHelperCallback =
    object : ItemTouchHelper.SimpleCallback(0, ItemTouchHelper.LEFT or
                                               ItemTouchHelper.RIGHT or 
                                               ItemTouchHelper.UP or
                                               ItemTouchHelper.DOWN;
) {
    override fun onMove(
                    recyclerView: RecyclerView,
                    viewHolder: RecyclerView.ViewHolder,
                    target: RecyclerView.ViewHolder
    ): Boolean {
        val fromPos = viewHolder.adapterPosition
        val toPos = target.adapterPosition
        
		// reorder items directly
        if (fromPosition < toPosition)
            for (i in fromPosition until toPosition) {
                Collections.swap(mItems, i, i + 1)
            }
        else for (i in fromPosition downTo toPosition + 1) {
                Collections.swap(mItems, i, i - 1)
        }
        
        // notify directly or use ObservableArrayList
        mAdapter.notifyItemMoved(fromPosition, toPosition)
        return true
    }

    override fun onSwiped(viewHolder: RecyclerView.ViewHolder, direction: Int) {
        val position = viewHolder.adapterPosition  
        
        // remove directly or use view model
        mItems.remove(position);
        
        // notify directly or use ObservableArrayList
        mAdapter.notifyItemRemoved(position)
     }
}

val itemTouchHelper = ItemTouchHelper(itemTouchHelperCallback)
itemTouchHelper.attachToRecyclerView(mRecylerView)

animations

Subclasses of ItemAnimator can be used to implement custom animations for actions on ViewHolder items. The RecyclerView will manage retaining these items while they are being animated, but implementors must call dispatchAnimationFinished() when a ViewHolder's animation is finished.

The DefaultItemAnimator provides default animations for remove, add, and move events.

Also you can see this library for item animation on GitHub.