kotlin 如何找到回收机视图的特定视图并更改背景颜色?

mwg9r5ms  于 2022-11-16  发布在  Kotlin
关注(0)|答案(2)|浏览(123)

我正在使用Kotlin和MVVM方法构建一个应用程序,我的Recycler View使用多种视图类型。
在我的List Adapter中,在覆盖函数onBindViewHolder中,我有一个代码,用于检测第一次单击行、第二次单击同一行以及第一次单击不同行。
点击检测工作正常。我的目标是在我第一次点击行时保存正确的视图id,然后当我点击另一行时,我希望找到第一行并恢复原始背景。我知道这是一个回收器视图,但我不滚动视图,我只是想排序点击,并把原来的背景。我已经看到了很多例子,有人硬编码的背景颜色,但这不是我要找的。
我已经尝试保存视图ID,但似乎保存了错误的ID,因为当我尝试恢复当前视图ID时,它与保存的视图ID相同。
查找上一个视图的代码如下所示:

val prevConstrainLayoutView = holder.itemView.findViewById<ConstraintLayout>(prevClickedItemViewId)
  }

1.如何保存正确的视图ID或其他内容,然后使用原始背景颜色恢复先前单击的行?

当前Androdi手持设备屏幕

在绑定视图占位符上

override fun onBindViewHolder(holder: WordViewHolder, position: Int) {
        val current = getItem(position)
        holder.bind(current)
        Log.d("onBindViewHolder->", "Views")

        // apply the click listener for the item
        holder.itemView.setOnClickListener {

            // that should check if something was selected, but not sure
            if (holder.bindingAdapterPosition != RecyclerView.NO_POSITION) {

                onClickListener.onClick(current)

                if (clicked == 1 && clickedItem != current.id) {

                    prevClickedItem = clickedItem
                    prevClickedItemType = clickedItemType
                    prevClickedItemViewId = clickedItemViewId
                    prevClickedItemRootBackgroundDrawable = clickedItemRootBackgroundDrawable
                    prevClickedItemRootBackgroundColour = clickedItemRootBackgroundColour
                    prevClickedItemView  = clickedItemView

                    clicked = 1
                    clickedItemRootBackgroundDrawable = holder.itemView.background.current
                    clickedItemRootBackgroundColour = holder.itemView.solidColor
                    clickedItemViewId =  holder.itemView.id
                    clickedItemType = current.orderBy
                    clickedItem = current.id
                    clickedItemView = holder.itemView
                    clickedItemView.tag = 2

                    if (clickedItem!=prevClickedItem && prevClickedItemViewId!=null && prevClickedItemType!=-1 && clickedConstraintLayout!=null) {

                        val prevConstrainLayoutView = holder.itemView.findViewById<ConstraintLayout>(prevClickedItemViewId)
                        Log.d("onBindViewHolder->", "Clicked second time different row")

                        Log.d("onBindViewHolder->", "$prevConstrainLayoutView and $prevClickedItemType")

                        when (prevClickedItemType) {
                            TYPE_ZERO -> {
                                prevConstrainLayoutView.setBackgroundColor(ContextCompat.getColor(holder.itemView.context, R.color.green_sushi))
                                Log.d("onBindViewHolder->", "Clicked second time different row, set the prev view to: green_sushi")
                            }
                            TYPE_ONE -> {
                                prevConstrainLayoutView.setBackgroundColor(ContextCompat.getColor(holder.itemView.context, R.color.yellow_background))
                                Log.d("onBindViewHolder->", "Clicked second time different row, set the prev view to: yellow_background")
                            }
                            TYPE_TWO -> {
                                prevConstrainLayoutView.setBackgroundColor(ContextCompat.getColor(holder.itemView.context, R.color.white_text))
                                Log.d("onBindViewHolder->", "Clicked second time different row, set the prev view to: white_text")
                            }
                            TYPE_THREE -> {
                                prevConstrainLayoutView.setBackgroundColor(ContextCompat.getColor(holder.itemView.context, R.color.blue_heather))
                                Log.d("onBindViewHolder->", "Clicked second time different row, set the prev view to: blue_heather")
                            }
                            TYPE_FOUR -> {
                                prevConstrainLayoutView.setBackgroundResource(R.drawable.purple_orange_background)
                                Log.d("onBindViewHolder->", "Clicked second time different row, set the prev view to: purple_orange_background")
                            }
                            else -> {
                                prevConstrainLayoutView.setBackgroundColor(ContextCompat.getColor(holder.itemView.context, R.color.green_sushi))
                                Log.d("onBindViewHolder->", "Clicked second time different row, set the prev view to: green_sushi")
                            }
                        }

                    }

                    holder.itemView.setBackgroundColor(
                        ContextCompat.getColor(
                            holder.itemView.context,
                            R.color.blue_background
                        )
                    )
                } else if (clicked == 1 && clickedItem == current.id) {
                    // second click the same row
                    clicked = 0
                    clickedItem = current.id

                } else if (clicked == 0) {

                    // first click
                    clicked = 1
                    clickedItem = current.id
                    clickedItemType = current.orderBy
                    clickedItemViewId =  holder.itemView.id
                    holder.itemView.tag = 1
                    clickedItemRootBackgroundDrawable = holder.itemView.background.current
                    clickedItemRootBackgroundColour = holder.itemView.solidColor
                    clickedItemView = holder.itemView
                    clickedConstraintLayout =  holder.itemView.findViewById<ConstraintLayout>(R.id.root)
                    Log.d("onBindViewHolder->", "Clicked first time, set the view to: blue_background, " +
                            "\nconstraint layout:$clickedConstraintLayout")

                    holder.itemView.setBackgroundColor(
                        ContextCompat.getColor(
                            holder.itemView.context,
                            R.color.blue_background
                        )
                    )
                }

            }
        }

    }

项视图布局

<?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:id="@+id/root"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:background="@drawable/purple_orange_background"
    android:paddingLeft="24dp"
    android:paddingRight="24dp">

    <TextView
        android:id="@+id/textView"
        android:layout_width="wrap_content"
        android:layout_height="48dp"
        android:gravity="center_vertical"
        android:text="View 6 TextView"
        android:textColor="@color/white"
        android:textSize="24sp"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent" />

    <ImageView
        android:layout_width="48dp"
        android:layout_height="48dp"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintTop_toTopOf="parent" />

</androidx.constraintlayout.widget.ConstraintLayout>

这是我在ListAdapter中使用的内容:

class WordListAdapter(private val onClickListener: MyRecyclerViewOnClickListener) :
    ListAdapter<Word, WordListAdapter.WordViewHolder>(WordsComparator()) {

这是View Model中的部分代码:

val allOrderedWords: LiveData<List<Word>> = repository.allOrderedWords.asLiveData()

这是我的活动:

wordViewModel.allOrderedWords.observe(this, Observer { words ->
    // Update the cached copy of the words in the adapter.
    words?.let { adapter.submitList(it) }
})
s3fp2yjn

s3fp2yjn1#

我的意思是视图保持器应该始终代表项目,而不是信息的来源。单次滚动,你会失去它。不要存储“视图ID”,存储关于它是什么项目的信息。

var clickedItem: Word? = null

override fun onBindViewHolder(holder: WordViewHolder, position: Int) {
    val current = getItem(position)
    val setBackgroundColor: (Int) -> Unit = { color ->
        viewHolder.itemView.setBackgroundColor(ContextCompat.getColor(viewHolder.itemView.context,color)
    }
    holder.bind(current)
    
    
    val color = when (current.itemType) {
        TYPE_ZERO -> R.color.green_sushi
        TYPE_ONE -> R.color.yellow_background
        TYPE_TWO -> R.color.white_text
        TYPE_THREE -> R.color.blue_heather
        TYPE_FOUR -> R.drawable.purple_orange_background
        else -> R.color.green_sushi
    }

    setBackgroundColor(color)
    
    holder.itemView.setOnClickListener {
        onClickListener.onClick(current)

        when {
            clickedItem == null -> {
                clickedItem= current
                setBackgroundColor(R.color.blue_background)
            }
            clickedItem == current -> {
                // Here I assume that you want to clear the "mark"?
                clickedItem= null
                notifyItemChanged(position)
            }
            clicked != current -> {
                val oldClicked = clickedItem
                clickedItem = current
                val indexOfPreviouslyClicked = data.indexOf(oldClicked)
                notifyItemChanged(indexOfPreviouslyClicked)
                setBackgroundColor(R.color.blue_background)
            }
        }
    }
}

这样,您就可以说RecyclerView(与notifyItemChanged(pos))本身应该更新某个项目,并且它将在该项目上强制onBindViewHolder

6gpjuf90

6gpjuf902#

最后,我找到了一个解决问题的解决方案,并且完全按照预期工作。

我如何逐步解决问题:
1.每个项目布局都指向其可绘制状态。

android:background="@drawable/green_sushi_state"

1.每个可绘制状态都有两个指针,一个是单击-选择项时的指针,另一个是默认值
第一次
这两个指针指向具有您喜欢的颜色的背景。
1.在我的ListAdapter下,我使用SparseBooleanArray来跟踪所选择的内容:

private val tvSparseBooleanArraySelectedItems = SparseBooleanArray()

1.在我的onBindViewHolder函数中,我检查SparseBooleanArray中是否存在该位置。默认值为false。该值被分配给我的约束布局。每当您滚动时,该值就会被分配。

val mConstraintLayout = holder.itemView.findViewById<ConstraintLayout>(R.id.root)

val isItSelected = tvSparseBooleanArraySelectedItems.getOrDefault(position, false)
mConstraintLayout.isSelected = isItSelected

1.在我的ViewHolder内部类下,我有多种类型的视图。

private fun bindOther(word: Word) {
    //Do your view assignment here from the data model
    val mTextView = itemView.findViewById<TextView>(R.id.textView)
    mTextView.text = word.word
    val mConstraintLayout = itemView.findViewById<ConstraintLayout>(R.id.root)

    mTextView.setOnClickListener {
        onClickListener.onClick(word)
        manageSparseBooleanArrayData(tvSparseBooleanArraySelectedItems, bindingAdapterPosition)
        mConstraintLayout.isSelected = true
    }

}
  1. fun manageSparseBooleanArrayData通过迭代、查找键、删除键和notifyItemChanged(keyIn)来管理SparseBooleanArray。我正在迭代SparseBooleanArrayData,因为我希望使用notifyItemChanged而不是notifyDataSetChanged。
fun manageSparseBooleanArrayData(_sparseBooleanArrayOnTextView: SparseBooleanArray, _position: Int) {

    when (currentTvSelectionMode) {

        SINGLE_SELECTION -> {
            if (_sparseBooleanArrayOnTextView.isNotEmpty()) {
                for (i in 0 until _sparseBooleanArrayOnTextView.size()) {
                    if (_sparseBooleanArrayOnTextView.valueAt(i)) {

                        val keyIn = _sparseBooleanArrayOnTextView.keyAt(i)
                        val value = _sparseBooleanArrayOnTextView.get(keyIn)
                        _sparseBooleanArrayOnTextView.delete(keyIn)
                        notifyItemChanged(keyIn)
                    }
                }
            }
            tvSparseBooleanArraySelectedItems.put(_position, true)
        }

        MULTIPLE_SELECTION -> {
            tvSparseBooleanArraySelectedItems.put(_position, true)
        }

        else -> {}
    }

}

希望我的解决方案对您有所帮助。

相关问题