又來(lái)更新小功能了详囤,項(xiàng)目中經(jīng)常會(huì)遇到單選多選功能,總是草草的寫下沒(méi)有系統(tǒng)總結(jié)镐作,今天來(lái)記錄一下藏姐。這篇是用RecyclerView實(shí)現(xiàn)單選多選功能,下一篇再來(lái)講用RecyclerView實(shí)現(xiàn)折疊效果的樹形結(jié)構(gòu)该贾。
1. 效果圖
2. RecyclerView實(shí)現(xiàn)單選功能
2.1 實(shí)現(xiàn)思路
- itemView布局內(nèi)的字體顏色和背景使用
selector
來(lái)控制羔杨,所以當(dāng)RecyclerView的itemView的isSelect
屬性為true時(shí),該布局內(nèi)的顏色和字體會(huì)變?yōu)檫x中狀態(tài)下的顏色靶庙。 - 當(dāng)點(diǎn)擊新的itemView時(shí)问畅,將舊的itemView設(shè)置為false娃属,新的點(diǎn)擊位置設(shè)置為true六荒,即可實(shí)現(xiàn)單選的效果。
2.2 具體實(shí)現(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í)代表選中掏击,設(shè)置背景為藍(lán)色,否則設(shè)置為灰色
2.2.2 創(chuàng)建適配器邏輯
class SingleSelectAdapter(var mDataList: MutableList<String>) :
RecyclerView.Adapter<SingleSelectAdapter.MyViewHolder>() {
//選擇的位置
var selPosition = 0
//臨時(shí)記錄上次選擇的位置
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
//將舊的位置保存下來(lái)秩铆,用于后面把舊的位置顏色變回來(lái)
temp = selPosition
//設(shè)置新的位置
selPosition = holder.layoutPosition
//更新舊位置
notifyItemChanged(temp)
}
}
}
在該適配器中砚亭,我們使用到兩個(gè)變量,一個(gè)變量用來(lái)記錄當(dāng)前點(diǎn)擊的位置殴玛,即選中的位置捅膘;一個(gè)變量用來(lái)臨時(shí)記錄當(dāng)點(diǎn)擊新的位置時(shí),舊的位置滚粟,防止selPosition賦新值后舊的位置找不到了寻仗。
具體的邏輯在onBindViewHolder()
方法內(nèi)
holder.itemView.isSelected = holder.layoutPosition==selPosition
當(dāng) 當(dāng)前的itemView位置是selPosition時(shí),將其設(shè)置為true凡壤,否則設(shè)置為false署尤。當(dāng)點(diǎn)擊新位置時(shí),先將點(diǎn)擊位置itemView的
isSelected
設(shè)置為true代表選中亚侠,然后用temp記錄下原先選中的位置曹体,將新的位置保存在selPosition中,然后再將舊位置進(jìn)行更新硝烂。
2.2.4 出現(xiàn)的問(wèn)題
看動(dòng)畫箕别,你會(huì)發(fā)現(xiàn)當(dāng)點(diǎn)擊新的位置時(shí),舊位置會(huì)發(fā)生閃爍,這是因?yàn)镽ecyclerView默認(rèn)設(shè)置了DefaultItemAnimator動(dòng)畫串稀,所以在調(diào)用notifyItemChanged()
方法時(shí)啥酱,會(huì)產(chǎn)生動(dòng)畫,發(fā)生閃爍現(xiàn)象厨诸。
解決方案:
(mRecyclerView.itemAnimator as DefaultItemAnimator).supportsChangeAnimations = false
將其設(shè)置為不支持?jǐn)?shù)據(jù)更改時(shí)的動(dòng)畫即可镶殷。
2.3 可取消的單選
2.3.1 實(shí)現(xiàn)思路
要實(shí)現(xiàn)可取消的單選,只需要將上面的Adapter更改兩個(gè)地方
- 將selPosition設(shè)置為-1微酬,代表默認(rèn)不選中任何選項(xiàng)
- 更改
onBindViewHolder()
內(nèi)ItemView的點(diǎn)擊事件邏輯
2.3.2 具體實(shí)現(xiàn)
class SingleSelectAdapter(var mDataList: MutableList<String>) :
RecyclerView.Adapter<SingleSelectAdapter2.MyViewHolder>() {
private var mItemClickListener: MyItemClickListener?=null
//選擇的位置(-1則代表默認(rèn)沒(méi)有選中)
private var selPosition = -1
//臨時(shí)記錄上次選擇的位置
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
//將舊的位置保存下來(lái),用于后面把舊的位置顏色變回來(lái)
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實(shí)現(xiàn)多選功能
3.1 實(shí)現(xiàn)思路
- 相比及單選颗管,多選就容易多了陷遮,布局和單選的一樣,也是使用
selector
來(lái)控制選中和未選中狀態(tài)的顏色垦江。 - 用集合來(lái)保存選中的位置下標(biāo)帽馋。
- 當(dāng)點(diǎn)擊itemView時(shí),若該itemView的下標(biāo)不存在于集合中比吭,則將該位置放入集合绽族,且該位置的isSelect屬性設(shè)置為true;若存在于集合中衩藤,則將其從集合中remove掉吧慢,然后將該位置的isSelect屬性設(shè)置為false即可。
3.2 具體實(shí)現(xiàn)
class MutilSelectAdapter(val dataList:MutableList<String>):RecyclerView.Adapter<MutilSelectAdapter.MyViewHolder>() {
//用來(lái)記錄已經(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é)
總體上還是很簡(jiǎn)單的赏表,無(wú)非就是用isSelect屬性配合Selector來(lái)實(shí)現(xiàn)選中和未選中的效果检诗,然后就是Adapter內(nèi)點(diǎn)擊事件里選中和未選中的邏輯設(shè)定,沒(méi)有太多難點(diǎn)瓢剿。以后遇到的無(wú)論是橫向還是縱向逢慌,什么樣的布局,無(wú)非就是item布局更改一下方向改變一下间狂,具體的操作沒(méi)什么難點(diǎn)攻泼。項(xiàng)目Github地址
如果本文對(duì)你有幫助,請(qǐng)別忘記三連前标,如果有不恰當(dāng)?shù)牡胤揭舱?qǐng)?zhí)岢鰜?lái)坠韩,下篇文章見(jiàn)。