How can I set a ConstraintLayout Group's visibility via DataBinding?

I have 2 Groups in my layout which control the visibility of my Views.
However, I cannot set their visibility via DataBinding:

<layout>
    <data>
        <import type="android.view.View"/>
        
        <variable
            name="viewModel"
            type="co.aresid.book13.fragments.trackinglist.TrackingListViewModel"
            />
    </data>
    <androidx.constraintlayout.widget.ConstraintLayout>

        ...

        <androidx.constraintlayout.widget.Group
            android:id="@+id/content_group"
            android:layout_width="0dp"
            android:layout_height="0dp"
            android:visibility="@{viewModel.hideLoadingAndShowContent ? View.VISIBLE : View.GONE, default=gone}"
            app:constraint_referenced_ids="tracking_list_recycler_view"
            />
        
        <androidx.constraintlayout.widget.Group
            android:id="@+id/loading_group"
            android:layout_width="0dp"
            android:layout_height="0dp"
            android:visibility="@{viewModel.hideLoadingAndShowContent ? View.GONE : View.VISIBLE, default=visible}"
            app:constraint_referenced_ids="progress_circular"
            />
    </androidx.constraintlayout.widget.ConstraintLayout>
</layout>

The hideLoadingAndShowContent variable is a LiveData which gets its value from a corresponding MutableLiveData in my ViewModel:

private val _hideLoadingAndShowContent = MutableLiveData<Boolean>()
val hideLoadingAndShowContent: LiveData<Boolean>
    get() = _hideLoadingAndShowContent

This LiveData is only set in the ViewModel and does not occur in the Fragment class.
In the Fragment class, I have also set the binding.lifecycleOwner:

binding.lifecycleOwner = viewLifecycleOwner

What detail am I missing out?

Upvotes: 0

Views: 897

Answers (2)

I forgot to pass the ViewModel to the layout binding in my Fragment class:

binding.viewModel = viewModel

Upvotes: 1

rahat
rahat

Reputation: 2056

Because that android:visibility does not support binding variable observation,

You can create BindingAdapter this way

@BindingAdapter("mutableVisibility")
fun setMutableVisibility(view: View, visibility: MutableLiveData<Boolean>) {
    val owner = (view.getParentActivity() ?: view.context) as LifecycleOwner
    if (owner != null) {
        visibility.observe(
            owner,
            Observer { value ->
                  view.visibility = if(value) View.VISIBLE else View.GONE
            })
    }
}

Utility function for getting activity from view.

fun View.getParentActivity(): AppCompatActivity?{
    var context = this.context
    while (context is ContextWrapper) {
        if (context is AppCompatActivity) {
            return context
        }
        context = context.baseContext
    }
    return null
}

Then in your XML you can do it like

 <androidx.constraintlayout.widget.Group
            android:id="@+id/content_group"
            android:layout_width="0dp"
            android:layout_height="0dp"
            android:visibility="@{viewModel.hideLoadingAndShowContent}"
            app:constraint_referenced_ids="tracking_list_recycler_view"
            />

Upvotes: 0

Related Questions