Android 数据绑定 - 如何将 ViewStub 与数据绑定一起使用

Android Data Binding - how to use ViewStub with data binding

是否可以将 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 dataBinding 一起使用?

这是我从docs看到的:

ViewStubs

ViewStub 与普通的 View 有点不同。他们出发 不可见以及当它们可见或被明确告知时 膨胀,他们通过膨胀另一个来取代自己在布局中 布局。

因为 ViewStub 基本上从视图层次结构中消失了, 绑定 object 中的视图也必须消失才能允许 collection。因为视图是最终的,所以 ViewStubProxy object 需要 ViewStub 的位置,使开发人员可以访问 ViewStub 当它存在并且当 ViewStub 已膨胀

膨胀另一个布局时,必须为 新版面。因此,ViewStubProxy 必须监听 ViewStub 的 ViewStub.OnInflateListener 并在此时建立绑定。 由于只能存在一个,ViewStubProxy 允许开发人员 在其上设置一个 OnInflateListener,它将在建立后调用 绑定。

只需按照文档中的说明设置监听器即可:

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

设置侦听器以在 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();

声明您的 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() 布局就会有数据。 您可以检查生成的绑定 class 来验证这一点。它甚至具有类型安全性,因此您不能将任何其他类型传递给 data.

我也遇到过这类问题, 终于我找到了解决方案,而且效果很好。

ViewStub 控股布局,

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

code里面的Class是,

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

还要详细说明 , and include the

在包含存根的布局中(例如 my_fragment.xml)

    <data class="MyDataBinding">
        ...
    </data>

    ...
    <ViewStub 
        android:id="@+id/stub_import"
        ... />

在您的 activity 或片段中(下面的示例使用片段):

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 的 documentation/source 代码很好。

当您创建新的 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);       


      }));

   }

如果您正在使用 ViewModels,那么您还需要为膨胀视图设置 生命周期所有者,请记住在 fragment/activity 视图。

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

希望这对某人有所帮助。