Home > Blockchain >  selection not working in reyclerview item in android
selection not working in reyclerview item in android

Time:02-21

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
    }
}
  • Related