Могу ли я привязать данные ProgressBar в Android?

Можно ли использовать привязку данных для SeekBar или ProgressBar в Android? У меня есть этот элемент данных:

<data>
  <variable
     name="foo"
     type="com.example.Foo" />
</data>

Если я ссылаюсь на переменную foo.bar (которая является int) в TextField, она работает так, как ожидалось:

<TextView
  android:text="@{String.valueOf(foo.bar)}"
  [...]

Я пытался сделать следующее:

<SeekBar
  android:progress="@{foo.bar}"
  [...]

но его не признали. (Как только я написал "@" между кавычками, он стал красным в редакторе). Есть ли другой способ привязки данных?


person prograde    schedule 11.07.2015    source источник
comment
Хм должно работать. Это может быть ошибка подсветки IDE. Вы пробовали компилировать?   -  person yigit    schedule 12.07.2015
comment
Сегодня я узнал, что всегда должен пытаться компилировать :) Это работает! Спасибо, йигит!   -  person prograde    schedule 13.07.2015
comment
Но, хм, он вызывает метод foo.getBar(), чтобы установить себя в нужное положение. Но он никогда не вызывает метод foo.setBar(), поэтому значение никогда не обновляется в моем коде. Ему все еще нужен SeekBarChangeListener или что?   -  person prograde    schedule 13.07.2015
comment
У нас нет двухсторонней привязки данных. Это сложно сделать правильно и частично дорого, и мы пытаемся сохранить привязку данных как можно ближе к коду, который вы написали бы (+ оптимизация). Мы можем добавить двустороннюю привязку после v1.   -  person yigit    schedule 13.07.2015
comment
RC1 был только что выпущен, и хотя у вас нет двусторонней привязки данных, теперь вы можете легко привязываться к методам обработчика. android:onProgressChanged=@{handlers.progressChanged}, где ваш класс обработчиков имеет метод progressChanged с теми же параметрами и возвращаемым значением onProgressChanged.   -  person George Mount    schedule 21.07.2015


Ответы (4)


Чтобы TextView обновлялся при изменении SeekBar, привяжите к прогрессу изменения через атрибут android:onProgressChanged. Это ожидает публичный метод в модели с сигнатурой SeekBarBindingAdapter.OnProgressChanged:

Просмотреть

<TextView
    android:text="{@model.seekBarValue} />

<SeekBar
    android:onProgressChanged="@{model.onValueChanged}" />

Модель

public class Model {
    public ObservableField<String> seekBarValue = new ObservableField<>("");

    public void onValueChanged(SeekBar seekBar, int progresValue, boolean fromUser) {
        seekBarValue.set(progresValue + "");
    }
}

В общем, я советую вам посмотреть исходный код всех классов адаптеров, созданных для привязки данных. Если вы, например, перейдете к файлу SeekBarBindingAdapter.java в Android Studio (меню «Навигация»> «Файл»), вы узнаете все методы событий, к которым вы можете привязаться через адаптеры. Эта конкретная функция доступна, потому что Google реализовал следующий адаптер:

@BindingAdapter("android:onProgressChanged")
public static void setListener(SeekBar view, OnProgressChanged listener) {
    setListener(view, null, null, listener);
}
person Nilzor    schedule 10.12.2015

Если это кому-то поможет, этот вопрос часто возникает при поиске, теперь это можно сделать с помощью двусторонней привязки данных. Я использую два связываемых значения ниже, я предпочитаю не отображать логику в самом XML, но я подозреваю, что он может работать и только с одним.

Создайте связываемые значения в ViewModel, одно для SeekBar (seekValue) и одно для TextView (seekDisplay).

int mSeekValue;
int mSeekDisplay;

@Bindable
public int getSeekValue() {
    return mSeekValue;
}

public void setSeekValue(int progress) {
    mSeekValue = progress;
    notifyPropertyChanged(BR.seekValue);
    setSeekDisplay(progress);
}

@Bindable
public String getSeekDisplay() {
    return Integer.toString(mSeekDisplay);
}

public void setSeekDisplay(int progress) {
    mSeekDisplay = progress;
    notifyPropertyChanged(BR.seekDisplay);
}

Теперь вы можете привязать их к Widgets.

<SeekBar
    android:id="@+id/my_seek"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:progress="@={viewModel.seekValue}" />
<TextView
    android:id="@+id/my_text"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:text="@{viewModel.seekDisplay}" />

