0

I would like to enable or disable the OK (POSITIVE) button of the AlertDialog with a custom layout such that I can:

  • Disable the OK button initially
  • Enable the OK button when all required fields have been entered
  • Disable the OK button again if a required field has been cleared
  • Perform validation after the OK button is selected and prevent dismissal upon validation errors

Assume the AlertDialog layout is as follows with one required field description and one optional field age:

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    xmlns:app="http://schemas.android.com/apk/res-auto">

    <EditText
        android:id="@+id/description"
        android:hint="Field is required"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintTop_toTopOf="parent"
        app:layout_constraintRight_toRightOf="parent"
        app:layout_constraintBottom_toTopOf="@id/age" />

    <EditText
        android:id="@+id/age"
        android:hint="Optional"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintTop_toBottomOf="@id/description"
        app:layout_constraintRight_toRightOf="parent"
        app:layout_constraintBottom_toBottomOf="parent" />


</androidx.constraintlayout.widget.ConstraintLayout>

Assume I have a button to kick off the dialog

Button b = findViewById(R.id.main_button);
b.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View view) {
            Log.e(TAG,"button");

            View viewcustom = getLayoutInflater().inflate(R.layout.customdialog,null);
            EditText edt1 = viewcustom.findViewById(R.id.description);
            EditText edt2 = viewcustom.findViewById(R.id.age);
            
            // render alertdialog
        }
});
Computable
  • 976
  • 2
  • 4
  • 16

1 Answers1

1

Here is the code. I created a custom layout with 2 EditText fields and require only 1 to be entered. The first is treated as just text that must be present and the second is treated as an optional Age. The final example shows how to add validation and to "not dismiss" after OK is pressed and validation fails.

The OK button is initially disabled and when data is entered in the first text field the OK button is enabled.

By controlling the enable/disable of the positive (OK) button it requires the user to the enter fields necessary (rather than giving them an error when omitted).

Note that when the user clears the same field the OK button is disabled.

You can also add a hint to the EditText field(s) to indicate required (shown in second example).

Note that this was used as reference for the EditText listening (as I linked to in comment).

Finally, the last demo shows if you really wanted to show an error on field validation after the OK button is enabled and pressed. (From here.)

This should be obvious how to expand it to all your EditText fields. And bear in mind you can an condition to enabling the OK button - here it is just at least one character.

Button b = findViewById(R.id.main_button);
b.setOnClickListener(new View.OnClickListener() {
    @Override
    public void onClick(View view) {
        Log.e(TAG,"button");

        View viewcustom = getLayoutInflater().inflate(R.layout.customdialog,null);
        EditText edt1 = viewcustom.findViewById(R.id.description);
        EditText edt2 = viewcustom.findViewById(R.id.age);


        final AlertDialog.Builder alertDialog = new AlertDialog.Builder(MainActivity.this)
                .setView(viewcustom)
                .setPositiveButton("Ok", (dialogInterface, i) -> {
                    String d = edt1.getText().toString();
                    String a = edt2.getText().toString();

                    Toast.makeText(MainActivity.this,d, Toast.LENGTH_LONG).show();
                });
        alertDialog.setNegativeButton("Cancel", null);
        AlertDialog ad = alertDialog.create();

        edt1.addTextChangedListener(new TextWatcher() {
            @Override
            public void beforeTextChanged(CharSequence sequence, int i, int i1, int i2) {}
            @Override
            public void onTextChanged(CharSequence sequence, int i, int i1, int i2) {}
            @Override
            public void afterTextChanged(Editable editable) {
                if (edt1.getText().length() > 0) {
                    // if user enters anything then enable - modify criteria as desired
                    ad.getButton(DialogInterface.BUTTON_POSITIVE).setEnabled(true);
                } else {
                    // if user deletes entry then back to disabled
                    ad.getButton(DialogInterface.BUTTON_POSITIVE).setEnabled(false);
                }
            }
        });


        // Initially OK button is disabled.
        ad.show();
        ad.getButton(DialogInterface.BUTTON_POSITIVE).setEnabled(false);


    }
});

And demo:

enter image description here

You can also add a hint to each field to indicate it is required if nothing is entered as in :

<EditText
    android:id="@+id/description"
    android:hint="Field is required"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    app:layout_constraintLeft_toLeftOf="parent"
    app:layout_constraintTop_toTopOf="parent"
    app:layout_constraintRight_toRightOf="parent"
    app:layout_constraintBottom_toTopOf="@id/age" />

enter image description here

Finally, if you really, really want to allow the OK but then do further validation to display errors then add the following. Note that the second field is treated as an Age field and the data entered must be an integer. A bit contrived but used to show an example.

// add this after the AlertDialog create()

ad.setOnShowListener(new DialogInterface.OnShowListener() {
    @Override
    public void onShow(DialogInterface anInterface) {
        Button b = ad.getButton(DialogInterface.BUTTON_POSITIVE);
        b.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                // do some validation on edit text
                String s = edt2.getText().toString();
                try {
                    Integer age = Integer.valueOf(s);
                    Toast.makeText(MainActivity.this,d+":"+age, Toast.LENGTH_LONG).show();
                    ad.dismiss();
                } catch (Exception e) {
                    // complain
                    Toast.makeText(MainActivity.this, "Age must be an integer", Toast.LENGTH_LONG).show();
                }
            }
        });
    }
});

And demo of requiring the optional Age to be an integer:

enter image description here

Computable
  • 976
  • 2
  • 4
  • 16