Как привязать данные к onTextChanged для EditText на Android?

В Yigit Boyar и George Mount рассказывают о привязке данных к Android, они иллюстрируют, как легко привязываться к TextWatcher onTextChanged (при 13: 41). На кнопке. Ошибочны ли их слайды? Прежде всего Button View не имеет свойства onTextChanged. Он не имеет метода setOnTextChanged. Также не существует EditText. Но они оба имеют addTextChangedListener, который принимает вход TextWatcher.

Так о чем они говорят? Как они это делают? Их примерный код не компилируется, но дает эту ошибку:

Error:(17) No resource identifier found for attribute 'onTextChanged' in package 'android'

Как мне привязываться к "событию с измененным текстом" на любом представлении или в частности в EditText с помощью платформы привязки данных Android?

Ответ 1

На самом деле это работает из коробки. Я думаю, что моя ошибка заключалась в использовании старой версии структуры привязки данных. Используя последнее, это процедура:

Вид:

<EditText
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:id="@+id/username"
    android:text="Enter username:"
    android:onTextChanged="@{data.onTextChanged}" />

Модель:

public void onTextChanged(CharSequence s, int start, int before, int count) {
    Log.w("tag", "onTextChanged " + s);
}

Убедитесь, что вы ссылаетесь на gradle инструменты сборки v1.5.0 или новее и включили привязку данных с помощью android.dataBinding.enabled true в файле build.gradle.

изменить: Функциональный демонстрационный проект здесь. просмотреть. model.

Ответ 2

Чтобы расширить ответ @Nilzors, также возможно передать текст и/или другие параметры в макете:

Вид:

<EditText
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:id="@+id/username"
    android:text="Enter username:"
    android:onTextChanged="@{(text, start, before, count) -> viewModel.onUsernameTextChanged(text)}" />

ViewModel:

public void onUsernameTextChanged(CharSequence text) {
    // TODO do something with text
}

Вам всегда нужно передать либо нулевой, либо все параметры.

Ответ 3

Легко

Если вы используете onTextChange() для обновления текста в модели, вы можете напрямую использовать двустороннюю привязку.

<data>
    <variable
        name="user"
        type="com.package.User"/>
</data>

<EditText
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:text="@={user.name}"/>

И у вашего модельного класса будет getter и setter.

public class User {
    private String name;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }
}

Теперь имя в модели будет изменено в реальном времени при взаимодействии с пользователем. Поэтому, всякий раз, когда вы используете binding.getUser().getName(), вы получите последний текст.

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

android:text="@{user.name}"

Двухстороннее связывание обновляет переменную модели в режиме реального времени с помощью пользовательского ввода.

android:text="@={user.name}"

ЕДИНСТВЕННАЯ разница - = (знак равенства) в одностороннем и двустороннем связывании.

Ответ 4

лучший способ для этого - добавить адаптер связывания и средство просмотра текста.

public class Model{
    private TextWatcher textWatcher;

public Model(){
        this.textWatcher= getTextWatcherIns();
}

private TextWatcher getTextWatcherIns() {
        return new TextWatcher() {
            @Override
            public void beforeTextChanged(CharSequence s, int start, int count, int after) {
                //do some thing
            }

            @Override
            public void onTextChanged(CharSequence s, int start, int before, int count) {
                //do some thing

            }

            @Override
            public void afterTextChanged(Editable s) {
                //do some thing
            }
        };
    }

    public TextWatcher getTextWatcher() {
        return textWatcher;
    }

    public void setTextWatcher(TextWatcher textWatcher) {
        this.textWatcher = textWatcher;
    }

    @BindingAdapter("textChangedListener")
    public static void bindTextWatcher(EditText editText, TextWatcher textWatcher) {
        editText.addTextChangedListener(textWatcher);
    }
}

и в вашем XML добавить этот атрибут к вашему тексту редактирования

<EditText
            android:id="@+id/et"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            app:textChangedListener="@{model.textWatcher}" />

Ответ 5

Прикрепите setOnFocusChangeListener к EditText и сравните текстовое содержимое с глобальной переменной (предыдущего состояния/содержимого поля), чтобы определить, изменилось ли оно:

    mEditTextTitle.setOnFocusChangeListener(new View.OnFocusChangeListener() {
        @Override
        public void onFocusChange(View v, boolean hasFocus) {
            if(!hasFocus)
                // check if text has changed       
        }
    });