How to include an Android layout but also access its elements in binding?

Viewed 484

I'm doind this on my activity:

       <include
        android:id="@+id/withGyroLayout"
        layout="@layout/with_gyro_layout"/>

Where with_gyro_layout.xml is

<androidx.constraintlayout.widget.ConstraintLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <com.example.util.FixedTransformerViewPager
        android:id="@+id/viewPagerTop"
        android:layout_width="0dp"
        android:layout_height="143dp"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintTop_toTopOf="parent" />

    <com.example.util.FixedTransformerViewPager
        android:id="@+id/viewPagerBottom"
        android:layout_width="0dp"
        android:layout_height="143dp"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintTop_toBottomOf="@+id/viewPagerTop" />
</androidx.constraintlayout.widget.ConstraintLayout>

However, I can't access the elements viewPagerBottom or viewPagerTop from the binding for my activity:

binding.viewPagerBottom.setVisibility(View.VISIBLE);
binding.viewPagerTop.setVisibility(View.VISIBLE);

I tried putting with_gyro_layout.xml around <merge>...</merge> but it also didn't solve.

I want to be able to change programatically between with_gyro_layout.xml and without_gyro_layout.xml and also access its inner elements by the binding. How can I do that?

1 Answers

Two things are required in order to use ViewBinding with an included layout.

<merge> is not supported

The documentation only covers Data Binding, and not View Binding, but it does appear to be applicable to both. See https://developer.android.com/topic/libraries/data-binding/expressions#includes

Data binding doesn't support include as a direct child of a merge element.

In other words, the layout must have a real, concrete view as its root element. The following is supported:

<LinearLayout ...>
    <TextView ... />
    <TextView ... />
</LinearLayout>

But a layout with a <merge> root is not supported:

<merge ...>
    <TextView ... />
    <TextView ... />
</merge>

The <include> tag must specify an ID

It is, in general, possible to include a layout without explicitly specifying an ID. View Binding does not support this:

<include layout="@layout/included_layout"/>

Even if the included layout has an ID on its root element, it is still not supported. Instead, you must explicitly specify the ID on the <include> tag:

<include
    android:id="@+id/some_id"
    layout="@layout/included_layout"/>

Once both of these conditions are satisfied, your generated binding for the outer layout will include a reference to the binding of the included layout. Let's say our two files are outer_layout.xml and included_layout.xml. Then these two files would be generated:

  • OuterLayoutBinding.java
  • IncludedLayoutBinding.java

And you could reference the included views like this:

val outerBinding = OuterLayoutBinding.inflate(layoutInflater)
val innerBinding = binding.someId // uses the id specified on the include tag
val innerView = innerBinding.viewPagerTop

Or, for short:

val binding = OuterLayoutBinding.inflate(layoutInflater)
val innerView = binding.someId.viewPagerTop
Related