有效地操作或捕获 EditText 输入

Manipulate or capture EditText input efficiently

我想要实现的目标

我想将用户输入的每个字符转换为另一个字符并显示在 EditText

我做了什么

我的第一个方法是使用 TextWatcher 实现的。

     private val textWatcher2 = object : TextWatcher {
        private var byUser = true

        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) {
            if (!byUser) return

            byUser = false

            val t = this@ManipulatingEditText.text.toString()
            val m = convert(t.last())
            val s = t.substring(0, t.length - 1) + m
            this@ManipulatingEditText.setText("")
            this@ManipulatingEditText.setText(s)
            this@ManipulatingEditText.setSelection(this@ManipulatingEditText.text!!.length)

            byUser = true
        }
    }

    /*This is just an mock of my real implementation. But the same delay occurs*/
    fun convert(c: Char) : String {
        return c.toString()
    }

这是有效的:每个新的输入字符都通过 convert(Char) 函数进行转换。不幸的是,这个解决方案 非常慢 并且 效率低下 。每次输入后都有一个短暂的延迟,您无法快速输入。

此解决方案不适用于生产应用。但是我还没有找到另一个更好的解决方案(通过 RxJava 去抖动或延迟不起作用,因为某些字符被跳过或竞争条件适用)。

如有任何想法、解决方案或帮助,我们将不胜感激。

我改变了一些东西,发现延迟大大降低,但我不能说哪个影响最大(如果有的话):

  • 用直接操作 Editable 替换了对 setText 的调用
  • 将文本操作从 onTextChanged 回调移至 afterTextChanged 回调,因为这是给我们 Editable 而不是 CharSequence[=25 的回调=]
  • 简化了决定新文本内容的逻辑——希望这仍然符合您的预期;我对你提供的示例代码有点不清楚

    private val textWatcher2 = object : TextWatcher {
         private var byUser = true
    
         override fun afterTextChanged(s: Editable?) {
             if (!byUser) return
    
             byUser = false
             s?.let {
                 if (s.isNotEmpty()) {
                     s.replace(s.length - 1, s.length, convert(s.last()))
                 }
             }
             byUser = true
         }
    
         override fun beforeTextChanged(s: CharSequence?, start: Int, count: Int, after: Int) {
         }
    
         override fun onTextChanged(s: CharSequence?, start: Int, before: Int, count: Int) {
         }
     }