12

I am learning data binding and mvvm. I have an issue where I would like a BaseViewModel.kt to include some UI related variables such as an isLoading flag and loadingText. When a network request is made, I set isLoading to true and some child of my base view model should set the text. For example for a LoginViewModel.kt the text might be 'logging in'. Is it possible to pass these variables to an included base layout?

So a login_activity.xml might include this in it's layout:

    <data>
        <import type="android.view.View" />
        <variable
            name="viewModel"
            type="core.sdk.ui.login.LoginViewModel" />
    </data>

<!-- Various click listeners using the viewModel variable -->

    <include
        android:id="@+id/progress_include"
        layout="@layout/progress_bar"
        android:visibility="@{viewModel.isLoading ? View.VISIBLE : View.GONE}"
        bind:viewModel="@{viewModel}"/>

Now I want my progress_bar.xml to be nice and generic and use the base view model:

<layout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
tools:context="core.sdk.ui.login.LoginActivity">

<data>

    <import type="android.view.View" />

    <variable
        name="viewModel"
        type="core.sdk.ui.base.BaseViewModel" />

</data>

<LinearLayout
    android:id="@+id/circular_progress"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:layout_gravity="center"
    android:gravity="center"
    android:orientation="vertical">

    <android.support.v4.widget.ContentLoadingProgressBar
        style="@style/Widget.AppCompat.ProgressBar"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content" />

    <TextView
        android:id="@+id/progress_text"
        style="@style/TextAppearance.AppCompat.Subhead"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:fontFamily="sans-serif-thin"
        android:gravity="center_horizontal"
        android:text="@{viewModel.loadingText}"
        android:textStyle="italic"
        tools:text="loading..." />
</LinearLayout>

The error I get is something like

****/ data binding error ****msg:Cannot find the setter for attribute 'bind:viewModel' with parameter type core.sdk.ui.login.LoginViewModel

If this isn't possible the only alternative I can see is to remove the include and copy and paste the progress bar + text to every view model which isn't very nice.

0

3 Answers 3

11

I think you should cast it in the binding:

<include
    android:id="@+id/progress_include"
    layout="@layout/progress_bar"
    android:visibility="@{viewModel.isLoading ? View.VISIBLE : View.GONE}"
    bind:viewModel="@{(core.sdk.ui.base.BaseViewModel)viewModel}"/>
Sign up to request clarification or add additional context in comments.

1 Comment

Thanks I could have sworn I tried that and it didn't like it :)
5

for those who still don't have solution, just check your code and check whether the name of "bind" attribute is same as the one used in the included layout

<include
       ...
        bind:viewModel="@{viewModel}"/>

and

<data>
    ...
    <variable
        name="viewModel"
        type="core.sdk.ui.base.BaseViewModel" />

</data>

Comments

3

You can use binding with include like

loading_view.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>

        <import type="android.view.View"/>

        <variable
            name="visibility"
            type="boolean"
            />

        <variable
            name="text"
            type="String"
            />
    </data>

    <LinearLayout
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:background="#ff0"
        android:gravity="center_horizontal"
        android:orientation="vertical"
        android:visibility="@{visibility?View.VISIBLE:View.GONE}"
        >
        <ProgressBar
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            />
        <TextView
            android:layout_width="wrap_content"
            android:layout_height="match_parent"
            android:text="@{text}"
            tools:text="AA"
            />
    </LinearLayout>
</layout>

Using

<include
        layout="@layout/loading_view"
        app:visibility="@{viewModel.loadingCondition}"
        app:text='@{"AA"}'
        />

you can also pass the hard value like

app:visibility="@{false}"
app:text="@{@string/loading_text}"

4 Comments

I wish I could mark this as the answer as well it's very useful thank you!
I've done this but the text is just an empty string (doesn't display), not any value, no matter what I put there. I've left off the visibility part, so I know it's not that. Help?
@Elliptica, default of visibility is false, if you want to show, you need to change it to true
In your example, yes, but in mine default is true. I don't set visibility to false. What's more, I've put a background on my TextView so I can see the view is rendering, it's just empty (no text).

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.