I have a todo app and I am accessing my views with ViewBinding from my onBindViewHolder class. I put a function to check the state of a Boolean(a checkBox in this sense) and toggle a strikethrough on the TextView(Todo) based on the state of that Boolean. I also put a setOnCheckedChangeListener
to know when the state of the checkBox has been changed and assign that new state to my stored Boolean variable for the checkBox. However it is not working properly despite changing the Implementation several times. This is my code.
But first this is my class
@Entity(tableName = "todo_table")
data class Todo(
@PrimaryKey (autoGenerate = true) // here "Room" will autoGenerate the id for us
// instead
// of assigning a randomUUID value
val id : Int = 0,
var title : String = "",
var date : Date = Date(),
var time : Date = Date(),
var todoCheckBox : Boolean = false
)
And my Adapter
import android.annotation.SuppressLint
import android.graphics.Paint.STRIKE_THRU_TEXT_FLAG
import android.view.LayoutInflater
import android.view.ViewGroup
import android.widget.TextView
import androidx.recyclerview.widget.RecyclerView
import androidx.recyclerview.widget.RecyclerView.Adapter
import com.bignerdranch.android.to_dolist.databinding.CustomRowBinding
import com.bignerdranch.android.to_dolist.fragments.add.SIMPLE_DATE_FORMAT
import com.bignerdranch.android.to_dolist.fragments.add.SIMPLE_TIME_FORMAT
import com.bignerdranch.android.to_dolist.model.Todo
import java.text.SimpleDateFormat
import java.util.Locale
class ListAdapter: Adapter<ListAdapter.TodoViewHolder>() {
private var todoList = emptyList<Todo>()
// will toggle strikeThrough on the Task title
private fun toggleStrikeThrough(tvTaskTitle : TextView, cbTask : Boolean) {
if (cbTask) {
tvTaskTitle.paintFlags = tvTaskTitle.paintFlags or STRIKE_THRU_TEXT_FLAG
} else {
tvTaskTitle.paintFlags = tvTaskTitle.paintFlags or STRIKE_THRU_TEXT_FLAG.inv()
}
}
inner class TodoViewHolder(val binding : CustomRowBinding) : RecyclerView.ViewHolder(binding.root)
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): TodoViewHolder {
// this can be done in an inline variable and I may experiment on it later.
val binding = CustomRowBinding.inflate(LayoutInflater.from(parent.context),
parent,
false
)
return TodoViewHolder(binding)
}
override fun onBindViewHolder(holder: TodoViewHolder, position: Int) {
val todo = todoList[position]
val dateLocales = SimpleDateFormat(SIMPLE_DATE_FORMAT, Locale.getDefault())
val timeLocales = SimpleDateFormat(SIMPLE_TIME_FORMAT, Locale.getDefault())
holder.apply {
binding.tvTaskTitle.text = todo.title
binding.tvTaskDate.text = dateLocales.format(todo.date)
binding.tvTaskTime.text = timeLocales.format(todo.time)
binding.cbTask.isChecked = todo.todoCheckBox
binding.cbTask.setOnCheckedChangeListener { _, isChecked ->
toggleStrikeThrough(binding.tvTaskTitle, isChecked)
todo.todoCheckBox = !todo.todoCheckBox
}
}
}
// as usual will return the size of the List
override fun getItemCount() = todoList.size
@SuppressLint("NotifyDataSetChanged")
fun setData(todo : List<Todo>) {
this.todoList = todo
// todo - This is a suppressed lint warning. Later check it online and see if there is a way to improve it.
notifyDataSetChanged()
}
}
Now this is the unusual behaviour when I run the App on my physical device or on my emulator. When I click on the CheckBox the strikeThrough appears but when I click on it again, the textView itself dissapears and the strikeThrough remains, and when I click on it again another strikeThrough appears making it two but with the textView still missing.
I have used different Implementations of the paintsFlag but its still not working. I also followed the exact same tutorial I used but still not working correctly with ViewBinding.
I just found out that I was using the "or" bitwise operator instead of the "and" for the else condition in the paintsFlag and that was what caused the bug, so I changed it to "and" and its working now. The "and" operator ensures that the strikeThrough gets inverted.