如何在内部控制中传递 ObservableField

How to pass ObservableField inside internal control

主视图模型如下所示:

class MainVM{
    public ObservableField<String> title;
    public ObservableField<Boolean> isFlexible;
}

主要布局如下:

<layout>
  <date><variable name="item" type="MainVM"></data>
  <LinearLayout>
     <TextView text="@{item.title}"/>
     <CustomCtrl1 vm="@{item.isFlexible}">
  </LinearLayout>
</layout>

CustomCtrl的布局有点像

   <layout>
      <date><variable name="item" type="boolean"></data>
      <LinearLayout>
          ...
         <Switch checked="@{item}"/>
          ...
      </LinearLayout>
    </layout>

问题是 ObservableFieldMainVM 传递给 CustomCtrl 时会转换为布尔值,之后在 CustomCtrl 中更改布尔值不会影响 MainVM的。第一个想法是将 CustomCtrl's viewmodel 从 Boolean 更改为 ObservableField<Boolean> 但由于某些原因不允许这样做。

所以问题是 - 在内部控制中传递 ObservableField 的正确方法是什么。

最好的方法是直接使用双向绑定。这需要 Android Studio 2.1 及更高版本。 Android Studio 2.2 修复了一个 inflation 自定义控件可能会遇到的错误。如果您使用的是 include 而不是自定义控件,那将是微不足道的:

<layout>
  <date><variable name="item" type="MainVM"></data>
  <LinearLayout>
     <TextView android:text="@{item.title}"/>
     <include layout="@layout/other" app:vm="@={item.isFlexible}">
  </LinearLayout>
</layout>

其他布局:

<layout>
  <date><variable name="item" type="boolean"></data>
  <LinearLayout>
      ...
     <switch android:checked="@={item}"/>
      ...
  </LinearLayout>
</layout>

使用自定义控件,您必须自己实现侦听器。这意味着您必须有一个 属性 的侦听器。我认为这应该可行(我现在在平板电脑上,所以我无法验证):

@InverseBindingMethods({
     InverseBindingMethod(type = CustomControl.class, attribute="vm")})
public class CustomCtrl extends View {
    private CustomCtrlBinding binding;
    private InverseBindingAdapter listener;

    public CustomCtrl(...) {
        binding = ...
        binding.addOnPropertyChangedCallback(new OnPropertyChangedCallback() {
            @Overriide
            public void OnPropertyChanged(Observable sender, int propertyId) {
                if (listener != null) {
                    listener.onChange();
                }
            }
        });
    }

    @Bindable
    public boolean getVm() { return binding.getItem(); }

    public void setVm(boolean vm) {
        binding.setItem(vm);
    }

    @BindingAdapter("vmAttrChanged")
    public static void setListener(CustomCtrl view,
            InverseBindingListener listener) {
        view.listener = listener;
    }
}

那么你就有了双向绑定:

<layout>
  <date><variable name="item" type="MainVM"></data>
  <LinearLayout>
     <TextView android:text="@{item.title}"/>
     <CustomCtrl app:vm="@={item.isFlexible}">
  </LinearLayout>
</layout>

以及自定义控件布局:

<layout>
  <date><variable name="item" type="boolean"></data>
  <LinearLayout>
      ...
     <switch android:checked="@={item}"/>
      ...
  </LinearLayout>
</layout>

我通常会编写一个具有自己的属性侦听器的自定义控件,但 InverseBindingListener 在紧要关头工作。