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}"
[...]
しかし、それは認識されませんでした。 (引用符の間に「@」を書くとすぐに、エディターで赤くなりました)。それをデータバインディングする別の方法はありますか?
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);
}
それが誰かを助ける場合、この質問は検索の下でたくさん出てきます、これは今双方向データバインディングを使用して行うことができます。以下の2つのバインド可能な値を使用します。XML自体に表示ロジックを使用しないことを好む傾向がありますが、1つだけでも機能すると思います。
ViewModelにバインド可能な値を作成します。1つはSeekBar
(seekValue)用、もう1つは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);
}
_
これで、これらをWidget
sにバインドできます。
_<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
が更新されます。
@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名前空間に。
このソリューションは、モデルに正しいリスナーを指定すれば、カスタムを含むすべての入力コントロールで機能します。
以下のような双方向バインディングを使用する必要があるかもしれません。
バインディング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"/>