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();
}
}
希望这对某人有所帮助。
是否可以将 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();
还要详细说明
在包含存根的布局中(例如 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();
}
}
希望这对某人有所帮助。