Важно отметить, что вы используете двустороннюю привязку данных к SeekBar с помощью @={viewModel.seekValue}, которая вызовет ваш метод setSeekValue(...).

Один из них называется, он обновит ваш TextView, вызвав setSeekDisplay(...)

person Kirk    schedule 04.04.2017
comment
+1 для обозначения @={}. Вы также можете обойтись одним свойством seekValue и использовать @{Integer.toString(viewModel.seekValue)} в TextView. - person josmith42; 22.08.2017

@George Mount прав, вы должны добавить обработчик в свой XML-макет, который определен в вашем классе Model или Handler (как бы вы его ни называли).

Посмотрите на мой ответ на этот вопрос для полноценного примера:

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

Вот пример из этого ответа:

Пример:

public class AmanteEditModel extends BaseObservable {

    private String senhaConfirm;

    @Bindable
    public String getSenhaConfirm() {
        return senhaConfirm;
    }

    public void setSenhaConfirm(String senhaConfirm) {
        this.senhaConfirm = senhaConfirm;
        notifyPropertyChanged(BR.senhaConfirm);
    }

    // Textwatcher Reference: http://developer.android.com/reference/android/text/TextWatcher.html
    public TextWatcher getMyEditTextWatcher() {
        return new TextWatcher() {

            public void afterTextChanged(Editable s) {
            }

            public void beforeTextChanged(CharSequence s, int start,
                                          int count, int after) {
            }

            public void onTextChanged(CharSequence s, int start,
                                  int before, int count) {
                // Important! Use the property setter, otherwhise the model won't be informed about the change.
                setSenhaConfirm(s);
            }
        };
    }

}

В вашем макете xml измените EditText на это:

<EditText
    android:id="@+id/amante_edit_senha_confirm"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:layout_gravity="center_vertical"
    android:hint="Confirme a senha"
    android:inputType="textPassword"
    android:maxLines="1"
    android:text="@{model.senhaConfirm}"
    app:addTextChangeListener="@{model.myEditTextWatcher}"
    />

Следите за пространством имен addTextChangeListener. Этот метод может быть недоступен через пространство имен android:, поэтому я использую app: здесь. Вы также можете использовать bind:, чтобы сделать привязку более понятной.

Так что не пропустите, чтобы добавить

xmlns:app="http://schemas.android.com/apk/res-auto"

or

xmlns:bind="http://schemas.android.com/apk/res-auto"

к вашим пространствам имен XML.

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

Справочник по TextWatcher

person Jürgen 'Kashban' Wahlmann    schedule 28.07.2015

Возможно, вам придется использовать двустороннюю привязку, как показано ниже.

Добавить класс связывания utils

private static final String ANDROID_PROGRESS = "android:progress";

@BindingAdapter(ANDROID_PROGRESS)
public static void setSeekbarProgress(SeekBar seekBar, int progress) {
    try {
        seekBar.setProgress(progress);
    } catch (Resources.NotFoundException nfe) {
        nfe.printStackTrace();
    }
}

@InverseBindingAdapter(attribute = ANDROID_PROGRESS)
public static int getSeekbarProgress(SeekBar seekBar) {
    try {
        return seekBar.getProgress();
    } catch (Resources.NotFoundException nfe) {
        nfe.printStackTrace();
        return 0;
    }
}

Добавьте наблюдаемую в модель представления

var child1Age = ObservableField(1)

В макете

 <SeekBar
            android:id="@+id/child1_age_sb"
            style="@style/HotelChildAgeSeekBarStyle"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_marginTop="@dimen/spacing_14"
            android:progress="@={vm.child1Age}"
            app:layout_constraintLeft_toLeftOf="parent"
            app:layout_constraintRight_toRightOf="parent"
            app:layout_constraintTop_toBottomOf="@+id/childs_age_label" />

        <TextView
            android:layout_marginTop="@dimen/spacing_6"
            android:id="@+id/child1_age_value"
            android:layout_width="wrap_content"
            android:layout_height="match_parent"
            app:layout_constraintTop_toBottomOf="@+id/child1_age_sb"
            app:layout_constraintLeft_toLeftOf="@id/child1_age_sb"
            app:layout_constraintRight_toRightOf="@id/child1_age_sb"
            android:text="@{String.valueOf(vm.child1Age)}"
            android:textColor="@color/black_medium"
            android:textSize="@dimen/font_14"/>
person Shahbaz Hashmi    schedule 13.05.2019
comment
Ты замечательный!! После 4 часов поиска!! в конце концов - person Emre Kilinc Arslan; 25.07.2020