29

The subject kinda says it all.. I'm requesting a PIN code from the user, if they enter it, click the OK Positive Button and the PIN is incorrect I want to display a Toast but keep the dialog open. At the moment it closes automatically.. Sure this is very trivial thing to correct but can't find the answer yet.

Thanks..

David Brown
  • 3,021
  • 3
  • 26
  • 46
  • I'm currently just recalling my function to create and display a dialog but it feels like a waste of resource when I just need to inform the dialog not to dismiss itself... – David Brown Oct 25 '10 at 16:11
  • 2
    duplicate of http://stackoverflow.com/questions/2620444/how-to-prevent-a-dialog-from-closing-when-a-button-is-clicked/9523257 – ccpizza Dec 29 '12 at 13:43

6 Answers6

43

You do not need to create a custom class. You can register a View.OnClickListener for the AlertDialog. This listener will not dismiss the AlertDialog. The trick here is that you need to register the listener after the dialog has been shown, but it can neatly be done inside an OnShowListener. You can use an accessory boolean variable to check if this has already been done so that it will only be done once:

    /*
     * Prepare the alert with a Builder.
     */
    AlertDialog.Builder b = new AlertDialog.Builder(this);

    b.setNegativeButton("Button", new DialogInterface.OnClickListener() {
        @Override
        public void onClick(DialogInterface dialog, int which) {}
    });
    this.alert = b.create();

    /*
     * Add an OnShowListener to change the OnClickListener on the
     * first time the alert is shown. Calling getButton() before
     * the alert is shown will return null. Then use a regular
     * View.OnClickListener for the button, which will not 
     * dismiss the AlertDialog after it has been called.
     */

    this.alertReady = false;
    alert.setOnShowListener(new DialogInterface.OnShowListener() {
        @Override
        public void onShow(DialogInterface dialog) {
            if (alertReady == false) {
                Button button = alert.getButton(DialogInterface.BUTTON_NEGATIVE);
                button.setOnClickListener(new View.OnClickListener() {
                    @Override
                    public void onClick(View v) {
                        //do something
                    }
                });
                alertReady = true;
            }
        }
    });

Part of this solution was provided by http://groups.google.com/group/android-developers/browse_thread/thread/fb56c8721b850124#

howettl
  • 12,419
  • 13
  • 56
  • 91
zenperttu
  • 764
  • 1
  • 7
  • 13
  • 1
    Unfortunately, setOnShowListener is only available in API Level 8 and later. To support API 7, I'm following the approach provided in the page you linked to: pass a no-op listener to setNegativeButton, call show(), then get a reference to the button and call setOnClickListener() with the full listener. – Travis Feb 05 '12 at 04:57
  • +1 for nice and helpful answer, This solution works for me. – rajpara Oct 03 '12 at 06:19
  • Nice work. Just one error in the code: `alertAndHelp` should be `alert`. Also, it's not entirely clear to me why you need the `alertReady` flag, is it just to avoid running the code again when the same alertdialog is show again? – Matthias Aug 12 '15 at 12:19
  • Thanks for pointing the variable name mistake out! (That's fixed now.) The alertReady flag is there just to make explicit that it's not necessary to run the code inside button.setOnClickListener every time the dialog is shown, in case somebody ends up doing something laborous in there. :) – zenperttu Sep 14 '15 at 19:53
  • In my case worked but I had to add a new line of code: `button.setVisibility(View.VISIBLE);` The button wasn't showing on the AlertDialog. Thanks for this tip – alexscmar Sep 30 '16 at 11:03
13

Build a custom dialog with a EditText with the attribute android:password="true" a button, then manually set onClick listener the button, and explicitly choose what to do in it.

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout 
    xmlns:android="http://schemas.android.com/apk/res/android" 
    android:layout_width="wrap_content" 
    android:layout_height="wrap_content" 
    android:orientation="vertical">

    <EditText 
        android:layout_width="fill_parent" 
        android:layout_height="wrap_content" 
        android:minWidth="180dip" 
        android:digits="1234567890" 
        android:maxLength="4" 
        android:password="true"/>

    <LinearLayout 
        android:layout_width="fill_parent" 
        android:layout_height="wrap_content" 
        android:orientation="horizontal">

        <Button 
            android:id="@+id/Accept" 
            android:layout_width="fill_parent" 
            android:layout_height="wrap_content" 
            android:text="Accept"/>

    </LinearLayout> 
</LinearLayout> 

Then when you want it to pop up:

final Dialog dialog = new Dialog(RealizarPago.this);
dialog.setContentView(R.layout.custom_dialog);
dialog.setTitle("PIN number:");
dialog.setCancelable(true);

Button button = (Button) dialog.findViewById(R.id.Accept);
button.setOnClickListener(new OnClickListener() {
@Override
    public void onClick(View v) {
        if(password_wrong){ 
          // showToast
        } else{
          dialog.dismiss();
          // other stuff to do
        }
    }
}); 

dialog.show();  
Mustafa Berkay Mutlu
  • 1,929
  • 1
  • 25
  • 37
