RecyclerView-Selection

构建app

class MainActivity : AppCompatActivity() {

    private val adapter = MainAdapter()

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        recyclerView.layoutManager = LinearLayoutManager(this)
        recyclerView.adapter = adapter
        adapter.list = createRandomIntList()
        adapter.notifyDataSetChanged()
    }

    private fun createRandomIntList(): List {
        val random = Random()
        return (1..10).map { random.nextInt() }
    }
}
class MainAdapter : RecyclerView.Adapter() {
    var list: List = arrayListOf()

    override fun onBindViewHolder(holder: ViewHolder, position: Int) {
        val number = list[position]
        holder.bind(number)
    }

    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
        val itemView = LayoutInflater
            .from(parent.context)
            .inflate(R.layout.item_row, parent, false)
        return ViewHolder(itemView)
    }

    override fun getItemCount(): Int {
        return list.size
    }

    inner class ViewHolder(view: View) : RecyclerView.ViewHolder(view) {
        private var text: TextView = view.findViewById(R.id.text)

        fun bind(value: Int) {
            text.text = value.toString()
        }
    }
}

继承RecyclerView-Selection

在app/build.gradle中添加如下代码

implementation 'androidx.recyclerview:recyclerview-selection:1.0.0'

选择一个key类型

选择一个key类型用来构建KeyProvider,selection库只支持三种类型:Parcelable, String and Long.

下面是对于该选用什么类型的建议:

Parcelable:任何Parcelable都可以用作selection的key,如果view中的内容与稳定的content:// uri相关联,你就使用uri作为你的key的类型

String:当基于字符串的稳定标识符可用时使用String

Long:当RecyclerView的long stable ID已经投入使用时,请使用Long,但是会有一些限制,在运行时访问一个稳定的id会被限定

我们将选择Long并使用列表项的位置作为其ID,首先我们需要id是稳定的,我们需要将setHasStableIds设置为true,将该选项设置为true只会告诉RecyclerView数据集中的每个项目都可以用Long类型的唯一标识符表示

init {
  setHasStableIds(true)
{

现在我们使用item的pisition作为id,需要实现getItemId方法并且返回item的position作为id

override fun getItemId(position:Int):Long = position.toLong()

实现KeyProvider

现在我们选择了我们的密钥类型,接着实现我们的KeyProvider了。事实证明,选择库为我们提供了StableIdKeyProvider的实现

实现ItemDetailsLookup

这个类将为选择库提供有关与用户选择关联的项目的信息,该选择基于MotionEvent,所以我们必须映射到我们的ViewHolders,返回产生MotionEvent事件的item的信息

class MyItemDetailsLookup(private val recyclerView: RecyclerView):ItemDetailsLookup(){
  override fun getItemDetails(event: MotionEvent): ItemDetails? {
        val view = recyclerView.findChildViewUnder(event.x, event.y)
        if (view != null) {
            return (recyclerView.getChildViewHolder(view) as MainAdapter.ViewHolder)
                .getItemDetails()
        }
        return null
    }
}

要返回这些信息,我们需要在ViewHolder中创建一个新方法,该方法返回一个ItemDetails的实例

fun getItemDetails(): ItemDetailsLookup.ItemDetails =
    object : ItemDetailsLookup.ItemDetails() {
        override fun getPosition(): Int = adapterPosition
        override fun getSelectionKey(): Long? = itemId
    }

高亮选择的items

创建一个drawable用来根据item的状态来改变颜色



    
    

然后将该drawable作为item的背景

android:background="@drawable/item_background"

在adapter中我们需要添加一个tracker字段,tracker就是用来让selection library跟踪用户的选择项,在MainActivity中创建该追踪器并且设置给adapter

var tracker: SelectionTracker? = null

我们还需要在viewholder中添加一个boolean参数用来告诉viewholder该position的item是否被用户选中

override fun onBindViewHolder(holder: ViewHolder, position: Int) {
    val number = list[position]
    tracker?.let {
        holder.bind(number, it.isSelected(position.toLong()))
    }
}

最后我们需要改变bind方法使用bool值来改变item的状态

fun bind(value: Int, isActivated: Boolean = false) {
    text.text = value.toString()
    itemView.isActivated = isActivated
}

创建tracker

到MainActivity中创建一个新的tracker,使用selection library提供的SelectionTracker.Builder

一下是builder需要的参数

  1. selectionId 一个字符串,用来在Activity或Fragment中标识我们的选择项
  2. recyclerView 需要应用跟踪器的RecyclerView
  3. keyProvider 选择键的来源
  4. detailsLookup RecyclerView items的详细信息
  5. storage 选择状态的类型安全存储策略

除了我们之前创建的MyItemDetailsLookup之外,其他所有内容都由选择库提供。最后,我们将指定一个SelectionPredicate,允许选择多个项目而不受任何限制。

tracker = SelectionTracker.Builder(
    "mySelection",
    recyclerView,
    StableIdKeyProvider(recyclerView),
    MyItemDetailsLookup(recyclerView),
    StorageStrategy.createLongStorage()
).withSelectionPredicate(
    SelectionPredicates.createSelectAnything()
).build()
adapter.tracker = tracker

SelectionPredicates.createSelectAnything()允许我们选择多个item,你也可以创建自己的SelectionPredicate实现不同的抽象方法,返回true允许选择,false为不允许

return object : SelectionTracker.SelectionPredicate() {
    override fun canSetStateForKey(key: K, nextState: Boolean): 
    Boolean {
        return true
    }

    override fun canSetStateAtPosition(position: Int, nextState:  
    Boolean): Boolean {
        return true
    }

    override fun canSelectMultiple(): Boolean {
        return true
    }
}

选择观察者

现在我们有一个列表,我们可以选择多个项目,可以添加一个观察者来观察当前的选择项并做一些工作。
下面就是观察者代码,当选择项改变时,就会执行下面的代码

tracker?.addObserver(
    object : SelectionTracker.SelectionObserver() {
        override fun onSelectionChanged() {
            super.onSelectionChanged()
            val items = tracker?.selection!!.size()
            if (items == 2) {
                launchSum(tracker?.selection!!)
            }
        }
    })
private fun launchSum(selection: Selection) {
    val list = selection.map {
        adapter.list[it.toInt()]
    }.toList()
    SumActivity.launch(this, list as ArrayList)
}

在生命周期事件中保持选择状态

如果我们旋转屏幕时所选择的item就会消失,事实上,如果旋转屏幕就会发生闪退:java.lang.NullPointerException: Attempt to invoke virtual method ‘int androidx.recyclerview.widget.RecyclerView$ViewHolder.getAdapterPosition()’ on a null object reference
这里我们创建自己的ItemKeyProvider替换掉从选择库中获取的StableIdKeyProvider

class MyItemKeyProvider(private val recyclerView: RecyclerView) :
    ItemKeyProvider(ItemKeyProvider.SCOPE_MAPPED) {

    override fun getKey(position: Int): Long? {
        return recyclerView.adapter?.getItemId(position)
    }

    override fun getPosition(key: Long): Int {
        val viewHolder = recyclerView.findViewHolderForItemId(key)
        return 
            viewHolder?.layoutPosition ?: RecyclerView.NO_POSITION
    }
}

原文地址:https://proandroiddev.com/a-guide-to-recyclerview-selection-3ed9f2381504

你可能感兴趣的:(RecyclerView-Selection)