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



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)的問題

看動畫,你會發(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>