带有TextWatcher和LiveData的EditText中的光标位置?

Posted

技术标签:

【中文标题】带有TextWatcher和LiveData的EditText中的光标位置?【英文标题】:Cursor position in EditText with TextWatcher and LiveData? 【发布时间】:2021-08-15 13:26:46 【问题描述】:

我正在使用 kotlin 在 android 应用程序上创建一个表单。表单的每个字段都与一个 livedata 相关联,以立即验证或更新数据。为了获得这个结果,我使用了一个 textwatcher,它会在每次文本更改时更新关联的 livedata。问题是每次更新时,它会将光标放在字段的开头,从而无法连续写入。

我把代码中有趣的部分贴在这里:

活动

     viewModel.name.observe(lifecycleOwner, Observer  nameValue->
            binding.nameEditText.setText(
                nameValue?.toString()
            )
            binding.nameTextInputLayout.error =
                viewModel.nameError.value
        )
     viewModel.price.observe(lifecycleOwner, Observer  priceValue->
            binding.priceEditText.setText(
                price?.toString()
            )
            binding.priceTextInputLayout.error =
                viewModel.priceError.value
        )

binding.nameEditText.addTextChangedListener(
        TextFieldValidation(
            binding.nameEditText
        )
    )
binding.priceEditText.addTextChangedListener(
        TextFieldValidation(
            binding.priceEditText
        )
    )


  inner class TextFieldValidation(private val view: View) : 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) 

            when (view.id) 
                R.id.nameEditText-> 
                    viewModel.onNameChanged(s.toString())
                    viewModel.isNameValid()
                
                R.id.priceEditText-> 
                    viewModel.onPriceChanged(s.toString())
                    viewModel.isPriceValid()
                
     

视图模型

var name = MutableLiveData<String>()
var price = MutableLiveData<Double>()

var nameError = MutableLiveData<String>()
var priceError = MutableLiveData<String>()

fun onNameChanged(newValue: String?) 
    if ((name.value != newValue)) 
        name.value = newValue
    

fun onPriceChanged(newValue: Double?) 
    if ((price.value != newValue)) 
        price.value = newValue
    


fun isNameValid() : Boolean 

    return if ((name.value == null) || (name.value == "")) 
        nameError.value = "Error"
        false
     else 
        nameError.value = ""
        true
    

fun isPriceValid() : Boolean 

    return if ((price.value == null) || (price.value == "")) 
        priceError.value = "Error"
        false
     else 
        priceError.value = ""
        true
    

XML

<com.google.android.material.textfield.TextInputLayout

            android:id="@+id/nameTextInputLayout"
            android:layout_
            android:layout_>

            <EditText
                android:id="@+id/nameEditText"
                android:layout_
                android:layout_
                android:layout_centerHorizontal="true"
                android:layout_centerVertical="true"
                android:backgroundTint="@color/white"
                android:inputType="text" />
        </com.google.android.material.textfield.TextInputLayout>

<com.google.android.material.textfield.TextInputLayout

            android:id="@+id/priceTextInputLayout"
            android:layout_
            android:layout_>

            <EditText
                android:id="@+id/priceEditText"
                android:layout_
                android:layout_
                android:layout_centerHorizontal="true"
                android:layout_centerVertical="true"
                android:backgroundTint="@color/white"
                android:inputType="numberDecimal" />
        </com.google.android.material.textfield.TextInputLayout>

我尝试使用 'mEdittext.setSelection (mEdittext.length ());' 但效果不佳,因为如果我在字符串中间进行更改,它会带来光标到最后。即使在双字段中,它的行为也不正确。 我需要让光标始终在准确的位置?在字符串中间添加、删除或写入的情况下。无论是字符串还是双精度。

有人可以帮我吗?

感谢您的耐心和帮助!

【问题讨论】:

【参考方案1】:

这种情况正在发生,因为在您的 ViewModel 观察者中,您将 nameValue 和 priceValue 设置回它们刚刚来自的 EditText。您可以添加一个检查并且不将未更改的值设置回 EditText:

if ((nameValue?.toString() == binding.nameEditText.getText().toString()) == false) 
   binding.nameEditText.setText(nameValue?.toString())

【讨论】:

不,我不能停止观察 nameValue 和 priceValue,因为我还有其他字段与这些值相关联。【参考方案2】:

我也有同样的问题,光标移到开头,搜索我找到了第一个解决方案,在一定程度上可以让我连续写一条消息,如下

viewModel.name.observe(lifecycleOwner, Observer  nameValue->
    binding.nameEditText.setText(
        nameValue?.toString()
    )
    binding.nameEditText.setSelection(
        nameValue?.toString().length
    )
)

我以为我已经解决了,但是出现了另一个问题,那就是如果我想在输入字符后编辑中心的任何部分,光标会移动到最后,直到找到正确的解决方案https://***.com/a/65794745/15798571

viewModel.name.observe(lifecycleOwner, Observer  nameValue->
    val selection = binding.nameEditText.selectionEnd
    val length = nameValue.length
    binding.nameEditText.setText(
        nameValue?.toString()
    )
    binding.nameEditText.setSelection(
        Math.min(selection, length)
    )
)

我希望它能像它为我一样为你服务

【讨论】:

以上是关于带有TextWatcher和LiveData的EditText中的光标位置?的主要内容,如果未能解决你的问题,请参考以下文章

TextWatcher中的参数

Edittext textwatcher触发listview中的所有editexts

带有列表的 LiveData

带有 sqlite 的 LiveData 不更新 UI

带有 RxJava Single 的 Android Livedata 在房间数据库中不起作用

带有livedata的kotlin扩展函数返回null?