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.
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.
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()
Data set of adapter can be mutable. In this case adapter must invoke notifyDataSetChanged() method or more precision methods like notifyItemRangeInserted().
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).
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
<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)
Don't use view as divider, more efficient to use ItemDecoration
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.
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.