epoxy
epoxy copied to clipboard
The problem that the value of EditText is randomly placed when scrolling
trafficstars
I've created an Epoxy that can add items dynamically.
The item has an EditText.
When items are added enough to allow scrolling, if you scroll down after entering values in the EditText of the first few items, the entered values are randomly assigned to the following items.
I found a similar problem on #426 and #218 applied it but couldn't solve it. (Referring to #426 and #218, it was successful to keep the EditText data after screen transition. However, setting a random value when scrolling was not resolved.)
How do I solve this problem?
@EpoxyModelClass(layout = R.layout.item_routine_detail)
abstract class EpoxyDetailModel : EpoxyModelWithHolder<EpoxyDetailModel.Holder>() {
private var textWatcher: TextWatcher = object : TextWatcher {
override fun beforeTextChanged(p0: CharSequence?, p1: Int, p2: Int, p3: Int) {
}
override fun onTextChanged(w: CharSequence?, p1: Int, p2: Int, p3: Int) {
}
override fun afterTextChanged(w: Editable?) { // w : weight
onEditTextChanged?.invoke(pos, w.toString())
}
}
@EpoxyAttribute
lateinit var pos: String
@EpoxyAttribute
var set: Int = 0
@EpoxyAttribute
var weight: String = ""
@EpoxyAttribute
var onEditTextChanged: ((String, String) -> Unit)? = null
@AfterPropsSet
override fun bind(holder: Holder) {
holder.set.text = set.toString()
holder.weight.apply {
setTextIfDifferent(weight)
removeTextChangedListener(textWatcher)
addTextChangedListener(textWatcher)
}
}
@OnViewRecycled
fun onViewRecycled(holder: Holder) {
holder.weight.removeTextChangedListener(textWatcher)
}
fun EditText.setTextIfDifferent(newText: CharSequence?): Boolean {
if (!isTextDifferent(newText, text)) {
// Previous text is the same. No op
return false
}
setText(newText)
setSelection(newText?.length ?: 0)
return true
}
fun isTextDifferent(str1: CharSequence?, str2: CharSequence?): Boolean {
if (str1 === str2) {
return false
}
if (str1 == null || str2 == null) {
return true
}
val length = str1.length
if (length != str2.length) {
return true
}
if (str1 is Spanned) {
return str1 != str2
}
for (i in 0 until length) {
if (str1[i] != str2[i]) {
return true
}
}
return false
}
class Holder : KotlinEpoxyHolder() {
val set by bind<TextView>(R.id.set)
val weight by bind<EditText>(R.id.weight)
}
}