如何通过在 RecyclerView 中单击来更改背景颜色项目

问题描述 投票:0回答:2

在我的应用程序中,我有

RecyclerView
并使用 DiffUtils 作为 recyclerview
Adapter

click 时,我想要
更改背景
颜色项目的recyclerview
当单击另一个项目时,新项目将背景和上一个项目设置回默认颜色。
我写了下面的代码并最终工作。
但在这段代码中我使用了 notifyDataSetChange 并且我不想使用这个方法!
对我的工作来说最好的解决方案是什么?
我的代码:

class HeartRateAdapter @Inject constructor() : RecyclerView.Adapter<HeartRateAdapter.ViewHolder>() {

    private lateinit var binding: ItemSelectDialogBinding
    private lateinit var context: Context
    private var moviesList = emptyList<Data>()
    private var selectedItem = -1

    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
        binding = ItemSelectDialogBinding.inflate(LayoutInflater.from(parent.context), parent, false)
        context = parent.context
        return ViewHolder()
    }

    override fun onBindViewHolder(holder: ViewHolder, position: Int) {
        //getItem from PagingDataAdapter
        holder.bind(moviesList[position])
        //Not duplicate items
        holder.setIsRecyclable(false)
    }

    override fun getItemCount() = moviesList.size

    inner class ViewHolder : RecyclerView.ViewHolder(binding.root) {

        @SuppressLint("SetTextI18n")
        fun bind(item: Data) {
            binding.apply {
                selectedTxt.text = item.description
                //Click
                binding.root.setOnClickListener {
                    selectedItem = adapterPosition
                    notifyDataSetChanged()
                    onItemClickListener?.let {
                        it(item)
                    }
                }
                //Change color
                if (selectedItem == adapterPosition) {
                    binding.selectedImg.setImageResource(R.drawable.bg_circle_selected)
                } else {
                    binding.selectedImg.setImageResource(R.drawable.bg_circle_un_selected)
                }
            }
        }
    }

    private var onItemClickListener: ((Data) -> Unit)? = null

    fun setOnItemClickListener(listener: (Data) -> Unit) {
        onItemClickListener = listener
    }

    fun setData(data: List<Data>) {
        val moviesDiffUtil = NotesDiffUtils(moviesList, data)
        val diffUtils = DiffUtil.calculateDiff(moviesDiffUtil)
        moviesList = data
        diffUtils.dispatchUpdatesTo(this)
    }

    class NotesDiffUtils(private val oldItem: List<Data>, private val newItem: List<Data>) : DiffUtil.Callback() {

        override fun getOldListSize(): Int {
            return oldItem.size
        }

        override fun getNewListSize(): Int {
            return newItem.size
        }

        override fun areItemsTheSame(oldItemPosition: Int, newItemPosition: Int): Boolean {
            return oldItem[oldItemPosition] === newItem[newItemPosition]
        }

        override fun areContentsTheSame(oldItemPosition: Int, newItemPosition: Int): Boolean {
            return oldItem[oldItemPosition] === newItem[newItemPosition]
        }
    }
} 
android kotlin android-recyclerview
2个回答
0
投票

要在单击 RecyclerView 中的项目时更改其背景颜色,您可以按照使用 Kotlin 的 Android 开发中的这些常规步骤进行操作。请记住,此示例假设您对设置 RecyclerView 及其适配器有基本的了解。


0
投票

我更愿意将选定的状态保存在数据模型中。假设您有一个像这样的数据模型来显示名称列表:

data class Data(
  val name: String,
  val isSelected: Boolean
)

这就是 ViewModel 中 UI 状态的内容。

class SampleViewModel: ViewModel {
  private val _uiState: MutableStateFlow<List<Data>>
  val uiState: StateFlow<List<Data> = _uiState.asStateFlow()

  // A function to change the state of a view when the user clicks on it
  fun onItemClicked(position: Int) {
    _uiState.update { items ->
      items.mapIndexed { index, item ->
        item.copy(isSelected = index == position)  
      }
    }
  }
}

然后你需要在你的Fragment/Activity中收集这个状态,但在此之前,最好为我们的recyclerview适配器创建另一个数据模型。这样您就可以区分 UI 逻辑和业务逻辑。

data class NameItem(
  val name: String,
  val backgroundColor: Int
)

然后你的片段会是这样的:

class MyFragment : Fragment() {
  private val viewModel: SampleViewModel by viewModels()

  override fun onCreateView(
    inflater: LayoutInflater, container: ViewGroup?,
    savedInstanceState: Bundle?
  ): View? {
    val binding = FragmentMyBinding.inflate(inflater, container, false)
    val adapter = MyAdapter { position ->
       viewModel.onItemClicked(position)
    }

    binding.recyclerView.layoutManager = LinearLayoutManager(requireContext())
    binding.recyclerView.adapter = adapter

    // Observe the ViewModel's UI state
    lifecycleScope.launchWhenStarted {
      viewModel.uiState.collect { newData ->
        // Map Data to NameItem and update the adapter
        val mappedData = newData.map { mapToNameItem(it) }
        adapter.submitList(mappedData)
      }
    }

    return binding.root
  }

  private fun mapToNameItem(data: Data): NameItem {
    return NameItem(data.name, if (data.isSelected) Color.BLUE else Color.WHITE)
  }

}

适配器会是这样的。它只设置背景颜色,没有任何逻辑。

// RecyclerView Adapter
    class MyAdapter(private val onItemClick: (position: Int) -> Unit) :
        RecyclerView.Adapter<MyAdapter.ViewHolder>() {

        private var data: List<Data> = emptyList()

        override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
            val binding = ItemLayoutBinding.inflate(
                LayoutInflater.from(parent.context),
                parent,
                false
            )
            return ViewHolder(binding)
        }

        override fun onBindViewHolder(holder: ViewHolder, position: Int) {
            val item = data[position]
            holder.bind(item)
            holder.itemView.setOnClickListener { onItemClick(position) }
        }

        override fun getItemCount(): Int = data.size

        fun setData(newData: List<Data>) {
            data = newData
            notifyDataSetChanged()
        }

        class ViewHolder(private val binding: ItemLayoutBinding) :
            RecyclerView.ViewHolder(binding.root) {

            fun bind(item: Data) {
                binding.nameTextView.text = item.name
                binding.root.setBackgroundColor(item.backgroundColor)
            }
        }
    }

希望您觉得它有帮助。

© www.soinside.com 2019 - 2024. All rights reserved.