分页 v3 不适用于开箱即用的 recyclerview-selection,因为选择库确实使用了稳定的 id,但分页 v3 不支持它们。
要使它们相互协作,您需要实现自己的稳定 id 密钥提供程序。一旦绑定到回收站视图,它就会保存项目 ID。
class MyStableIdKeyProvider(
private val mRecyclerView: RecyclerView
) : ItemKeyProvider<Long>(SCOPE_CACHED) {
init {
mRecyclerView.addOnChildAttachStateChangeListener(
object : RecyclerView.OnChildAttachStateChangeListener {
override fun onChildViewAttachedToWindow(view: View) {
onAttached(view)
}
override fun onChildViewDetachedFromWindow(view: View) {
onDetached(view)
}
}
)
}
private val mPositionToKey = mutableMapOf<Int, Long>()
private val mKeyToPosition = mutableMapOf<Long, Int>()
fun /* synthetic access */onAttached(view: View) {
val holder = mRecyclerView.findContainingViewHolder(view)
if (holder == null) {
Log.w(TAG, "Unable to find ViewHolder for View. Ignoring onAttached event.")
return
}
val position = holder.bindingAdapterPosition
val myItemId = (holder as ItemVH).myItemId
if (position != RecyclerView.NO_POSITION && myItemId != null) {
mPositionToKey[position] = myItemId
mKeyToPosition[myItemId] = position
}
}
fun /* synthetic access */onDetached(view: View) {
val holder = mRecyclerView.findContainingViewHolder(view)
if (holder == null) {
Log.w(TAG, "Unable to find ViewHolder for View. Ignoring onDetached event.")
return
}
val position = holder.bindingAdapterPosition
val myItemId = (holder as ItemVH).myItemId
if (position != RecyclerView.NO_POSITION && myItemId != null) {
mPositionToKey.remove(position)
mKeyToPosition.remove(myItemId)
}
}
override fun getKey(position: Int): Long? = mPositionToKey[position]
override fun getPosition(key: Long): Int = mKeyToPosition[key] ?: RecyclerView.NO_POSITION
companion object {
private const val TAG = "MyKeyProvider"
}
}
您的 ItemVH 必须提供其 ID。您不能使用 getItemId(),因为它总是返回 NO_ID。
class ItemVH(
view: View,
selectionTracker: SelectionTracker<Long>,
) : RecyclerView.ViewHolder(view) {
protected var myItem: MyItem? = null
val myItemId: Long? get() = myItem?.id
fun bind(myItem: MyItem, position: Int) {
this.myItem = myItem
// Put data to item's views
// ..
// Update checkmark visibility passing `myItemId` to the selection tracker
if (selectionTracker.isSelected(myItemId)) {
selectedView.visibility = View.VISIBLE
} else {
selectedView.visibility = View.GONE
}
}
fun getItemDetails() = object: ItemDetailsLookup.ItemDetails<Long>() {
override fun getPosition() = bindingAdapterPosition
override fun getSelectionKey() = myItemId
}
fun clear() {
myItem = null
}
}
适配器很简单
class MyItemListAdapter : PagingDataAdapter<MyItem, ItemVH>(DIFF_CALLBACK) {
lateinit var selectionTracker: SelectionTracker<Long>
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ItemVH {
val view = LayoutInflater.from(parent.context).inflate(R.layout.item, parent, false)
return ItemVH(view, selectionTracker)
}
override fun onBindViewHolder(viewHolder: ItemVH, position: Int) {
val myItem = getItem(position)
if (myItem == null) {
viewHolder.clear()
} else {
viewHolder.bind(myItem, position)
}
}
companion object {
private val DIFF_CALLBACK = object :
DiffUtil.ItemCallback<MyItem>() {
// ...
}
}
}
构建选择跟踪器需要项目详细信息查找:
class ItemListLookup(
private val rv: RecyclerView
) : ItemDetailsLookup<Long>() {
override fun getItemDetails(e: MotionEvent): ItemDetails<Long>? {
val view = rv.findChildViewUnder(e.x, e.y)
if(view != null) {
return (rv.getChildViewHolder(view) as ItemVH)
.getItemDetails()
}
return null
}
}
片段联系在一起
class MyFragment : Fragment() {
private val adapter = MyItemListAdapter()
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
view.recyclerView.adapter = adapter
adapter.selectionTracker = SelectionTracker.Builder<Long>(
"item_selection",
view.recyclerView,
MyStableIdKeyProvider(view.recyclerView),
ItemListLookup(view.recyclerView),
StorageStrategy.createLongStorage()
).build()
adapter.selectionTracker.addObserver(object : SelectionTracker.SelectionObserver<Long>() {
override fun onItemStateChanged(key: Long, selected: Boolean) {
// handle selection change event
}
override fun onSelectionCleared() {
// clear selection
}
})
// ...
}
}