RecyclerView實現(xiàn)單選多選功能

又來更新小功能了,項目中經(jīng)常會遇到單選多選功能,總是草草的寫下沒有系統(tǒng)總結(jié),今天來記錄一下。這篇是用RecyclerView實現(xiàn)單選多選功能,下一篇再來講用RecyclerView實現(xiàn)折疊效果的樹形結(jié)構(gòu)。

1. 效果圖

單選.gif

單選取消.gif

多選.gif

2. RecyclerView實現(xiàn)單選功能

2.1 實現(xiàn)思路

  • itemView布局內(nèi)的字體顏色和背景使用selector來控制,所以當(dāng)RecyclerView的itemView的isSelect屬性為true時,該布局內(nèi)的顏色和字體會變?yōu)檫x中狀態(tài)下的顏色。
  • 當(dāng)點擊新的itemView時,將舊的itemView設(shè)置為false,新的點擊位置設(shè)置為true,即可實現(xiàn)單選的效果。

2.2 具體實現(xiàn)

2.2.1創(chuàng)建布局

<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="72dp"
    android:layout_height="92dp"
    android:background="@drawable/bg_selector"
    xmlns:app="http://schemas.android.com/apk/res-auto">
    <TextView
        android:id="@+id/tvDate"
        android:text="10/28"
        android:textSize="15sp"
        android:textColor="@color/text_sel"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toRightOf="parent"
        app:layout_constraintTop_toTopOf="parent"
        android:layout_marginTop="20dp"/>
  ......
</androidx.constraintlayout.widget.ConstraintLayout>

bg_selector

<selector xmlns:android="http://schemas.android.com/apk/res/android">
    <item android:drawable="@color/colorBlue" android:state_selected="true"></item>
    <item android:drawable="@color/colorWhite" android:state_selected="false"></item>
</selector>

text_sel 同理

這里的selector主要用到了state_selected屬性,當(dāng)為true時代表選中,設(shè)置背景為藍(lán)色,否則設(shè)置為灰色

2.2.2 創(chuàng)建適配器邏輯

class SingleSelectAdapter(var mDataList: MutableList<String>) :
RecyclerView.Adapter<SingleSelectAdapter.MyViewHolder>() {

    //選擇的位置
    var selPosition = 0
    //臨時記錄上次選擇的位置
    var temp =-1

    override fun onBindViewHolder(holder: MyViewHolder, position: Int) {
        holder.date.text = mDataList[position]

        holder.itemView.isSelected = holder.layoutPosition==selPosition

        holder.itemView.setOnClickListener {
            holder.itemView.isSelected =true
            //將舊的位置保存下來,用于后面把舊的位置顏色變回來
            temp = selPosition
            //設(shè)置新的位置
            selPosition = holder.layoutPosition
            //更新舊位置
            notifyItemChanged(temp)
        }
    }
}

在該適配器中,我們使用到兩個變量,一個變量用來記錄當(dāng)前點擊的位置,即選中的位置;一個變量用來臨時記錄當(dāng)點擊新的位置時,舊的位置,防止selPosition賦新值后舊的位置找不到了。

具體的邏輯在onBindViewHolder()方法內(nèi)

  • holder.itemView.isSelected = holder.layoutPosition==selPosition當(dāng) 當(dāng)前的itemView位置是selPosition時,將其設(shè)置為true,否則設(shè)置為false。

  • 當(dāng)點擊新位置時,先將點擊位置itemView的isSelected設(shè)置為true代表選中,然后用temp記錄下原先選中的位置,將新的位置保存在selPosition中,然后再將舊位置進(jìn)行更新。

2.2.4 出現(xiàn)的問題

單選閃爍.gif

看動畫,你會發(fā)現(xiàn)當(dāng)點擊新的位置時,舊位置會發(fā)生閃爍,這是因為RecyclerView默認(rèn)設(shè)置了DefaultItemAnimator動畫,所以在調(diào)用notifyItemChanged()方法時,會產(chǎn)生動畫,發(fā)生閃爍現(xiàn)象。

解決方案:

(mRecyclerView.itemAnimator as DefaultItemAnimator).supportsChangeAnimations = false

