【问题标题】:How can I prevent a user from deleting pre-existing text in an EditText widget?如何防止用户删除 EditText 小部件中预先存在的文本?
【发布时间】:2021-01-16 18:01:13
【问题描述】:

我有一个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()) 一起使用,或者创建一个自定义视图(尽管我以前从未做过其中之一)。

【问题讨论】:

  • 考虑使用InputFilter
  • EditText 不是合适的工具。我会查看 TextField 和 EditText 的组合,或者使用可以从 EditText 派生的功能编写自定义视图
  • 这很 hacky,但是为什么不在 EditText 的左侧添加一个带有固定文本的 TextView,并以某种方式设置两个视图的样式,使它们看起来像一个单独的视图。
  • 我已经更新了我的帖子,以包含更多关于我尝试过的以及我想要实现的目标的详细信息。

标签: android kotlin text android-edittext


【解决方案1】:

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

如果您仍然需要使用EditText,则可以更改条件以使用startsWith() 方法检查EditText 观察程序返回的CharSequence 是否以原始文本开头

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?) {}
})

【讨论】:

  • 我已经更新了我的帖子,我认为您使用 startsWith() 的解决方案可能是我唯一的选择。
  • 我看到您需要EditTextTextView 的末尾连续。这将是多么复杂.. 并且可以从屏幕尺寸/分辨率更改为另一个(您需要准确计算文本相对于屏幕结束的时间).. 文本大小也是此计算的一个参数.. 您可以尝试使用 Custom 视图
  • @BobSacamano 请看here
  • 我现在决定使用您的 EditText 解决方案。其他答案很有趣,但最终并不完美。
【解决方案2】:

您可以使用文本字段,它是 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内容的一部分,所以用户不能修改。

有用的链接:

【讨论】:

  • 使用单一视图的优雅解决方案 +1
  • 恐怕这行不通。查看我的更新
  • @BobSacamano - 是的,这只有在可以确定前缀相当短的情况下才能正常工作。
【解决方案3】:

这个检查应该有效:

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

但请考虑查看InputFilter,作为评论建议。

【讨论】:

    猜你喜欢
    • 2021-12-21
    • 2012-11-29
    • 2011-01-17
    • 2020-07-30
    • 1970-01-01
    • 2013-01-20
    • 2015-06-10
    • 1970-01-01
    • 2019-08-14
    相关资源
    最近更新 更多