recyclerview 中的复选框状态在图形上不正确
Checkbox states are graphically incorrect in recyclerview
我正在 RecyclerView
使用 CheckBoxes
选择项目。我想通过以下规则实现可检查项目:
- 只能同时检查一个项
- 如果选中项目,则无法取消选中该项目(不能为零 个项目已选中)
每个项目在以编程方式启动时都有一个选中的复选框(默认为第一个)。原因很简单。 ArrayList 中的每个项目都是自定义对象,其内部具有表示为布尔值的复选框状态,您将能够保存状态并稍后再次打开它们。
所以我将 setOnCheckedChangeListener()
用于我的 CheckBox
并且每次我都会遍历 Arraylist
项并将 isChecked
设置为 true
如果它的位置等于 tag
.
中的位置
这很好用。我已经通过调试器检查了每个状态并且状态是正确的,但是图形表示不正确,我不知道为什么。
这是图示:
onBindViewHolder()
代码:
override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int){
try {
if (holder is ViewHolder){
val res = holder.itemView.context.resources
val ctx = holder.itemView.context
foodVariants[position].let{
//food variant vals
val variantID: Int = it.foodVariant.getInt(ctx.getString(R.string.food_variant_id))
val variantName: String? = it.foodVariant.getString(ctx.getString(R.string.food_variant_name))
val variantPrice: Int = it.foodVariant.getInt(ctx.getString(R.string.food_variant_price))
//set food variant name
holder.foodVariantName.text = variantName
//set food variant price
val variantPriceConverted: String = convertCentsToFloat(variantPrice)
holder.foodVariantPrice.text = variantPriceConverted + " €"
//set item tag
holder.foodVariantCheckBox.tag = position
//set food variant state
holder.foodVariantCheckBox.isChecked = it.isChecked
//uncheck all variants if this is checked - one variant has to be checked everytime
holder.foodVariantCheckBox.setOnCheckedChangeListener { buttonView, isChecked ->
val newPosition = buttonView.tag as Int
createLog("VARIANT_STATE: ", "isChecked: " + variantName.toString())
for (variantPos in 0 until foodVariants.size){
foodVariants[variantPos].isChecked = variantPos == newPosition
}
mActivity.refreshOtherRecyclerViews(it)
notifyDataSetChanged()
}
}
}
} catch (e: Exception){
e.printStackTrace()
}
}
最简单的方法是将逻辑移到回收器视图之外。 (在干净架构的演示者中)
您有一个对象列表 CheckboxModel(val id: Int, val label: String, var isChecked: Boolean)
。单击复选框时,您会更新 CheckboxModel 列表并将其传递回适配器:
fun onUpdate(selectedCase: CheckboxModel) {
data.forEach { it.isChecked = it.id == selectedCase.id }
updateAdapter(data)
}
您还必须防止(在视图持有者中)单击选中的项目时取消选中它。
这是我的实现方式
使复选框可聚焦并将 focusbleInTouchMode 设置为 false
在adapter中取一个全局变量ex checkedId .
在适配器onBindViewHolder
中写一个逻辑
if(variantID==checkedId){
holder.foodVariantCheckBox.isChecked=true
}else{
holder.foodVariantCheckBox.isChecked=false
}
为 holder.foodVariantCheckBox
设置 OnclickListener。在 onClick 方法中将 checkedId 设置为 variantID 和 notifyDataSetChanged()
最终检查的项目 ID 将在适配器 checkedId 变量中。
所以我结合了@Redman 和@Kélian 的答案使其发挥作用。
这是最终代码:
private var previouslySelectedVariant: Int = -1
override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int){
try {
if (holder is ViewHolder){
val res = holder.itemView.context.resources
val ctx = holder.itemView.context
foodVariants[position].let{
//food variant vals
val variantID: Int = it.foodVariant.getInt(ctx.getString(R.string.food_variant_id))
val variantName: String? = it.foodVariant.getString(ctx.getString(R.string.food_variant_name))
val variantPrice: Int = it.foodVariant.getInt(ctx.getString(R.string.food_variant_price))
//set food variant name
holder.foodVariantName.text = variantName
//set food variant price
val variantPriceConverted: String = convertCentsToFloat(variantPrice)
holder.foodVariantPrice.text = variantPriceConverted + " €"
//set food variant state
holder.foodVariantCheckBox.isChecked = it.isChecked
//uncheck all variants if this is checked - one variant has to be checked everytime
holder.foodVariantCheckBox.setOnCheckedChangeListener { buttonView, isChecked ->
if (isChecked) {
mActivity.updateVariantData(variantID)
mActivity.refreshIngredients(it)
previouslySelectedVariant = variantID
} else {
if(previouslySelectedVariant == variantID){
holder.foodVariantCheckBox.isChecked = true
}
}
}
}
}
} catch (e: Exception){
e.printStackTrace()
}
}
//ParentActivity
fun updateVariantData(variantID: Int){
foodVariantsArray.forEach { it.isChecked = it.foodVariant.getInt(getString(R.string.food_variant_id)) == variantID }
foodVariantsAdapter.notifyDataSetChanged()
}
我正在 RecyclerView
使用 CheckBoxes
选择项目。我想通过以下规则实现可检查项目:
- 只能同时检查一个项
- 如果选中项目,则无法取消选中该项目(不能为零 个项目已选中)
每个项目在以编程方式启动时都有一个选中的复选框(默认为第一个)。原因很简单。 ArrayList 中的每个项目都是自定义对象,其内部具有表示为布尔值的复选框状态,您将能够保存状态并稍后再次打开它们。
所以我将 setOnCheckedChangeListener()
用于我的 CheckBox
并且每次我都会遍历 Arraylist
项并将 isChecked
设置为 true
如果它的位置等于 tag
.
这很好用。我已经通过调试器检查了每个状态并且状态是正确的,但是图形表示不正确,我不知道为什么。
这是图示:
onBindViewHolder()
代码:
override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int){
try {
if (holder is ViewHolder){
val res = holder.itemView.context.resources
val ctx = holder.itemView.context
foodVariants[position].let{
//food variant vals
val variantID: Int = it.foodVariant.getInt(ctx.getString(R.string.food_variant_id))
val variantName: String? = it.foodVariant.getString(ctx.getString(R.string.food_variant_name))
val variantPrice: Int = it.foodVariant.getInt(ctx.getString(R.string.food_variant_price))
//set food variant name
holder.foodVariantName.text = variantName
//set food variant price
val variantPriceConverted: String = convertCentsToFloat(variantPrice)
holder.foodVariantPrice.text = variantPriceConverted + " €"
//set item tag
holder.foodVariantCheckBox.tag = position
//set food variant state
holder.foodVariantCheckBox.isChecked = it.isChecked
//uncheck all variants if this is checked - one variant has to be checked everytime
holder.foodVariantCheckBox.setOnCheckedChangeListener { buttonView, isChecked ->
val newPosition = buttonView.tag as Int
createLog("VARIANT_STATE: ", "isChecked: " + variantName.toString())
for (variantPos in 0 until foodVariants.size){
foodVariants[variantPos].isChecked = variantPos == newPosition
}
mActivity.refreshOtherRecyclerViews(it)
notifyDataSetChanged()
}
}
}
} catch (e: Exception){
e.printStackTrace()
}
}
最简单的方法是将逻辑移到回收器视图之外。 (在干净架构的演示者中)
您有一个对象列表 CheckboxModel(val id: Int, val label: String, var isChecked: Boolean)
。单击复选框时,您会更新 CheckboxModel 列表并将其传递回适配器:
fun onUpdate(selectedCase: CheckboxModel) {
data.forEach { it.isChecked = it.id == selectedCase.id }
updateAdapter(data)
}
您还必须防止(在视图持有者中)单击选中的项目时取消选中它。
这是我的实现方式
使复选框可聚焦并将 focusbleInTouchMode 设置为 false
在adapter中取一个全局变量ex checkedId .
在适配器
onBindViewHolder
中写一个逻辑if(variantID==checkedId){
holder.foodVariantCheckBox.isChecked=true
}else{
holder.foodVariantCheckBox.isChecked=false
}
为
holder.foodVariantCheckBox
设置 OnclickListener。在 onClick 方法中将 checkedId 设置为 variantID 和notifyDataSetChanged()
最终检查的项目 ID 将在适配器 checkedId 变量中。
所以我结合了@Redman 和@Kélian 的答案使其发挥作用。
这是最终代码:
private var previouslySelectedVariant: Int = -1
override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int){
try {
if (holder is ViewHolder){
val res = holder.itemView.context.resources
val ctx = holder.itemView.context
foodVariants[position].let{
//food variant vals
val variantID: Int = it.foodVariant.getInt(ctx.getString(R.string.food_variant_id))
val variantName: String? = it.foodVariant.getString(ctx.getString(R.string.food_variant_name))
val variantPrice: Int = it.foodVariant.getInt(ctx.getString(R.string.food_variant_price))
//set food variant name
holder.foodVariantName.text = variantName
//set food variant price
val variantPriceConverted: String = convertCentsToFloat(variantPrice)
holder.foodVariantPrice.text = variantPriceConverted + " €"
//set food variant state
holder.foodVariantCheckBox.isChecked = it.isChecked
//uncheck all variants if this is checked - one variant has to be checked everytime
holder.foodVariantCheckBox.setOnCheckedChangeListener { buttonView, isChecked ->
if (isChecked) {
mActivity.updateVariantData(variantID)
mActivity.refreshIngredients(it)
previouslySelectedVariant = variantID
} else {
if(previouslySelectedVariant == variantID){
holder.foodVariantCheckBox.isChecked = true
}
}
}
}
}
} catch (e: Exception){
e.printStackTrace()
}
}
//ParentActivity
fun updateVariantData(variantID: Int){
foodVariantsArray.forEach { it.isChecked = it.foodVariant.getInt(getString(R.string.food_variant_id)) == variantID }
foodVariantsAdapter.notifyDataSetChanged()
}