如何在 MaterialAlertDialog 中使用数据绑定?

How to use Databinding in MaterialAlertDialog?

我想在我的 MaterialAlertDialog 中使用数据绑定,以便在我的对话框显示时更改文本,但几乎没有关于此的教程。有人知道这样做吗?

对话框布局

<?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"
    xmlns:tools="http://schemas.android.com/tools">
    <data>
        <variable
            name="loginUserId"
            type="String" />
        <variable
            name="loginOperation"
            type="String" />
    </data>


    <androidx.constraintlayout.widget.ConstraintLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent">

        <ProgressBar
            android:id="@+id/progressBar"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_marginStart="24dp"
            android:layout_marginTop="16dp"
            app:layout_constraintStart_toStartOf="parent"
            app:layout_constraintTop_toTopOf="parent"
            tools:visibility="visible" />

        <com.google.android.material.textview.MaterialTextView
            android:id="@+id/materialTextView2"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_marginStart="24dp"
            android:text="Example Verifizierung:"
            android:textSize="@dimen/textDescriptionNormal2"
            app:layout_constraintStart_toEndOf="@+id/progressBar"
            app:layout_constraintTop_toTopOf="@+id/progressBar" />

        <com.google.android.material.textview.MaterialTextView
            android:id="@+id/materialTextView3"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_marginStart="24dp"
            android:text="@{loginUserId}"
            android:textSize="@dimen/textDescriptionNormal2"
            app:layout_constraintStart_toEndOf="@+id/progressBar"
            app:layout_constraintTop_toBottomOf="@+id/materialTextView2" />

        <com.google.android.material.textview.MaterialTextView
            android:id="@+id/materialTextView4"
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:layout_marginStart="24dp"
            android:paddingBottom="@dimen/big16dpMargin"
            android:text="@{loginOperation}"
            android:textSize="@dimen/textDescriptionNormal2"
            app:layout_constraintEnd_toEndOf="@+id/materialTextView3"
            app:layout_constraintStart_toEndOf="@+id/progressBar"
            app:layout_constraintTop_toBottomOf="@+id/materialTextView3" />

    </androidx.constraintlayout.widget.ConstraintLayout>
</layout>

对话生成器

fun Fragment.buildLoginDialog() {
    return MaterialAlertDialogBuilder(requireContext(), R.style.LoginDialogTheme)
        .setTitle(R.string.loading_login_title)
        .setView(R.layout.login_loading_screen)
        .setCancelable(true)
}

片段(我想要的)

// Somewhere in fragment
val dialog = buildLoginDialog()

private fun observerSignInStatus() {
    loginViewModel.signInResult.observe(viewLifecycleOwner) { status ->
        dialog.show()
        when(status) {
            is LoginStateEvent.Loading -> {
                dialog.changeText(status.message)
            }
            is LoginStateEvent.LoggedIn -> {
                dialog.dismiss()
            }
            is LoginStateEvent.Error -> {
                dialog.dismiss()
            }
        }
    }
}

对话框图片

我在这里看到 2 个选项。您可以创建一个继承自 DialogFragment 的 class。 Dialogfragments 对于以对话框方式显示更复杂的布局非常有用,允许您控制和操作您的自定义布局。它们的行为类似于常规 Fragment,这意味着您必须覆盖 onCreateView() & onViewCreated() 才能使用 databinding.

显示您的自定义视图

您再次创建了一个继承自 DialogFragment 的 class,但现在您需要覆盖 onCreateDialog() 以使其使用 onCreateView() & onViewCreated()显示和管理 Fragment 的布局,如下所示:

override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
        return MaterialAlertDialogBuilder(requireContext(), theme).apply {
            dialogView = onCreateView(LayoutInflater.from(requireContext()), null, savedInstanceState)

            dialogView?.let { onViewCreated(it, savedInstanceState) }
            setView(dialogView)
        }.create()
    }

那么你还需要:

override fun getView(): View? { return dialogView   }

好的,我设法找到了解决方案,但没有创建 dialogFragment。事实上,可以轻松地在 Alertdialog 中使用数据绑定。如果我对 lifecycleowner 的实现是正确的,那么我不是 100%。

实施

class CustomDialog(context: Context, private val mLifecycleOwner: LifecycleOwner): AlertDialog(context, R.style.LoginDialogTheme) {
    private var _binding: LoginLoadingScreenBinding? = null
    private val binding: LoginLoadingScreenBinding get() = _binding!!

    override fun onCreate(savedInstanceState: Bundle?) {
        initDialog()
        super.onCreate(savedInstanceState)
    }

    override fun show() {
        _binding = LoginLoadingScreenBinding.inflate(layoutInflater).apply { lifecycleOwner = mLifecycleOwner }
        super.show()
    }

    override fun dismiss() {
        _binding = null
        super.dismiss()
    }

    fun onChangeUserId(mText: String) {
        binding.userId.text = mText
    }

    fun onChangeLoginOperation(mText: String) {
        binding.loginOperation.text = mText
    }

    private fun initDialog() {
        setTitle(R.string.loading_login_title)
        setCancelable(true)
        setView(binding.root)
    }
}

主叫方

// fragment
val dialog = CustomDialog(requireContext(), viewLifecyleOwner)

dialog.show()
dialog.onChangeUserId("New Id")
dialog.OnChangeLoginOperation("New Operation")