android kotlin - AlertDialog EditText programmatically

MainActivity.kt

package com.cfsuman.kotlintutorials

import android.app.Activity
import android.content.Context
import android.os.Bundle
import android.text.Editable
import android.text.TextWatcher
import android.util.TypedValue
import android.view.View
import android.widget.*
import androidx.appcompat.app.AlertDialog
import androidx.constraintlayout.widget.ConstraintLayout
import androidx.constraintlayout.widget.ConstraintSet
import com.google.android.material.dialog.MaterialAlertDialogBuilder
import com.google.android.material.textfield.TextInputEditText
import com.google.android.material.textfield.TextInputLayout


class MainActivity : Activity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        val context:MainActivity = this

        // get the widgets reference from XML layout
        val button = findViewById<Button>(R.id.button)
        val textView = findViewById<TextView>(R.id.textView)


        button.setOnClickListener {
            val builder = MaterialAlertDialogBuilder(context)

            // dialog title
            builder.setTitle("Tell us your name.")

            // dialog message view
            val constraintLayout = getEditTextLayout(context)
            builder.setView(constraintLayout)

            val textInputLayout = constraintLayout.
            findViewWithTag<TextInputLayout>("textInputLayoutTag")
            val textInputEditText = constraintLayout.
            findViewWithTag<TextInputEditText>("textInputEditTextTag")

            // alert dialog positive button
            builder.setPositiveButton("Submit"){dialog,which->
                val name = textInputEditText.text
                textView.text = "Hello, $name"
            }

            // alert dialog other buttons
            builder.setNegativeButton("No",null)
            builder.setNeutralButton("Cancel",null)

            // set dialog non cancelable
            builder.setCancelable(false)

            // finally, create the alert dialog and show it
            val dialog = builder.create()

            dialog.show()

            // initially disable the positive button
            dialog.getButton(AlertDialog.BUTTON_POSITIVE).isEnabled = false

            // edit text text change listener
            textInputEditText.addTextChangedListener(object : TextWatcher {
                override fun afterTextChanged(p0: Editable?) {
                }

                override fun beforeTextChanged(p0: CharSequence?, p1: Int,
                                               p2: Int, p3: Int) {
                }

                override fun onTextChanged(p0: CharSequence?, p1: Int,
                                           p2: Int, p3: Int) {
                    if (p0.isNullOrBlank()){
                        textInputLayout.error = "Name is required."
                        dialog.getButton(AlertDialog.BUTTON_POSITIVE)
                            .isEnabled = false
                    }else{
                        textInputLayout.error = ""
                        dialog.getButton(AlertDialog.BUTTON_POSITIVE)
                            .isEnabled = true
                    }
                }
            })
        }
    }
}



// get edit text layout
fun getEditTextLayout(context:Context): ConstraintLayout {
    val constraintLayout = ConstraintLayout(context)
    val layoutParams = ConstraintLayout.LayoutParams(
        ConstraintLayout.LayoutParams.MATCH_PARENT,
        ConstraintLayout.LayoutParams.WRAP_CONTENT
    )
    constraintLayout.layoutParams = layoutParams
    constraintLayout.id = View.generateViewId()

    val textInputLayout = TextInputLayout(context)
    textInputLayout.boxBackgroundMode =
        TextInputLayout.BOX_BACKGROUND_OUTLINE

    layoutParams.setMargins(
        32.toDp(context),
        8.toDp(context),
        32.toDp(context),
        8.toDp(context)
    )

    textInputLayout.layoutParams = layoutParams
    textInputLayout.hint = "Input name"
    textInputLayout.id = View.generateViewId()
    textInputLayout.tag = "textInputLayoutTag"


    val textInputEditText = TextInputEditText(context)
    textInputEditText.id = View.generateViewId()
    textInputEditText.tag = "textInputEditTextTag"

    textInputLayout.addView(textInputEditText)

    val constraintSet = ConstraintSet()
    constraintSet.clone(constraintLayout)

    constraintLayout.addView(textInputLayout)
    return constraintLayout
}



// extension method to convert values to dp
fun Int.toDp(context: Context):Int = TypedValue.applyDimension(
    TypedValue.COMPLEX_UNIT_DIP,
    this.toFloat(),
    context.resources.displayMetrics
).toInt()
activity_main.xml

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout
    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"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="#DCDCDC"
    android:padding="24dp">

    <Button
        android:id="@+id/button"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Show Dialog"
        android:textAllCaps="false"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent" />

    <TextView
        android:id="@+id/textView"
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:layout_marginTop="24dp"
        android:fontFamily="sans-serif"
        android:textSize="24sp"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toBottomOf="@id/button" />

</androidx.constraintlayout.widget.ConstraintLayout>
build.gradle dependencies[add]

// Material components
implementation 'com.google.android.material:material:1.6.1'
More android examples