Android Data Binding - как использовать ViewStub с привязкой данных
Есть ли в любом случае использовать ViewStubs с DataBinding? может помочь ViewStubProxy?
Мой ток заглушки выглядит так:
<ViewStub
android:id="@+id/stub_import"
android:inflatedId="@+id/panel_import"
android:layout="@layout/progress_overlay"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_gravity="@{myobject.bottom ? bottom:top}" />
Но этот макет будет заменен, когда я надуваю ViewStub, так как же можно использовать ViewStubs с привязкой данных Android?
это то, что я вижу из документов:
ViewStubs
ViewStubs немного отличаются от обычных видов. Они начинаются невидимыми, и когда их либо делают видимыми, либо явно просят их надуть, они заменяют себя в макете, раздувая другой макет.
Поскольку ViewStub по существу исчезает из иерархии View, View для объекта привязки также должен исчезать, чтобы разрешить сбор. Поскольку представления являются окончательными, объект ViewStubProxy занимает место ViewStub, предоставляя разработчику доступ к ViewStub, когда он существует, а также доступ к раздутой иерархии View, когда ViewStub был раздут.
При накачивании другого макета необходимо установить привязку для нового макета. Поэтому ViewStubProxy должен прослушать ViewStub ViewStub.OnInflateListener и установить привязку в это время. Поскольку может существовать только один, ViewStubProxy позволяет разработчику установить для него OnInflateListener, который он будет вызывать после установления привязки.
9 ответов
Просто установите слушателя так, как говорит доктор:
mBinding.viewStub.setOnInflateListener(new ViewStub.OnInflateListener() {
@Override
public void onInflate(ViewStub stub, View inflated) {
ViewStubBinding binding = DataBindingUtil.bind(inflated);
binding.setModel(model);
}
});
public void inflateViewStub(View view) {
if (!mBinding.viewStub.isInflated()) {
mBinding.viewStub.getViewStub().inflate();
}
}
Объявите свое пространство имен xml и передайте переменную через него. Это работает с <include>
тоже кстати. Вот пример:
main_layout.xml:
<layout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:my-namespace="http://schemas.android.com/apk/res-auto">
<data>
<variable name="myData" type="com.example.SomeModel" />
</data>
<RelativeLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content">
<ViewStub
android:id="@+id/view_stub"
android:inflatedId="@+id/view"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout="@layout/another_layout"
my-namespace:data="@{myData}"
/>
</RelativeLayout>
</layout>
another_layout.xml:
<layout xmlns:android="http://schemas.android.com/apk/res/android">
<!-- No need to declare my-namespace here -->
<data>
<variable name="data" type="com.example.SomeModel" />
</data>
<RelativeLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@{data.someValue}" />
</RelativeLayout>
</layout>
Так что теперь вам просто нужно позвонить inflate()
и макет будет иметь данные. Вы можете проверить сгенерированный класс привязки, чтобы убедиться в этом. У него даже есть безопасность типов, так что вы не можете передать любой другой тип в data
,
Просто, чтобы уточнить принятый ответ @ andrew-classen выше, а также включить ответ @user9113597:
В вашем макете, который содержит заглушку (например, my_fragment.xml)
<data class="MyDataBinding">
...
</data>
...
<ViewStub
android:id="@+id/stub_import"
... />
В вашей деятельности или фрагменте (пример ниже использует фрагмент):
MyDataBinding mBinding;
MyViewModel mViewModel;
@Nullable
@Override
public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container,
@Nullable Bundle savedInstanceState)
{
mBinding = DataBindingUtil.inflate(inflater, R.layout.my_fragment, container, false);
mBinding.viewStub.setOnInflateListener(new ViewStub.OnInflateListener()
{
@Override
public void onInflate(ViewStub stub, View inflated)
{
ViewDataBinding dataBinding = DataBindingUtil.bind(inflated);
binding.setVariable(BR.mViewModel, mViewModel));
}
});
}
public void inflateViewStub(View view) {
if (!mBinding.viewStub.isInflated()) {
mBinding.viewStub.getViewStub().inflate();
}
}
В вашем макете заглушки:
<layout xmlns:android="http://schemas.android.com/apk/res/android">
<data>
<variable
name="mViewModel"
type="com.example.myapp.MyViewModel" />
</data>
...
Другой способ, которым я это сделал, - использование ViewStubProxy. Документация / исходный код для ViewStubProxy хороши.
Когда вы создаете свой новый ViewStubProxy, передайте свой ViewStub в конструктор. потомViewStubProxy.setContainingBinding(<pass in your root layout binding>)
. Если вы этого не сделаете, вы получите нули.
Затем вместо установки ViewStub.setOnInflateListener (ViewStubProxy установит его для вас внутри), установите ViewStubProxy.setOnInflateListener, чтобы установить свои переменные привязки и LifecycleOwner.
Образец кода:
private void setBindings(){
//usual outside layout binding steps
binding = (MeasurementsLayoutBinding) getBinding();
binding.setViewModel(viewModel());
binding.setLifecycleOwner(this);
//cartSideStubView is the root layout stubview
cartViewStubProxy = new ViewStubProxy(cartSideStubView);
cartViewStubProxy.setContainingBinding(binding);
cartViewStubProxy.setOnInflateListener(((viewStub, view) -> {
cartViewStubProxy.getBinding().setVariable(BR.viewModel, viewModel());
cartViewStubProxy.getBinding().setLifecycleOwner(this);
//after inflation you can find your viewstub views
cartHitchToFixedAxleInputField = view.findViewById(R.id.cart_hitch_to_fixed_axle_input_field);
}));
}
Настройте слушателя, чтобы получить доступ к надутому макету после успешного надувания viewStub
mBinding.viewStub.setOnInflateListener(new OnInflateListener() {
@Override
public void onInflate(ViewStub stub, View inflated) {
ViewStubBinding binding = DataBindingUtil.bind(inflated); //call after succesful inflating of viewStub
// set data here
}
});
Тогда надуйте свой viewStub
mBinding.viewStub.getViewStub().inflate();
Если вы работаете с ViewModels, вам также необходимо установить владельца жизненного цикла для расширенного представления. Не забудьте установить того же владельца, который вы установили для переменной mBinding во время просмотра фрагмента / активности.
mBinding.viewStub.setOnInflateListener(new ViewStub.OnInflateListener() {
@Override
public void onInflate(ViewStub stub, View inflated) {
ViewStubBinding binding = DataBindingUtil.bind(inflated);
binding.setModel(model);
binding.setLifeCycleOwner(this) // setLifeCycleOwner
}
});
public void inflateViewStub(View view) {
if (!mBinding.viewStub.isInflated()) {
mBinding.viewStub.getViewStub().inflate();
}
}
надеюсь, что это поможет кому-то.
Я также столкнулся с этим типом проблем, наконец, я получил решение и его прекрасно работает.
ViewStub Holding Макет,,
<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android">
<data class="MBinding">
<variable
name="mmmmm"
type="com.vvv.bbb.fragments.MFragment" />
</data>
--------------------
--------------------
<ViewStub
android:id="@+id/stub_import"
-------------------
-------------------
<ViewStub/>
--------------------
--------------------
<layout/>
макет внутри ViewStub является,,,
<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto">
<data class="MViewStubLayoutBinding">
<variable
name="mmmmm"
type="com.vvv.bbb.fragments.MFragment" />
</data>
----------------
----------------
----------------
Код внутри класса есть,,,
public Class KKKKKK() {
-----------------
MBinding mBinding;
MViewStubLayoutBinding mviewStubLayoutBinding;
-----------------------------
-----------------------------
mBinding.stubImport.getViewStub().setLayoutResource(R.layout.progress_overlay);
mBinding.stubImport.setOnInflateListener(new ViewStub.OnInflateListener() {
@Override
public void onInflate(ViewStub viewStub, View view) {
mviewStubLayoutBinding=DataBindingUtil.bind(view);
}
});
autoCheckBinding.vsAutoDetailsOne.getViewStub().inflate();
Можно получить доступ к привязке в любое время, используя
layout_binding.viewStub.binding
а затем приведение в качестве сгенерированного класса Binding для вашего макета
(layout_bindinng.viewStub.binding as YourLayoutBinding).viewModel = viewModel
Будьте осторожны с нулевой проверкой, так как она будет нулевой перед раздутием.
Я предпочитаю раздувать макеты ViewStub следующим образом:
MainViewbinding mainBinding = MainViewbinding.inflate(LayoutInflater.from(context));
ItemStubBinding stubBinding = DataBindingUtil.inflate(LayoutInflater
.from(context), R.layout.item_stub, binding.container, true); // binding.container is the ViewGroup
Таким образом, я могу сразу использовать представления из привязки ViewStub.