如何通过 DataBinding 设置 ConstraintLayout 组的可见性?

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

我的布局中有 2 个 Group 用于控制视图的可见性。
但是,我无法通过 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>

hideLoadingAndShowContent 变量是一个 LiveData,它从我的 ViewModel:

中相应的 MutableLiveData 获取值
private val _hideLoadingAndShowContent = MutableLiveData<Boolean>()
val hideLoadingAndShowContent: LiveData<Boolean>
    get() = _hideLoadingAndShowContent

这个LiveData只在ViewModel中设置,不会出现在Fragment中 class.
Fragment class 中,我还设置了 binding.lifecycleOwner:

binding.lifecycleOwner = viewLifecycleOwner

我错过了什么细节?

因为android:visibility不支持绑定变量观察,

您可以通过这种方式创建 BindingAdapter

@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
            })
    }
}

从视图中获取 activity 的实用函数。

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

然后在你的XML中你可以这样做

 <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"
            />

我忘记将 ViewModel 传递给 Fragment 中的布局绑定 class:

binding.viewModel = viewModel