选择在 android 中的 recyclerview 项目中不起作用

selection not working in reyclerview item in android

嘿,我在 reyclerview selection 工作。第一次加载 reyclerview 时,我想显示默认选择,然后在单击后显示所选项目选择。但它不起作用。默认选择有效,但在点击其他项目后它没有选择该项目。

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>

我正在发布我的视频link

您的适配器从不读取 selectedItemPosition,那么它怎么能改变显示为选中的项目?

通过在每次绑定项目时使用列表项目中的 defaultValue,它们将永远无法更改。

为简化这一点,让您的适配器将 selectedItemPosition 视为关于应该选择什么的唯一真实来源。 Activity 应该告诉它从哪个项目开始:

val selectionAdapter = SelectionAdapter()
val list = createList()
selectionAdapter.selectedItemPosition = list.indexOfFirst { it.defaultValue == true }
selectionAdapter.submitList(list)

您的适配器应专门使用 selectedItemPosition 作为其来源,以确定项目是否应显示为已选中。而点击监听器只需要改变选中的项目。让它手动改变项目的外观是没有意义的,因为这只能短暂地改变它的外观,直到下一次绑定视图持有者。

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