Search code examples
androidkotlindata-bindingandroid-alertdialogandroid-databinding

How to use Databinding in MaterialAlertDialog?


I would like to use databinding in my MaterialAlertDialog in order to change the text while my dialog is showing, but there are literally zero tutorials covering this. Does somebody has any idea doing this?

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

Dialog Builder

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

Fragment (what I want)

// 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()
            }
        }
    }
}

Dialog Picture

enter image description here


Solution

  • Okay, I've managed to find a solution, without creating a dialogFragment. In fact, it IS possible to use databinding in a Alertdialog with ease. I am not 100% if my implementation of the lifecycleowner is correct, tho.

    Implementation

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

    Calling Side

    // fragment
    val dialog = CustomDialog(requireContext(), viewLifecyleOwner)
    
    dialog.show()
    dialog.onChangeUserId("New Id")
    dialog.OnChangeLoginOperation("New Operation")