如何防止用户删除 EditText 小部件中预先存在的文本?

How can I prevent a user from deleting pre-existing text in an EditText widget?

我有一个 EditText,其中包含一些不得删除的预先存在的文本。应该只允许用户在视图中追加文本。

我现在的解决方案如下所示,我检查 EditText 的新长度是否比原始文本短。如果是,则用户试图删除一个字符,所以我只需用原始文本重新填充视图并移动光标。这个解决方案的问题是用户可以输入比原始长度更长的文本,然后将光标的位置更改为原始文本中的某个位置,最后删除字符。

override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
    super.onViewCreated(view, savedInstanceState)

    val originalText = "Hello"
    binding.et.setText(originalText)
    
    binding.et.addTextChangedListener(object : TextWatcher {
        override fun beforeTextChanged(s: CharSequence?, start: Int, count: Int, after: Int) {}

        override fun onTextChanged(s: CharSequence?, start: Int, before: Int, count: Int) {
            s?.let {
                if (s.length < originalText.length) {
                    binding.et.setText(originalText)
                    binding.et.setSelection(originalText.count())
                }
            }
        }

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

我该怎么办?我对所有想法持开放态度。

谢谢!

编辑:

我也试过组合 EditTextTextView(正如一些人所建议的那样)但是布局很难实现,因为原始文本和新文本都可以跨越多行.我上面的解决方案在原文中包含一个单词,但可能有很多。所以我需要迎合这种情况:

...其中白色框代表 TextView,红色框代表 EditText

我认为 Bö macht Blau 的回答也不会奏效,因为前缀在它自己的“列”中。

我想我将不得不使用 Zain 的解决方案 (startsWith()) 或创建自定义视图(尽管我以前从未做过其中之一)。

此检查应该有效:

if (s.substring(0, 4) == originalText) {
  // update text
}

但考虑考虑 InputFilter,正如评论所建议的那样。

请考虑 OP 评论中的@Gabe Sechan 建议,单独使用 EditText 并不是最佳解决方案。

如果您仍然需要使用 EditText 那么您可以更改条件以检查 EditText 观察者返回的 CharSequence 是否以使用 [=16 的原始文本开头=] 方法

et.addTextChangedListener(object : TextWatcher {
    override fun beforeTextChanged(s: CharSequence?, start: Int, count: Int, after: Int) {}

    override fun onTextChanged(s: CharSequence?, start: Int, before: Int, count: Int) {
        s?.let {

            if (!s.startsWith(originalText)) {

                if (s.length <= originalText.length) {
                    et.setText(originalText)
                    et.setSelection(originalText.count())
                } else {
                    et.setText(originalText + s.subSequence(originalText.length, s.length))
                    et.setSelection(s.count())
                }
            }
        }
    }

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

您可以使用文本字段,它是 TextInputEditTextTextInputLayout 的组合。然后你可以像这样设置一个前缀:

<com.google.android.material.textfield.TextInputLayout
         android:layout_width="match_parent"
         android:layout_height="wrap_content"
         app:prefixText="@string/prefix_text">

     <com.google.android.material.textfield.TextInputEditText
             android:layout_width="match_parent"
             android:layout_height="wrap_content"/>

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

TextInputEditText 获得焦点后,前缀将立即可见。由于它不是 EditText 内容的一部分,因此用户无法修改它。

有用的链接: