Główny model widoku wygląda tak:
class MainVM{
public ObservableField<String> title;
public ObservableField<Boolean> isFlexible;
}
główny układ wygląda tak:
<layout>
<date><variable name="item" type="MainVM"></data>
<LinearLayout>
<TextView text="@{item.title}"/>
<CustomCtrl1 vm="@{item.isFlexible}">
</LinearLayout>
</layout>
i CustomCtrl
Układ „wygląda trochę jak
<layout>
<date><variable name="item" type="boolean"></data>
<LinearLayout>
...
<Switch checked="@{item}"/>
...
</LinearLayout>
</layout>
Problemem jest ObservableField
od MainVM
konwertuj wartość s na wartość boolowską po przekazaniu do CustomCtrl
i po zmianie wartości logicznej wewnątrz CustomCtrl
nie wpływaj MainVM
„s. Pierwszym pomysłem była zmiana CustomCtrl"s
viewmodel z Boolean
do ObservableField<Boolean>
ale z jakiegoś powodu nie jest to dozwolone.
Więc pytanie brzmi - jaki jest właściwy sposób przekazywania ObservableField
wewnątrz kontroli wewnętrznej.
Odpowiedzi:
1 dla odpowiedzi № 1Najlepszym sposobem na to jest użycie wiązania dwukierunkowegobezpośrednio. Wymaga to Android Studio 2.1 i nowszych. Android Studio 2.2 naprawia błąd inflacyjny, który możesz trafić za pomocą niestandardowych kontrolek. Jeśli użyłbyś dołączenia zamiast kontrolki niestandardowej, byłoby to dość trywialne:
<layout>
<date><variable name="item" type="MainVM"></data>
<LinearLayout>
<TextView android:text="@{item.title}"/>
<include layout="@layout/other" app:vm="@={item.isFlexible}">
</LinearLayout>
</layout>
I inny układ:
<layout>
<date><variable name="item" type="boolean"></data>
<LinearLayout>
...
<switch android:checked="@={item}"/>
...
</LinearLayout>
</layout>
Dzięki niestandardowej kontroli musisz zaimplementować słuchacza samodzielnie. Oznacza to, że musisz mieć słuchacza dla nieruchomości. Myślę, że to powinno zadziałać (jestem teraz na tablecie, więc nie mogę „zweryfikować”):
@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;
}
}
Następnie masz powiązanie dwukierunkowe:
<layout>
<date><variable name="item" type="MainVM"></data>
<LinearLayout>
<TextView android:text="@{item.title}"/>
<CustomCtrl app:vm="@={item.isFlexible}">
</LinearLayout>
</layout>
I niestandardowy układ sterowania:
<layout>
<date><variable name="item" type="boolean"></data>
<LinearLayout>
...
<switch android:checked="@={item}"/>
...
</LinearLayout>
</layout>
Normalnie napisałbym niestandardową kontrolkę, która miała swój własny detektor dla atrybutu, ale InverseBindingListener działa w szczyptę.