將其設(shè)置為不支持?jǐn)?shù)據(jù)更改時的動畫即可。

2.3 可取消的單選

2.3.1 實現(xiàn)思路

要實現(xiàn)可取消的單選,只需要將上面的Adapter更改兩個地方

  • 將selPosition設(shè)置為-1,代表默認(rèn)不選中任何選項
  • 更改onBindViewHolder()內(nèi)ItemView的點擊事件邏輯

2.3.2 具體實現(xiàn)

class SingleSelectAdapter(var mDataList: MutableList<String>) :
RecyclerView.Adapter<SingleSelectAdapter2.MyViewHolder>() {
 
    private var mItemClickListener: MyItemClickListener?=null

    //選擇的位置(-1則代表默認(rèn)沒有選中)
    private var selPosition = -1
    //臨時記錄上次選擇的位置
    private var temp = -1

    .....
    override fun onBindViewHolder(holder: SingleSelectAdapter2.MyViewHolder, position: Int) {
        holder.date.text = mDataList[position]

        holder.itemView.isSelected = holder.layoutPosition == selPosition

        holder.itemView.setOnClickListener {
            //已選中則取消選中,更新原位置
            if (it.isSelected) {
                it.isSelected = false
                notifyItemChanged(selPosition)
                selPosition = -1
                //更新舊位置
                mItemClickListener?.onClick(holder.layoutPosition,false)
            }else{
                holder.itemView.isSelected = true
                //將舊的位置保存下來,用于后面把舊的位置顏色變回來
                temp = selPosition
                //設(shè)置新的位置
                selPosition = holder.layoutPosition
                //更新舊位置
                notifyItemChanged(temp)
                mItemClickListener?.onClick(holder.layoutPosition,true)
            }
        }
    }

    interface MyItemClickListener{
        fun onClick(position:Int,isSelect:Boolean)
    }
    fun setOnMyItemClickListener(listener:MyItemClickListener){
        this.mItemClickListener = listener
    }
}

3. RecyclerView實現(xiàn)多選功能

3.1 實現(xiàn)思路

  • 相比及單選,多選就容易多了,布局和單選的一樣,也是使用selector來控制選中和未選中狀態(tài)的顏色。
  • 用集合來保存選中的位置下標(biāo)。
  • 當(dāng)點擊itemView時,若該itemView的下標(biāo)不存在于集合中,則將該位置放入集合,且該位置的isSelect屬性設(shè)置為true;若存在于集合中,則將其從集合中remove掉,然后將該位置的isSelect屬性設(shè)置為false即可。

3.2 具體實現(xiàn)

class MutilSelectAdapter(val dataList:MutableList<String>):RecyclerView.Adapter<MutilSelectAdapter.MyViewHolder>() {

    //用來記錄已經(jīng)勾選的位置(set集合是為了防止放入重復(fù)數(shù)據(jù))
    var mutilSelectedList = mutableSetOf<Int>()

    override fun onBindViewHolder(holder: MyViewHolder, position: Int) {
        holder.tvContent.text = dataList[position]
        holder.ivSelect.isSelected = mutilSelectedList.contains(position)
        holder.itemView.setOnClickListener {
            if (mutilSelectedList.contains(position)) {
                mutilSelectedList.remove(position)
                holder.ivSelect.isSelected = false
                Log.i(TAG, "onBindViewHolder: 取消選中")
            } else {
                mutilSelectedList.add(position)
                holder.ivSelect.isSelected = true
                Log.i(TAG, "onBindViewHolder: 選中")
            }
        }
    }
}

總結(jié)

總體上還是很簡單的,無非就是用isSelect屬性配合Selector來實現(xiàn)選中和未選中的效果,然后就是Adapter內(nèi)點擊事件里選中和未選中的邏輯設(shè)定,沒有太多難點。以后遇到的無論是橫向還是縱向,什么樣的布局,無非就是item布局更改一下方向改變一下,具體的操作沒什么難點。項目Github地址

如果本文對你有幫助,請別忘記三連,如果有不恰當(dāng)?shù)牡胤揭舱執(zhí)岢鰜?,下篇文章見?/p>

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容