How to prevent AlertDialog from being closed when any button is clicked?

4

Problem

I'm trying to validate certain data contained in a% custom View in the event of clicking the Save button. So after the validation I save the data and close the AlertDialog, and in case the data is not valid I would show the errors to be corrected. But even if I do not call the method AlertDialog the dialog.dismiss(); in question is closed.

Question

  

How could I intercept and prevent automatic closing of AlertDialog by clicking any of its buttons?

Implementation Attempt

What I'm implementing that is not working is as follows:

AlertDialog dialog = new AlertDialog.Builder(getActivity()).create();
dialog.setTitle("Preencha o formulário:");
dialog.setCancelable(true);
View view = LayoutInflater.from(getContext()).inflate(R.layout.layout_dialog_forms, null);
dialog.setView(view);
dialog.setButton(DialogInterface.BUTTON_POSITIVE, getString(R.string.btn_save), new DialogInterface.OnClickListener() {
    @Override
    public void onClick(DialogInterface dialog, int which) {
        if(validForm()){
            save();
            dialog.dismiss();
        } else {
            exibirErrosFormulario();
            // ... como não chamo "dialog.dismiss();" não era para fechar o AlertDialog, mas está fechando.
        }
    }
});
dialog.setButton(DialogInterface.BUTTON_NEGATIVE, getString(R.string.btn_cancel), new DialogInterface.OnClickListener() {
    @Override
    public void onClick(DialogInterface dialog, int which) {
        dialog.dismiss();
    }
});
    
asked by anonymous 08.05.2015 / 22:49

1 answer

2

I use an artifice that I found I can no longer remember where.

Begin by defining a class that will treat the event onClick of the dialog button:

public abstract class DialogButtonClickWrapper implements OnClickListener{

    private AlertDialog dialog;

    public DialogButtonClickWrapper(AlertDialog dialog) {
        this.dialog = dialog;
    }

    @Override
    public void onClick(View v) {

        if(onClicked()){
            dialog.dismiss();
        }
    }

    protected abstract boolean onClicked();
}

Declare the button as usual, but do not enter any code in onClick() :

dialog.setButton(DialogInterface.BUTTON_POSITIVE, getString(R.string.btn_save), new DialogInterface.OnClickListener() {
    @Override
    public void onClick(DialogInterface dialog, int which) {

    }
});

In the line where you have dialog.show() enter the following code:

//É necessário porque os botões só são atribuídos após o método 'show' ser chamado
dialog.show();

Button theButton = dialog.getButton(DialogInterface.BUTTON_POSITIVE);
theButton.setOnClickListener(new DialogButtonClickWrapper(dialog) {

    @Override
    protected boolean onClicked() {

        if(validForm()){
            save();
            return true;//Retornando true fecha o dialog
        } else {
            exibirErrosFormulario();
            return false;//Retornando false o dialog não é fechado
        }
    }
});

The DialogButtonClickWrapper class has only the minimum required for this situation. From it you can improve it to, for example, be it to validate the form and then call the onClicked method.

In this case the class would have a private boolean isValid() method that will return true or false depending on the validity of the form data. The onClick method would look like this:

@Override
public void onClick(View v) {

    if(isValid()){
        if(onClicked()){
            dialog.dismiss();
        }
    }
}

The implementation of the onClicked method will have the code corresponding to the button action, it should return true if all goes well or false if something wrong happens.

    
09.05.2015 / 01:35