Custom text input field which extends from View

52 views Asked by At

I have a custom view for editing image and I need to add new feature which will be set text on this Image. This is my code to handle input events inside this view:

private val inputMethodManager by lazy {
        context.getSystemService(Activity.INPUT_METHOD_SERVICE) as? InputMethodManager
    }

    private var mEditable = SpannableStringBuilder("")
    private var text: String = ""

    private val mMyTextWatcher = object : TextWatcher {
        override fun beforeTextChanged(s: CharSequence?, start: Int, count: Int, after: Int) {}

        override fun onTextChanged(s: CharSequence?, start: Int, before: Int, count: Int) {
            text = s.toString()
            Log.d("DEBUG", "Text length: ${text.length}")
            invalidate()
        }

        override fun afterTextChanged(s: Editable?) {}
    }

init {
        isFocusableInTouchMode = true
        isFocusable = true
        isSaveEnabled = true

        setupEditable()
        setupKeyboardListener()
    }

override fun onCreateInputConnection(outAttrs: EditorInfo): InputConnection {
        outAttrs.apply {
            inputType = InputType.TYPE_CLASS_TEXT
            imeOptions = EditorInfo.IME_ACTION_UNSPECIFIED
            initialSelStart = mEditable.length
            initialSelEnd = mEditable.length
        }

        return object : BaseInputConnection(this, true) {
            override fun getEditable(): Editable {
                return mEditable
            }
        }
    }

 override fun onCheckIsTextEditor(): Boolean {
        return true
    }

    private fun showKeyboard() {
        try {
            requestFocus()
            inputMethodManager?.apply {
                updateSelection(this@ImageEditorView, 0, mEditable.length, -1, MAX_CHARACTER_NUM)
                showSoftInput(this@ImageEditorView, InputMethodManager.SHOW_IMPLICIT)
            }
        } catch (e: Exception) {
            e.printStackTrace()
        }
    }

    private fun hideKeyboard() {
        clearFocus()
        inputMethodManager?.hideSoftInputFromWindow(
            windowToken,
            InputMethodManager.SHOW_IMPLICIT
        )
    }

    private fun setupEditable() {
        mEditable = SpannableStringBuilder(text)
        Selection.setSelection(mEditable, mEditable.length)
        mEditable.setSpan(mMyTextWatcher, 0, mEditable.length, Spanned.SPAN_INCLUSIVE_INCLUSIVE)
        
        mEditable.filters = mEditable.filters.toMutableList().apply {
            add(InputFilter.LengthFilter(MAX_CHARACTER_NUM))
        }.toTypedArray()
    }

Text editing works fine, but I need to set max text length and LengthFilter don't work properly. For example, I have entered 200 symbols and max length is 160. SpannableStringBuilder still have 200 symbols but returns to textwatcher only 160. And when I try to delete text from the end, it start deleting from all 200 symbols and I cant see cursor until 160 symbols left.

How to set max length correctly and restrict enter more symbols?

I also tried this delete LengthFilter and add this code to TextWatcher:

override fun onTextChanged(s: CharSequence?, start: Int, before: Int, count: Int) {
            if (s != null && s.length > MAX_CHARACTER_NUM) {
                text = s.subSequence(0, MAX_CHARACTER_NUM).toString()
                setupEditable()
                inputMethodManager?.restartInput(this@ImageEditorView)
            } else {
                text = s.toString()
            }
            Log.d("DEBUG", "Text length: ${text.length}")
            invalidate()
        }

It works better? but on Android 8 it make bug:

  • enter max length text
  • hide keyboard
  • open keyboard
  • try to delete text

Text don't deleted and returns this warning:

[ANR Warning]Input routeing takes more than 6000ms since 2023-06-26 12:57:34.128, this = com.mediatek.view.impl.ViewDebugManagerImpl@4f786bb
Input event delivered to android.view.ViewRootImpl$SyntheticInputStage@e12fbc0 at 2023-06-26 12:57:40.662
Input event delivered to android.view.ViewRootImpl$EarlyPostImeInputStage@29821fd at 2023-06-26 12:57:40.661
Input event delivered to android.view.ViewRootImpl$NativePostImeInputStage@bcfbef2 at 2023-06-26 12:57:40.661
Input event delivered to android.view.ViewRootImpl$ViewPostImeInputStage@4ce3943 at 2023-06-26 12:57:40.661
0

There are 0 answers