Android Data Binding - как использовать ViewStub с привязкой данных

Можно ли использовать viewStubs с привязкой данных? может помочь 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?

это то, что я вижу из docs:

ViewStubs

ViewStubs немного отличаются от обычных представлений. Они начинают невидимыми, и когда они либо становятся видимыми, либо явно указаны надувать, они заменяют себя в макете, накачивая другой макета.

Поскольку ViewStub по существу исчезает из иерархии View, Просмотр в объекте привязки также должен исчезнуть, чтобы разрешить коллекция. Поскольку представления являются окончательными, объект ViewStubProxy принимает место ViewStub, предоставляя разработчику доступ к ViewStub когда он существует, а также доступ к расширенной иерархии представлений, когда ViewStub был завышен.

При раздувании другого макета необходимо установить привязку для новый макет. Поэтому ViewStubProxy должен прослушивать ViewStub ViewStub.OnInflateListener и установите привязку в это время. Поскольку существует только один, ViewStubProxy позволяет разработчику установите на нем OnInflateListener, который он вызовет после установления привязка.

Ответ 1

Просто установите слушателя в качестве документа:

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();
    }
}

Ответ 2

Объявите пространство имен 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.

Ответ 3

Я также столкнулся с этим типом проблем, наконец, я получил решение и его безупречную работу.

ViewStub Holding Layout,

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

layout Inside ViewStub is,,

<?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>
  ----------------
  ----------------
  ----------------

code Внутри класса есть,,

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();

Ответ 4

Установите слушателя, чтобы получить доступ к раздутому макету после успешного раздувания 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();

Ответ 5

Просто, чтобы уточнить ответ @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>
    ...

Ответ 6

Еще один способ, которым я это сделал, - использование 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);       


  }));

}