epoxy icon indicating copy to clipboard operation
epoxy copied to clipboard

The problem that the value of EditText is randomly placed when scrolling

Open sybeom opened this issue 4 years ago • 0 comments
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?

Problem Image Link

@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)
    }
}

sybeom avatar Nov 25 '21 20:11 sybeom