include 替换成 ViewStub .
ViewStub 的优点就是不用的布局,可以不加载。不像include,虽然没有显示,但是总要先加载布局。
xml 需要修改:
step1:
<include>替换成<ViewStub>标签。
step2:
layout 属性换成 android:layout.
注意,如果不修改,运行会奔溃。 报没有设置layout。
step3:
id 修改为带viewStub 的名字。不修改不报错,但是表意不清晰;
step4:
设置 android:inflatedId="@+id/your_layout"。
注意:如果与约束性布局结合使用, android:inflatedId 属性值必须与 android:id一致。
设置与 id不同的值不会报错,但是会导致约束失效。具体参考:
https://stackoverflow.com/questions/47164398/how-to-use-viewstub-in-constraintlayout
当与databinding 结合使用时,根据id获取viewStub.inflate获取到view,
根据 DataBindingUtil.getBinding(view)获取到 viewStub 的binding。
代码如下(这里的binding 是根布局binding):
val inflateView = binding.contentViewStub.viewStub?.inflate()
val newBinding = DataBindingUtil.getBinding<IncludeNewLayoutBinding>(inflateView)
newBinding?.vm = vm
注意事项:ViewStub 只能inflate一次。在可能被复用的地方格外要注意(比如recyclerView 的adapter中)
ViewStub inflate 后,就会被替换为对应的layout, 再获取父布局就为null.
也就是 上面的代码,如果inflate后 ,binding.contentViewStub.viewStub 获取到的就是null。
那么inflate后,怎么隐藏呢,设置 visibility 来控制。
参考代码:
if (binding.contentViewStub.isInflated) {
//viewStub 只能inflate 一次
binding.contentViewStub.binding?.root?.visibility = View.VISIBLE
} else {
//这里viewStub肯定不为null
val inflateView = binding.contentViewStub.viewStub!!.inflate()
val newBinding = DataBindingUtil.getBinding<IncludeContentLayoutBinding>(inflateView)
newBinding?.vm = vm
}
题外话:
来看下源码ViewStubProxy.isInflated() 怎么判断的:很显然,加载后返回true,没加载返回false。
/**
* Returns <code>true</code> if the ViewStub has replaced itself with the inflated layout
* or <code>false</code> if not.
*
* @return <code>true</code> if the ViewStub has replaced itself with the inflated layout
* or <code>false</code> if not
*/
public boolean isInflated() {
return mRoot != null;
}
getViewStub 可以看到,只要加载过就返回null.没有加载过就返回layout。
那么用之前判断下有没有加载过。加载过,控制可见性;没加载,如果需要显示直接加载。
/**
* Returns the ViewStub in the layout or <code>null</code> if the ViewStub has been inflated.
*
* @return the ViewStub in the layout or <code>null</code> if the ViewStub has been inflated.
*/
@Nullable
public ViewStub getViewStub() {
return mViewStub;
}