androidkotlinandroid-viewbindingstrikethrough

ViewBinding with PaintsFlag STRIKE_THRU_TEXT_FLAG not working properly


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.

This is itThis is it!

Sometimes the TextView dosen't appear at all

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.


Solution

  • 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.