Mithat Sinan Sarı
Mithat Sinan Sarı

Reputation: 302

EditText inTextInputLayout calls onTextChanged twice for first letter only

I am developing an open source text masker. You can click here to see source code.

My problem is that, when I wrap my custom edit text with TextInputLayout, onTextChanged is being triggered twice only for first letter. Then it works as expected.

This "twice call" breaks my logic. Do you guys have any idea what might be the problem? Since it is being used by other developers, I don't want to fix it with hacky solution. I need to find out the problem.

I set text manually after removing text watcher, then I add text watcher again.

Here is my main logic;

This method is being called only once;

   private fun initTextWatcher() {
        textWatcher = object : TextWatcher {
            override fun afterTextChanged(s: Editable?) {}
            override fun beforeTextChanged(s: CharSequence?, start: Int, count: Int, after: Int) {}
            override fun onTextChanged(s: CharSequence?, start: Int, before: Int, count: Int) {
                masker?.onTextChanged(s, start, count, before)
            }
        }
        addTextChangedListener(textWatcher)
    }

And this is how I set my text manually;

    private fun setEditTextWithoutTriggerListener(newText: String) {
        removeTextChangedListener(textWatcher)
        onTextChangedListener?.invoke(newText) // This is a custom listener. 
        setText(newText)
        setSelection(text?.length ?: 0) // This puts cursor at the end of the text.
        addTextChangedListener(textWatcher)
    }

To handle hint position like TextInputEditText does, I simply copied it's functions into mine.


    override fun getHint(): CharSequence? {
        val layoutHint = getTextInputLayout()?.hint
        return layoutHint ?: super.getHint()
    }

    override fun onCreateInputConnection(outAttrs: EditorInfo): InputConnection? {
        val ic = super.onCreateInputConnection(outAttrs)
        if (ic != null && outAttrs.hintText == null) {
            outAttrs.hintText = getHintFromLayout()
        }
        return ic
    }

    private fun getTextInputLayout(): TextInputLayout? {
        var parent = this.parent
        while (parent is View) {
            if (parent is TextInputLayout) {
                return parent
            }
            parent = parent.getParent()
        }
        return null
    }

    private fun getHintFromLayout(): CharSequence? {
        val layout = getTextInputLayout()
        return layout?.hint
    }

And my class extends AppCompatEditText like TextInputEditText does.

Upvotes: 1

Views: 858

Answers (1)

Sharone Lev
Sharone Lev

Reputation: 841

If you are calling addTextChangedListener() from onCreate() or init() move the call into onResume() or any other function called later, otherwise onTextChanged() is triggered before the resume

Upvotes: 1

Related Questions