使用带有分页的recyclerview选择3

问题描述 投票:0回答:3

我正在尝试将Selection(https://developer.android.com/reference/androidx/recyclerview/selection/package-summary)与新的分页库(所以分页3)一起使用

使用 Paging 2 是可行的,因为我们使用的是 PagedListAdapter,并且它与 Selection 库一起工作,但现在使用新的 PagingDataAdapter 我无法再让它工作了。

https://developer.android.com/reference/kotlin/androidx/paging/PagingDataAdapter

我们正在失去 getCurrentList(),setHasStableIds() 现在将返回 UnsupportedOperationException。

因此,如果有人正在使用它,我将非常感谢对此的帮助。

android android-recyclerview selection android-paging-3
3个回答
2
投票

在新的 Paging3 库中,您可以使用

snapShot()
类的
PagingDataAdapter
方法获取当前列表。

我最近遇到了同样的密钥提供程序问题,因此我实现了一个自定义密钥提供程序,如下所示:

class MyItemKeyProvider(private val adapter: MyPagingAdapter) :
    ItemKeyProvider<String>(SCOPE_CACHED) {
    override fun getKey(position: Int): String = adapter.snapshot().items[position].id
    override fun getPosition(key: String): Int = adapter.snapshot().items.indexOfFirst { it.id == key }

1
投票

如果您已经将其与 Paging 2 一起使用,我建议您首先实现您自己的

ItemKeyProvider<K>
。打包的
StableIdKeyProvider
无法使用,因为它需要启用稳定 ID,并且正如您所说,
PagingDataAdapter
不支持稳定 ID。


0
投票

Paging v3 无法与开箱即用的 recyclerview-selection 一起使用,因为选择库确实使用稳定的 ID,但 Paging 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
            }
        })
        
        // ...
    }
}
© www.soinside.com 2019 - 2024. All rights reserved.