У меня есть 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?) {}
    })
}

Что я должен делать? Я открыт для всех идей.

Благодарность!

Изменить:

Я также пробовал комбинировать EditText и TextView (как предлагали некоторые), но создать макет сложно, потому что и исходный текст, и новый текст могут занимать несколько строк. Мое решение выше содержит одно слово в исходном тексте, но их может быть много. Поэтому мне нужно учитывать этот сценарий:

textview and edittext

... где белое поле представляет TextView, а красное поле представляет EditText.

Я не думаю, что ответ Bö macht Blau сработает, потому что префикс находится в отдельном «столбце».

Я думаю, мне придется использовать решение Zain с (startsWith()) или создать собственное представление (хотя я никогда раньше не делал ничего из этого).

1
BobSacamano 16 Янв 2021 в 21:01

3 ответа

Лучший ответ

Пожалуйста, примите во внимание совет @Gabe Sechan в комментариях OP о том, что само по себе EditText не является оптимальным решением для этого.

Если вам все еще нужно использовать EditText, вы можете изменить условие, чтобы проверить, что возвращаемый CharSequence наблюдателя EditText начинается с исходного текста, используя startsWith() метод

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?) {}
})
1
Zain 16 Янв 2021 в 18:37

Вы можете использовать текстовое поле, представляющее собой комбинацию TextInputEditText и TextInputLayout. Затем вы можете установить такой префикс:

<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
Bö macht Blau 16 Янв 2021 в 20:26

Эта проверка должна работать:

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

Но рассмотрите возможность изучения InputFilter, как предлагается в комментарии.

0
Noah 16 Янв 2021 в 18:13
65752870