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.
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With