Android数据绑定 - 如何使用ViewStub进行数据绑定

时间:2016-01-11 01:40:10

标签: 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 dataBinding一起使用?

这是我从docs看到的:

  
    

ViewStubs

  
     

ViewStubs与普通视图略有不同。他们开始了   看不见的,当它们被显示或被明确告知时   为了膨胀,他们通过膨胀另一个来替换自己的布局   布局。

     

因为ViewStub基本上从View层次结构中消失,   绑定对象中的视图也必须消失才能允许   采集。因为视图是最终的,所以ViewStubProxy对象需要   ViewStub的位置,使开发人员可以访问ViewStub   当它存在时,还可以访问膨胀的View层次结构   ViewStub已被夸大。

     

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

8 个答案:

答案 0 :(得分:15)

只需按照文档说明设置监听器:

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

答案 1 :(得分:1)

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

答案 2 :(得分:1)

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

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

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

答案 3 :(得分:0)

设置侦听器,以便在成功膨胀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();

答案 4 :(得分:0)

只需详细说明@andrew-classen's accepted answer above,并同时包含@user9113597's answer

在包含存根的布局中(例如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>
    ...

答案 5 :(得分:0)

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

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

然后,不要设置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);       


  }));

}

答案 6 :(得分:0)

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

希望这对某人有所帮助。

答案 7 :(得分:-1)

可以通过使用

随时访问绑定
layout_binding.viewStub.binding

,然后将其转换为布局的生成的Binding类

(layout_bindinng.viewStub.binding as YourLayoutBinding).viewModel = viewModel

请谨慎进行null检查,因为在充气之前它将为null。