Is it possible to include child layout dynamically through "if-else" condition?
So far, this is not possible, because the layout
attribute must point to a certain layout before the data-binding works:
(Data Binding) As its name implies, it binds data to a layout, so there must be a layout first, in order to bind data to it.
In other words, the layout="@{model.isOk ? @layout/layout_container_1 : @layout/layout_container_2}"
doesn't work because there should be an existing layout before examining model.isOk
, and also the layout
attribute expects a layout resource after the @
symbol.
So, we need to do that programmatically instead of the XML layout. And this an be done by replacing the <include>
with ViewStub
which is a sort of deferring layout inflation to be done in the activity.
So before inflating the ViewStub
layout, you can have a chance to check whether the model.isOk
in the activity before deciding which layout can be inflated on the ViewStub
.
And hence based on the model.isOk
value, we can set the layout with binding.myLayoutStub.myViewStub?.layoutResource = R.layout.layout_container_1
Eventually we can inflate the new ViewStub
layout using binding.myLayoutStub.myViewStub?.inflate()
method.
Using the ViewStub
, will make you have a couple of binding object, one for the activity (or fragment), and the other for the inflated layout of the ViewStub
.
Here is an example like yours:
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>
And we've layout_container_1
& layout_container_2
that only differ in the the textview value:
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>
ViewModel:
class ActivityViewModel : ViewModel() {
var isOk = true
}
Then decide which layout in the activity based on the model.isOk
whenever you inflate the 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()
}
}
}
Preview:
