Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

DataBinding: Adjust visibility by LiveData Variable on Click

I want to adjust the visibility of a ProgressBar depending on a MutableLiveData variable in my ViewModel. I learned that MutableLiveData does not work, so I need a LiveData variable to transform it... Kind of strange, but well at least it should work right?

Well it does not work at the moment. And I don't get why I want two variables to do one thing.

I hope the code speaks for itself:

Activity:

override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    val binding: ActivityLoginBinding = DataBindingUtil.setContentView(this, R.layout.activity_login)
    binding.lifecycleOwner = this
    binding.viewmodel = vm
}

View Model:

class LoginViewModel : ViewModel() {
    var isLoading: MutableLiveData<Boolean> = MutableLiveData(false)
    var showLoadingIndicator: LiveData<Boolean> = Transformations.map(isLoading) { isLoading.value }

    fun login() {
        Timber.d("login")
        isLoading.value = true
    }
}

Layout:

<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:app="http://schemas.android.com/apk/res-auto">
    <data>
        <variable
                name="viewmodel"
                type="mypackage.LoginViewModel"/>
    </data>

    <androidx.constraintlayout.widget.ConstraintLayout>

        <com.google.android.material.button.MaterialButton        
                android:onClick="@{() -> viewmodel.login()}"/>

        <include
                layout="@layout/loading_indicator"
                app:goneUnless="@{viewmodel.showLoadingIndicator}"/>
    </androidx.constraintlayout.widget.ConstraintLayout>
</layout>

BindingAdapter:

@Suppress("unused")
object BindingAdapters {
    @BindingAdapter("goneUnless")
    @JvmStatic
    fun goneUnless(view: View, visible: Boolean) {
        view.visibility = if (visible) View.VISIBLE else View.GONE
    }
}

When I click the Button the Timber call works, but the visibility of the loading indicator does not change (from GONE to VISIBLE). How can I fix this and maybe get rid of the two variables and have only one?

Thanks.

like image 229
chrjs Avatar asked Jan 25 '19 12:01

chrjs


1 Answers

You don't actually need a BindingAdapter, there's a simpler way to accomplish what you want.

1) ViewModel: change your loading field to: val isLoading = ObservableBoolean() OR val isLoading = MutableLiveData<Boolean>*

2) Add the import inside the <data> tag of your layout: <import type="android.view.View"/>

3) Your include will become:

<include
   layout="@layout/loading_indicator"
   android:visibility="@{viewmodel.isLoading ? View.VISIBLE : View.GONE}"/>

Use set(value) to change the value of the ObservableBoolean or setValue() (postValue() if you are off the main thread) for LiveData.

*it is considered a good practice to expose a LiveData instance and keep the actual MutableLiveData private.

like image 135
Droidman Avatar answered Nov 03 '22 11:11

Droidman