blindstuff
  • 18,298
  • 10
  • 47
  • 48
  • Thanks, so dialogs, unless you specify a custom layout will automatically close in an onclick? – David Brown Oct 25 '10 at 17:20
  • I do belive so, i might be mistaken, but I found it easier to do a custom dialog instead of trying to get another one to work and I had total control over what it looks like and how it behaves. Plz mark the answer as accepted if it works for you. – blindstuff Oct 25 '10 at 17:26
5

You can set an OnClickListener as follows to keep the dialog open:

public class MyDialog extends AlertDialog {
    public MyDialog(Context context) {
        super(context);
        setMessage("Hello");
        setButton(AlertDialog.BUTTON_POSITIVE, "Ok", (new DialogInterface.OnClickListener() {
            @Override
            public void onClick(DialogInterface dialog, int which) {
                // this will never be called
            }
        });
    }

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        getButton(AlertDialog.BUTTON_POSITIVE).setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                if (ok) {
                    // do something
                    dismiss();
                } else {
                    Toast.makeText(getContext(), "when you see this message, the dialog should stay open", Toast.LENGTH_SHORT).show();
                }
            }
        });
    }
}
josias
  • 586
  • 4
  • 9
1

You can just continue using the dialog you already have, just put an if clause in the onClick() saying

if(pin_check_method){  //pin_check_method should be a boolean returned method
     //close the Dialog, then continue
     }
   else{
     //dont put the dialog.dismiss() in here, put instead
    Toast.makeText(getApplicationContext(),"Invalid pin, please try again",Toast.LENGTH_LONG).show();
}

Now, to use this code, simply invoke text.setText(""); and put in the text you want here common error is that when you type in:

TextView text = (TextView) findViewById(R.id.dialog);

you miss that it needs to actually be

dialog.findViewById

and this is regardless of what the name of the dialog is, in my example it just happens to be the same name.

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
                android:id="@+id/layout_root" 
                android:layout_width="fill_parent" 
                android:layout_height="fill_parent" 
                >

    <TextView android:id="@+id/text"
              android:layout_height="wrap_content"
              android:textColor="#FFF"
              android:layout_centerHorizontal="true"
              android:layout_width="wrap_content"/>



    <Button android:text="Continue" 
            android:id="@+id/Button01" 
            android:layout_width="fill_parent" 
            android:layout_height="wrap_content" android:layout_below="@+id/text">
             </Button>

</RelativeLayout>
Samuel
  • 4,337
  • 3
  • 29
  • 35
  • This is what I was doing however the dialog automatically closes even without the dismiss() call. – David Brown Oct 25 '10 at 17:19
  • Okay, after looking into it, it looks like custom dialog is going to be your best bet.. I'll edit my answer to one that you'll find useful. I'm actually using it in my application. dont forget to mark as accepted if you use my answer :) – Samuel Oct 26 '10 at 03:52
1

Try this:

final AlertDialog alertDialog = new AlertDialog.Builder(context)
        .setView(v)
        .setTitle(R.string.my_title)
        .setPositiveButton(android.R.string.ok, null) //Set to null. We override the onclick
        .setNegativeButton(android.R.string.cancel, null)
        .create();

alertDialog.setOnShowListener(new DialogInterface.OnShowListener() {

    @Override
    public void onShow(DialogInterface dialog) {

        Button b = alertDialog.getButton(AlertDialog.BUTTON_POSITIVE);
        b.setOnClickListener(new View.OnClickListener() {

            @Override
            public void onClick(View view) {
                // TODO Do something

            }
        });
    }
});
alertDialog.show();

Source: Prevent Alertdialog from closing after button click


Hope This Helps! Good Luck!

Shreshth Kharbanda
  • 1,777
  • 14
  • 24
0

Same problem for me in a FragmentDialog. Here's my criminal/elegant solution: Remove all buttons from the dialog (positive,negative,neutral). Add your buttons from the xml.eg.:

<LinearLayout
        android:layout_width="match_parent"
        android:orientation="horizontal"
        android:layout_height="wrap_content">
        <Button
            android:layout_width="0dp"
            android:layout_weight="1"
            android:layout_height="wrap_content"
            android:id="@+id/button_cancel"
            style="@style/Widget.AppCompat.Button.Borderless.Colored"
            android:text="@android:string/cancel"
            android:layout_gravity="left"
            />
        <Button
            android:layout_width="0dp"
            android:layout_weight="1"
            android:layout_height="wrap_content"
            android:id="@+id/button_ok"
            style="@style/Widget.AppCompat.Button.Borderless.Colored"
            android:text="@android:string/ok"
            android:layout_gravity="right"
            />
    </LinearLayout>

And then in your code handle it with:

view.findViewById(R.id.button_ok).setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View view2) {
                    if (wannaClose)
                        dismiss();
                    else
                        //do stuff without closing!
                }
            });

where view is the view assigned to the dialog!

GabrieleG
  • 107
  • 1
  • 7