Search code examples
androidandroid-layoutandroid-recyclerviewandroid-databinding

Data binding: how to bind different data variables in one view


I'm using MVVM design pattern and so the native data binding.

Is it possible to use multiple data variable for one view in data binding?

I mean that I have one xml layout that use data binding and I want to use it for multiple recyclerview items.

It's the first data model class for one recyclerview items:

data class Sample1 (
    val name: String,
    val id: Int
)

And this is the second one for another recyclerview items:

data class Sample2 (
    val name: String,
    val type: String
)

And it's the xml code that use in both recyclerview:

<layout>

<data class="SampleDataBinding">

    <variable
        name="Sample1"
        type="model.Sample1" />

    <variable
        name="Sample2"
        type="model.Sample2" />

</data>

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:gravity="center_vertical"
    android:orientation="horizontal"
    android:padding="8dp">

    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:paddingStart="8dp"
        android:paddingEnd="8dp"
        android:text="@{Sample1.component1()}" // this line may be different in another recyclerview item
        android:textColor="@color/black" />

</LinearLayout>

I don't mean the concatation two Strings. I mean that the TextView may be different in first recyclerview items and second one.

If it's possible how I can do it?

Thanks in advance


Solution

  • You can achieve it using an interface and your XML/data-binding will work with that interface. For instance, you need a title in that xml and you can create an interface (SampleRecyclerItem) and its implementers have to provide a title: String.

    interface SampleRecyclerItem{
        val title: String
    }
    
    data class Sample1 (
        val name: String,
        val id: Int
    ) : SampleRecyclerItem {
        override val title get() = name // either using a getter
    }
    
    
    data class Sample2 (
        val name: String,
        val type: String
    ) : SampleRecyclerItem {
        override val title by this::name // or using delegation (easier for vars for not providing setter and getter)
    }
    
    

    and then, your XML can use this interface instead of the data classes directly

    <layout>
    
    <data class="SampleDataBinding">
    
        <variable
            name="sample"
            type="model.SampleRecyclerItem" />
    
    </data>
    
    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:gravity="center_vertical"
        android:orientation="horizontal"
        android:padding="8dp">
    
        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:paddingStart="8dp"
            android:paddingEnd="8dp"
            android:text="@{sample.title}"
            android:textColor="@color/black" />
    
    </LinearLayout>