Hey I am working in reyclerview selection. When first reyclerview load I want to show default selection then after I click then show selected item selection. But it's not working. Default selection is working, but after clicking on other item it's not selecting the item.
MainActivity.kt
class MainActivity : AppCompatActivity() {
private lateinit var binding: ActivityMainBinding
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
binding = ActivityMainBinding.inflate(layoutInflater)
setContentView(binding.root)
val selectionAdapter = SelectionAdapter()
selectionAdapter.submitList(createList())
binding.recyclerView.apply {
layoutManager =
LinearLayoutManager(this@MainActivity, LinearLayoutManager.HORIZONTAL, false)
adapter = selectionAdapter
}
}
private fun createList(): List<Data> {
return listOf(
Data("1"),
Data("2"),
Data("3", true),
Data("4"),
)
}
data class Data(
val value: String? = null,
val defaultValue: Boolean? = null
)
}
SelectionAdapter.kt
class SelectionAdapter :
ListAdapter<MainActivity.Data, SelectionAdapter.SelectionViewHolder>(COMPARATOR) {
var selectedItemPosition: Int = 0
set(value) {
val oldPosition = field
field = value
notifyItemChanged(oldPosition)
notifyItemChanged(value)
}
companion object {
private val COMPARATOR = object : DiffUtil.ItemCallback<MainActivity.Data>() {
override fun areItemsTheSame(
oldItem: MainActivity.Data,
newItem: MainActivity.Data
): Boolean {
return true
}
override fun areContentsTheSame(
oldItem: MainActivity.Data,
newItem: MainActivity.Data
): Boolean {
return true
}
}
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): SelectionViewHolder {
return SelectionViewHolder(
SelectionItemLayoutBinding.inflate(
LayoutInflater.from(parent.context),
parent,
false
)
)
}
override fun onBindViewHolder(holder: SelectionViewHolder, position: Int) {
holder.binding.root.setOnClickListener {
selectedItemPosition = holder.adapterPosition
holder.binding.root.isSelected = selectedItemPosition == position
}
holder.bindItem(getItem(position))
}
inner class SelectionViewHolder(val binding: SelectionItemLayoutBinding) :
RecyclerView.ViewHolder(binding.root) {
fun bindItem(item: MainActivity.Data) {
binding.textView.text = item.value
binding.root.isSelected = item.defaultValue == true
}
}
}
selection_item_layout.xml
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginEnd="10dp"
android:padding="5dp"
android:background="@drawable/options_item_selector_background"
tools:context=".MainActivity">
<TextView
android:id="@ id/textView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_margin="10dp"
android:text="1"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>
mainactivity.xml
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">
<androidx.recyclerview.widget.RecyclerView
android:id="@ id/recyclerView"
android:layout_width="match_parent"
android:layout_height="match_parent" />
</androidx.constraintlayout.widget.ConstraintLayout>
options_item_default_background.xml
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle">
<stroke
android:width="1dp"
android:color="#D8DFED" />
<corners android:radius="1dp" />
</shape>
options_item_selector_background.xml
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:drawable="@drawable/options_item_selected_background" android:state_pressed="false" android:state_selected="true" />
<item android:drawable="@drawable/options_item_default_background" android:state_selected="false" />
</selector>
options_item_selected_background.xml
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle">
<stroke
android:width="1dp"
android:color="#213F66" />
<corners android:radius="1.5dp" />
</shape>
I am posting my video link
CodePudding user response:
Your adapter never reads from selectedItemPosition
, so how could it ever change which item is shown as selected?
By using the defaultValue
from the list items every time you bind the items, they will never be able to change either.
To simplify this, let your adapter treat selectedItemPosition
as the single source of truth about what should be selected. The Activity should tell it which item to start with:
val selectionAdapter = SelectionAdapter()
val list = createList()
selectionAdapter.selectedItemPosition = list.indexOfFirst { it.defaultValue == true }
selectionAdapter.submitList(list)
Your adapter should exclusively use selectedItemPosition
as its source for whether an item should appear selected. And the click listener only needs to change the selected item. It's pointless to have it change the item's appearance manually because this can only briefly change how it looks until the next time the view holder is bound.
override fun onBindViewHolder(holder: SelectionViewHolder, position: Int) {
holder.binding.root.setOnClickListener {
selectedItemPosition = holder.adapterPosition
}
holder.bindItem(getItem(position), selectedItemPosition == position)
}
inner class SelectionViewHolder(val binding: SelectionItemLayoutBinding) :
RecyclerView.ViewHolder(binding.root) {
fun bindItem(item: MainActivity.Data, isSelected: Boolean) = with(binding) {
textView.text = item.value
root.isSelected = isSelected
}
}