【问题标题】:Can I databind a ProgressBar in Android?我可以在 Android 中对 ProgressBar 进行数据绑定吗?
【发布时间】:2015-07-11 18:34:53
【问题描述】:

是否可以在 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}"
  [...]

但它未被识别。 (只要我在引号之间写了一个“@”,它就在编辑器中变红了)。还有另一种数据绑定方式吗?

【问题讨论】:

  • 嗯,它应该可以工作。这可能是一个 IDE 突出显示错误。你试过编译吗?
  • 我今天了解到,我应该总是尝试编译 :) 它有效!谢谢,yigit!
  • 但是,嗯,它确实调用了 foo.getBar() 方法将自己设置在正确的位置。但它似乎从未调用 foo.setBar() 方法,因此该值从未在我的代码中更新。它还需要一个 SeekBarChangeListener,还是什么?
  • 我们没有双向数据绑定。正确和部分成本很高是很棘手的,我们正在努力使数据绑定尽可能接近您将编写的代码(+优化)。我们可以在 v1 之后添加双向绑定。
  • RC1 刚刚发布,虽然您没有双向数据绑定,但您现在可以轻松绑定到处理程序方法。 android:onProgressChanged="@{handlers.progressChanged}" 您的处理程序类有一个 progressChanged 方法,具有相同的参数和 onProgressChanged 的​​返回值。

标签: android data-binding android-seekbar


【解决方案1】:

要在 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(菜单 Navigate>File),您将了解可以通过那里的适配器绑定到的所有事件方法。之所以可以使用此特定功能,是因为 Google 实施了以下适配器:

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

【讨论】:

    【解决方案2】:

    如果它对某人有帮助,这个问题在搜索中出现了很多,现在可以使用双向数据绑定来完成。我在下面使用了两个可绑定的值,我倾向于在 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(...) 方法。

    这个被称为,它会通过调用setSeekDisplay(...)来更新你的TextView

    【讨论】:

    • +1 表示 @={} 表示法。您也可以使用单一属性 seekValue 并在 TextView 上使用 @{Integer.toString(viewModel.seekValue)}。
    【解决方案3】:

    @George Mount 是正确的,您必须在布局 xml 中添加一个处理程序,该处理程序在您的模型或处理程序类中定义(无论您如何称呼它)。

    查看我对这个问题的回答以获得完整的示例:

    Two way databinding with Android Databinding Library

    这是该答案的示例:

    例子:

    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"
    

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

    到您的 XML 命名空间。

    此解决方案适用于所有输入控件,包括自定义,只要您在模型中提供正确的侦听器。

    TextWatcher Reference

    【讨论】:

      【解决方案4】:

      你可能需要像下面这样使用双向绑定。

      添加绑定工具类

      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"/>
      

      【讨论】:

      • 你太棒了!!经过4小时的搜索!!终于
      猜你喜欢
      • 2021-12-13
      • 1970-01-01
      • 2011-12-03
      • 2018-07-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-06-03
      • 1970-01-01
      相关资源
      最近更新 更多