web-dev-qa-db-ja.com

AndroidでProgressBarをデータバインドできますか?

AndroidのSeekBarまたはProgressBarにデータバインディングを使用することは可能ですか?私はこのデータ要素を持っています:

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

TextFieldで変数foo.bar(int)を参照すると、期待どおりに機能します。

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

私がやろうとしたことはこれでした:

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

しかし、それは認識されませんでした。 (引用符の間に「@」を書くとすぐに、エディターで赤くなりました)。それをデータバインディングする別の方法はありますか?

12
prograde

SeekBarが変更されたときにTextViewを更新するには、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 + "");
    }
}

一般に、データバインディング用に作成されたすべてのアダプタクラスのソースコードを確認することをお勧めします。たとえば、Android Studio(メニューの[ナビゲート]> [ファイル])でファイルSeekBarBindingAdapter.Javaに移動すると、そこにあるアダプターを介してバインドできるすべてのイベントメソッドを学習できます。 Googleが次のアダプターを実装しているため、この機能を利用できます。

@BindingAdapter("Android:onProgressChanged")
public static void setListener(SeekBar view, OnProgressChanged listener) {
    setListener(view, null, null, listener);
}
15
Nilzor

それが誰かを助ける場合、この質問は検索の下でたくさん出てきます、これは今双方向データバインディングを使用して行うことができます。以下の2つのバインド可能な値を使用します。XML自体に表示ロジックを使用しないことを好む傾向がありますが、1つだけでも機能すると思います。

ViewModelにバインド可能な値を作成します。1つはSeekBarseekValue)用、もう1つはTextViewseekDisplay)用です。

_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(...)メソッドが呼び出されます。

これが呼び出されると、setSeekDisplay(...)を呼び出すことによってTextViewが更新されます。

5
Kirk

@George Mountは正しいです。モデルまたはハンドラークラス(どのように呼んでも)で定義されているハンドラーをレイアウトxmlに追加する必要があります。

本格的な例については、この質問に対する私の答えを見てください。

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:hereを使用しています。 bind:を使用して、バインディングをより明確にすることもできます。

だから、追加することをお見逃しなく

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

または

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

xML名前空間に。

このソリューションは、モデルに正しいリスナーを指定すれば、カスタムを含むすべての入力コントロールで機能します。

TextWatcherリファレンス

以下のような双方向バインディングを使用する必要があるかもしれません。

バインディング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"/>
0
Shahbaz Hashmi