22

无论如何可以将 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 一起使用?

这是我从文档中看到的:

查看存根

ViewStubs 与普通的 Views 有点不同。它们一开始是不可见的,当它们变得可见或被明确告知膨胀时,它们会通过膨胀另一个布局来替换布局中的自己。

因为 ViewStub 本质上从 View 层次结构中消失了,绑定对象中的 View 也必须消失才能允许收集。因为 Views 是最终的,所以 ViewStubProxy 对象代替了 ViewStub,当 ViewStub 存在时,开发人员可以访问它,并且当 ViewStub 膨胀时,还可以访问膨胀的 View 层次结构。

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

4

7 回答 7

32

只需按照文档所述设置侦听器:

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();
    }
}
于 2016-01-11T01:52:21.467 回答
9

声明你的 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>

另一个_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.

于 2017-05-31T10:41:51.030 回答
4

只是为了详细说明上面@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>
    ...
于 2018-11-22T23:22:38.663 回答
2

我这样做的另一种方法是使用 ViewStubProxy。ViewStubProxy 的文档/源代码很好。

当您创建新的 ViewStubProxy 时,请在构造函数中传入您的 ViewStub。然后ViewStubProxy.setContainingBinding(<pass in your root layout binding>)。如果你不这样做,你会得到空值。

然后设置 ViewStubProxy.setOnInflateListener 来设置绑定变量和 LifecycleOwner,而不是设置 ViewStub.setOnInflateListener(ViewStubProxy 会在内部为您设置一个)。

示例代码:

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


      }));

   }
于 2019-06-07T16:06:36.647 回答
1

设置监听器以在成功充气后访问充气布局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();
于 2017-04-25T13:51:11.757 回答
1

我也遇到过这类问题,最后我得到了一个解决方案并且它完美地工作。

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

类里面的代码是,,,

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();
于 2017-12-20T10:55:19.127 回答
1

如果您正在使用 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();
    }
}

希望这对某人有所帮助。

于 2020-08-12T11:48:50.293 回答