是否可以通过“if-else”条件动态包含子布局?
到目前为止,这是不可能的,因为layout 属性必须在数据绑定起作用之前指向某个布局:
(数据绑定)顾名思义就是将数据绑定到一个布局,所以必须先有一个布局,才能绑定数据。
换句话说,layout="@{model.isOk ? @layout/layout_container_1 : @layout/layout_container_2}" 不起作用,因为在检查model.isOk 之前应该有一个现有的布局,而且layout 属性需要在@ 符号之后有一个布局资源。
所以,we need to do that programmatically instead of the XML layout。这可以通过将 <include> 替换为 ViewStub 来完成,这是在活动中完成的一种延迟布局膨胀。
所以在膨胀ViewStub布局之前,你可以有机会检查一下Activity中的model.isOk是否在决定ViewStub上可以膨胀哪个布局。
因此基于model.isOk 的值,我们可以使用binding.myLayoutStub.myViewStub?.layoutResource = R.layout.layout_container_1 设置布局
最终我们可以使用binding.myLayoutStub.myViewStub?.inflate() 方法来扩充新的ViewStub 布局。
使用ViewStub,将使您拥有一对绑定对象,一个用于活动(或片段),另一个用于ViewStub的膨胀布局。
这是一个像你这样的例子:
activity_main.xml:
<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools">
<data>
<variable
name="model"
type="com.example.android.databindingexample.ActivityViewModel" />
</data>
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
<ViewStub
android:id="@+id/layout_stub"
android:layout_width="match_parent"
android:layout_height="match_parent"/>
</androidx.constraintlayout.widget.ConstraintLayout>
</layout>
我们有 layout_container_1 和 layout_container_2,它们仅在 textview 值上有所不同:
layout_container_1.xml:
<?xml version="1.0" encoding="utf-8"?>
<layout>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@color/purple_200">
<TextView
android:id="@+id/textview"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Layout 1"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>
</layout>
视图模型:
class ActivityViewModel : ViewModel() {
var isOk = true
}
然后根据model.isOk 决定Activity 中的哪个布局,每当您对ViewStub 进行充气时:
class MainActivity : AppCompatActivity() {
private lateinit var binding: ActivityMainBinding
// This is of Any type as it will be casted later to the proper DataBinding generated class when the ViewStub layout inflated
private lateinit var stubBinding: Any
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
binding = DataBindingUtil.setContentView(this, R.layout.activity_main)
val model = ViewModelProvider(this).get(ActivityViewModel::class.java)
binding.model = model
// Listener to ViewStub inflation so that we can change its layout
binding.layoutStub.setOnInflateListener { _, inflated ->
stubBinding =
(if (model.isOk) DataBindingUtil.bind<LayoutContainer1Binding>(
inflated
)
else DataBindingUtil.bind<LayoutContainer2Binding>(
inflated
))!!
// Changing the text of the inflated layout in the ViewStub using the ViewStubBinding
if (model.isOk)
(stubBinding as (LayoutContainer1Binding)).textview.text = "This is Layout container 1"
else
(stubBinding as (LayoutContainer2Binding)).textview.text = "This is Layout container 2"
}
// Inflating the ViewStub
if (!binding.layoutStub.isInflated) {
binding.layoutStub.viewStub?.layoutResource = if (model.isOk)
R.layout.layout_container_1 else R.layout.layout_container_2
binding.layoutStub.viewStub?.inflate()
}
}
}
预览: