Bagaimana mencegah dialog agar tidak ditutup ketika tombol diklik

732

Saya memiliki dialog dengan EditTextuntuk input. Ketika saya mengklik tombol "ya" pada dialog, itu akan memvalidasi input dan kemudian menutup dialog. Namun, jika inputnya salah, saya ingin tetap berada di dialog yang sama. Setiap kali apa pun inputnya, dialog harus ditutup secara otomatis ketika saya mengklik tombol "tidak". Bagaimana saya bisa menonaktifkan ini? Omong-omong, saya telah menggunakan PositiveButton dan NegativeButton untuk tombol pada dialog.

pengguna304881
sumber

Jawaban:

916

EDIT: Ini hanya berfungsi pada API 8+ seperti yang dicatat oleh beberapa komentar.

Ini adalah jawaban yang terlambat, tetapi Anda bisa menambahkan onShowListener ke AlertDialog di mana Anda kemudian dapat menimpa onClickListener tombol.

final AlertDialog dialog = 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();

dialog.setOnShowListener(new DialogInterface.OnShowListener() {

    @Override
    public void onShow(DialogInterface dialogInterface) {

        Button button = ((AlertDialog) dialog).getButton(AlertDialog.BUTTON_POSITIVE);
        button.setOnClickListener(new View.OnClickListener() {

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

                //Dismiss once everything is OK.
                dialog.dismiss();
            }
        });
    }
});
dialog.show();
Tom Bollwitt
sumber
7
Hai, lebih baik terlambat daripada tidak sama sekali, saya mencari tepat itu, terima kasih, +1 :) Ini adalah cara yang elegan untuk menambahkan validasi ke dialog Anda, terutama ketika Anda sudah memiliki kelas pembungkus pembantu untuk menangani peringatan
Guillaume
11
Tidak bekerja AlertDialog.Builder.setOnShowListener tidak ada. developer.android.com/reference/android/app/…
Leandros
4
Dengan API pre 8, Anda dapat menghubungi d.getButton (AlertDialog.BUTTON_POSITIVE); karena ini adalah metode publik, tetapi Anda harus menyebutnya show (); telah dikeluarkan, jika tidak, Anda hanya akan mendapatkan nol darinya
Hurda
13
Anda dapat menjadikan ini lebih bersih dengan menetapkan OnClickListener nol ke pembuat dialog (menyimpan pendengar kosong "// ini akan diganti").
Steve Haley
1
Bekerja juga baik dengan DialogFragments ketika AlertDialog dibuat dalam metode onCreateDialog (Bundle SavedInstanceState).
Christian Lischnig
655

Berikut adalah beberapa solusi untuk semua jenis dialog termasuk solusi untuk AlertDialog.Builder yang akan bekerja pada semua level API (bekerja di bawah API 8, yang jawaban lain di sini tidak). Ada solusi untuk AlertDialogs menggunakan AlertDialog.Builder, DialogFragment, dan DialogPreference.

Di bawah ini adalah contoh kode yang menunjukkan cara mengganti penangan tombol umum yang umum dan mencegah dialog menutup untuk bentuk dialog yang berbeda ini. Semua contoh menunjukkan bagaimana mencegah tombol positif menutup dialog.

Catatan: Deskripsi tentang cara kerja dialog penutup di bawah tenda untuk kelas android dasar dan mengapa pendekatan berikut dipilih mengikuti contoh-contoh, bagi mereka yang ingin lebih detail


AlertDialog.Builder - Ubah penangan tombol default segera setelah show ()

AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
builder.setMessage("Test for preventing dialog close");
builder.setPositiveButton("Test", 
        new DialogInterface.OnClickListener()
        {
            @Override
            public void onClick(DialogInterface dialog, int which)
            {
                //Do nothing here because we override this button later to change the close behaviour. 
                //However, we still need this because on older versions of Android unless we 
                //pass a handler the button doesn't get instantiated
            }
        });
final AlertDialog dialog = builder.create();
dialog.show();
//Overriding the handler immediately after show is probably a better approach than OnShowListener as described below
dialog.getButton(AlertDialog.BUTTON_POSITIVE).setOnClickListener(new View.OnClickListener()
      {            
          @Override
          public void onClick(View v)
          {
              Boolean wantToCloseDialog = false;
              //Do stuff, possibly set wantToCloseDialog to true then...
              if(wantToCloseDialog)
                  dialog.dismiss();
              //else dialog stays open. Make sure you have an obvious way to close the dialog especially if you set cancellable to false.
          }
      });

DialogFragment - override onResume ()

@Override
public Dialog onCreateDialog(Bundle savedInstanceState)
{
    AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
    builder.setMessage("Test for preventing dialog close");
    builder.setPositiveButton("Test", 
        new DialogInterface.OnClickListener()
        {
            @Override
            public void onClick(DialogInterface dialog, int which)
            {
                //Do nothing here because we override this button later to change the close behaviour. 
                //However, we still need this because on older versions of Android unless we 
                //pass a handler the button doesn't get instantiated
            }
        });
    return builder.create();
}

//onStart() is where dialog.show() is actually called on 
//the underlying dialog, so we have to do it there or 
//later in the lifecycle.
//Doing it in onResume() makes sure that even if there is a config change 
//environment that skips onStart then the dialog will still be functioning
//properly after a rotation.
@Override
public void onResume()
{
    super.onResume();    
    final AlertDialog d = (AlertDialog)getDialog();
    if(d != null)
    {
        Button positiveButton = (Button) d.getButton(Dialog.BUTTON_POSITIVE);
        positiveButton.setOnClickListener(new View.OnClickListener()
                {
                    @Override
                    public void onClick(View v)
                    {
                        Boolean wantToCloseDialog = false;
                        //Do stuff, possibly set wantToCloseDialog to true then...
                        if(wantToCloseDialog)
                            d.dismiss();
                        //else dialog stays open. Make sure you have an obvious way to close the dialog especially if you set cancellable to false.
                    }
                });
    }
}

DialogPreference - ganti showDialog ()

@Override
protected void onPrepareDialogBuilder(Builder builder)
{
    super.onPrepareDialogBuilder(builder);
    builder.setPositiveButton("Test", this);   //Set the button here so it gets created
}

@Override
protected void showDialog(Bundle state)
{       
    super.showDialog(state);    //Call show on default first so we can override the handlers

    final AlertDialog d = (AlertDialog) getDialog();
    d.getButton(AlertDialog.BUTTON_POSITIVE).setOnClickListener(new View.OnClickListener()
            {            
                @Override
                public void onClick(View v)
                {
                    Boolean wantToCloseDialog = false;
                    //Do stuff, possibly set wantToCloseDialog to true then...
                    if(wantToCloseDialog)
                        d.dismiss();
                    //else dialog stays open. Make sure you have an obvious way to close the dialog especially if you set cancellable to false.
                }
            });
}

Penjelasan pendekatan:

Melihat melalui kode sumber Android, implementasi default AlertDialog bekerja dengan mendaftarkan pengendali tombol umum ke semua tombol aktual di OnCreate (). Ketika sebuah tombol diklik, handler tombol umum meneruskan acara klik ke handler apa pun yang Anda lewati di setButton () lalu panggilan mengabaikan dialog.

Jika Anda ingin mencegah kotak dialog menutup ketika salah satu tombol ini ditekan, Anda harus mengganti penangan tombol umum untuk tampilan tombol yang sebenarnya. Karena ditugaskan di OnCreate (), Anda harus menggantinya setelah implementasi OnCreate () default dipanggil. OnCreate dipanggil dalam proses metode show (). Anda bisa membuat kelas Dialog khusus dan menimpa OnCreate () untuk memanggil super.OnCreate () kemudian menimpa penangan tombol, tetapi jika Anda membuat dialog kustom Anda tidak mendapatkan Builder gratis, dalam hal apa gunanya titik ?

Jadi, dalam menggunakan dialog cara itu dirancang tetapi dengan mengendalikan ketika itu diberhentikan, salah satu pendekatan adalah untuk memanggil dialog. Tunjukkan () terlebih dahulu, kemudian dapatkan referensi ke tombol menggunakan dialog.getButton () untuk mengganti penangan klik. Pendekatan lain adalah dengan menggunakan setOnShowListener () dan mengimplementasikan menemukan tampilan tombol dan mengganti handler di OnShowListener. Perbedaan fungsional antara keduanya adalah 'hampir' nill, tergantung pada utas yang awalnya membuat instance dialog. Melihat melalui kode sumber, onShowListener dipanggil oleh pesan yang diposting ke penangan yang berjalan di utas yang membuat dialog itu. Jadi, karena OnShowListener Anda dipanggil oleh pesan yang diposting di antrian pesan, secara teknis dimungkinkan bahwa panggilan pendengar Anda tertunda beberapa saat setelah pertunjukan selesai.

Oleh karena itu, saya percaya pendekatan teraman adalah yang pertama: memanggil show.Dialog (), lalu segera di jalur eksekusi yang sama, ganti penangan tombol. Karena kode Anda yang memanggil show () akan beroperasi pada utas GUI utama, itu berarti kode apa pun yang Anda ikuti tampilkan () dengan akan dieksekusi sebelum kode lain pada utas itu, sedangkan waktu metode OnShowListener berada di bawah kendali antrian pesan.

Sogger
sumber
12
Sejauh ini, ini adalah implementasi termudah dan bekerja dengan sempurna. Saya telah menggunakan AlertDialog.Builder - Ubah handler tombol default segera setelah show () dan itu berfungsi seperti pesona.
Reinherd
1
@sogger Bung, saya benar-benar dengan berani mengedit jawaban Anda yang luar biasa karena pada bagian 1 Anda telah mengabaikan (); bukannya saya percaya dialog.dismiss (); terima kasih banyak atas jawaban yang luar biasa!
Fattie
Apakah ada cara untuk mencegah penutupan ProgressDialogketika tombol diklik?
Joshua Pinter
1
sapi suci, semakin saya tahu tentang Android semakin saya merasa jijik ... semua ini hanya untuk mendapatkan dialog sederhana yang berfungsi dengan baik. dibutuhkan berjam-jam hanya untuk mengetahui cara menampilkan dialog
SpaceMonkey
1
@harsh_v memperbarui jawaban untuk menggunakan onResume () untuk orang berikutnya, terima kasih!
Sogger
37

Solusi alternatif

Saya ingin menyajikan jawaban alternatif dari perspektif UX.

Mengapa Anda ingin mencegah dialog ditutup ketika tombol diklik? Mungkin itu karena Anda memiliki dialog khusus di mana pengguna belum membuat pilihan atau belum sepenuhnya mengisi semuanya. Dan jika mereka belum selesai, maka Anda seharusnya tidak membiarkan mereka mengklik tombol positif sama sekali. Nonaktifkan saja sampai semuanya siap.

Jawaban lain di sini memberikan banyak trik untuk mengganti klik tombol positif. Jika itu penting untuk dilakukan, bukankan Android telah membuat metode yang nyaman untuk melakukannya? Mereka tidak melakukannya.

Sebaliknya, panduan desain Dialogs menunjukkan contoh situasi seperti itu. Tombol OK dinonaktifkan sampai pengguna membuat pilihan. Tidak ada trik utama yang diperlukan sama sekali. Jelas bagi pengguna bahwa sesuatu masih perlu dilakukan sebelum melanjutkan.

masukkan deskripsi gambar di sini

Cara menonaktifkan tombol positif

Lihat dokumentasi Android untuk membuat tata letak dialog khusus . Disarankan agar Anda menempatkan AlertDialogdi dalam a DialogFragment. Maka yang perlu Anda lakukan adalah mengatur pendengar pada elemen tata letak untuk mengetahui kapan harus mengaktifkan atau menonaktifkan tombol positif.

Tombol positif dapat dinonaktifkan seperti ini:

AlertDialog dialog = (AlertDialog) getDialog();
dialog.getButton(AlertDialog.BUTTON_POSITIVE).setEnabled(false);

Berikut ini adalah keseluruhan yang bekerja DialogFragmentdengan tombol positif yang dinonaktifkan seperti yang dapat digunakan pada gambar di atas.

import android.support.v4.app.DialogFragment;
import android.support.v7.app.AlertDialog;

public class MyDialogFragment extends DialogFragment {

    @Override
    public Dialog onCreateDialog(Bundle savedInstanceState) {

        // inflate the custom dialog layout
        LayoutInflater inflater = getActivity().getLayoutInflater();
        View view = inflater.inflate(R.layout.my_dialog_layout, null);

        // add a listener to the radio buttons
        RadioGroup radioGroup = (RadioGroup) view.findViewById(R.id.radio_group);
        radioGroup.setOnCheckedChangeListener(new RadioGroup.OnCheckedChangeListener() {
            @Override
            public void onCheckedChanged(RadioGroup radioGroup, int i) {
                // enable the positive button after a choice has been made
                AlertDialog dialog = (AlertDialog) getDialog();
                dialog.getButton(AlertDialog.BUTTON_POSITIVE).setEnabled(true);
            }
        });

        // build the alert dialog
        AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
        builder.setView(view)
                .setPositiveButton("OK", new DialogInterface.OnClickListener() {
                    @Override
                    public void onClick(DialogInterface dialog, int id) {
                        // TODO: use an interface to pass the user choice back to the activity
                    }
                })
                .setNegativeButton("Cancel", new DialogInterface.OnClickListener() {
                    public void onClick(DialogInterface dialog, int id) {
                        MyDialogFragment.this.getDialog().cancel();
                    }
                });
        return builder.create();
    }

    @Override
    public void onResume() {
        super.onResume();

        // disable positive button by default
        AlertDialog dialog = (AlertDialog) getDialog();
        dialog.getButton(AlertDialog.BUTTON_POSITIVE).setEnabled(false);
    }
}

Dialog khusus dapat dijalankan dari aktivitas seperti ini:

MyDialogFragment dialog = new MyDialogFragment();
dialog.show(getFragmentManager(), "MyTag");

Catatan

  • Demi singkatnya, saya menghilangkan antarmuka komunikasi untuk meneruskan info pilihan pengguna kembali ke aktivitas. The dokumentasi menunjukkan bagaimana hal ini dilakukan, meskipun.
  • Tombol masih nulldi onCreateDialogjadi saya menonaktifkannya onResume. Ini memiliki efek yang tidak diinginkan untuk menonaktifkannya lagi jika pengguna beralih ke aplikasi lain dan kemudian kembali tanpa mengabaikan dialog. Ini dapat diatasi dengan juga membatalkan pilihan pengguna atau dengan memanggil Runnabledari onCreateDialoguntuk menonaktifkan tombol pada putaran berikutnya.

    view.post(new Runnable() {
        @Override
        public void run() {
            AlertDialog dialog = (AlertDialog) getDialog();
            dialog.getButton(AlertDialog.BUTTON_POSITIVE).setEnabled(false);
        }
    });

Terkait

Suragch
sumber
33

Saya telah menulis sebuah kelas sederhana (AlertDialogBuilder) yang dapat Anda gunakan untuk menonaktifkan fitur auto-dismiss ketika menekan tombol dialog.

Ini kompatibel juga dengan Android 1.6, sehingga tidak menggunakan OnShowListener (yang hanya tersedia API> = 8).

Jadi, alih-alih menggunakan AlertDialog.Builder Anda dapat menggunakan CustomAlertDialogBuilder ini. Bagian terpenting adalah Anda tidak boleh memanggil create () , tetapi hanya metode show () . Saya telah menambahkan metode seperti setCanceledOnTouchOutside () dan setOnDismissListener sehingga Anda masih dapat mengaturnya langsung di builder.

Saya mengujinya di Android 1.6, 2.x, 3.x dan 4.x jadi itu seharusnya bekerja dengan cukup baik. Jika Anda menemukan beberapa masalah, silakan komentar di sini.

package com.droidahead.lib.utils;

import android.app.AlertDialog;
import android.content.Context;
import android.content.DialogInterface;
import android.view.View;
import android.view.View.OnClickListener;

public class CustomAlertDialogBuilder extends AlertDialog.Builder {
    /**
     * Click listeners
     */
    private DialogInterface.OnClickListener mPositiveButtonListener = null;
    private DialogInterface.OnClickListener mNegativeButtonListener = null;
    private DialogInterface.OnClickListener mNeutralButtonListener = null;

    /**
     * Buttons text
     */
    private CharSequence mPositiveButtonText = null;
    private CharSequence mNegativeButtonText = null;
    private CharSequence mNeutralButtonText = null;

    private DialogInterface.OnDismissListener mOnDismissListener = null;

    private Boolean mCancelOnTouchOutside = null;

    public CustomAlertDialogBuilder(Context context) {
        super(context);
    }

    public CustomAlertDialogBuilder setOnDismissListener (DialogInterface.OnDismissListener listener) {
        mOnDismissListener = listener;
        return this;
    }

    @Override
    public CustomAlertDialogBuilder setNegativeButton(CharSequence text, DialogInterface.OnClickListener listener) {
        mNegativeButtonListener = listener;
        mNegativeButtonText = text;
        return this;
    }

    @Override
    public CustomAlertDialogBuilder setNeutralButton(CharSequence text, DialogInterface.OnClickListener listener) {
        mNeutralButtonListener = listener;
        mNeutralButtonText = text;
        return this;
    }

    @Override
    public CustomAlertDialogBuilder setPositiveButton(CharSequence text, DialogInterface.OnClickListener listener) {
        mPositiveButtonListener = listener;
        mPositiveButtonText = text;
        return this;
    }

    @Override
    public CustomAlertDialogBuilder setNegativeButton(int textId, DialogInterface.OnClickListener listener) {
        setNegativeButton(getContext().getString(textId), listener);
        return this;
    }

    @Override
    public CustomAlertDialogBuilder setNeutralButton(int textId, DialogInterface.OnClickListener listener) {
        setNeutralButton(getContext().getString(textId), listener);
        return this;
    }

    @Override
    public CustomAlertDialogBuilder setPositiveButton(int textId, DialogInterface.OnClickListener listener) {
        setPositiveButton(getContext().getString(textId), listener);
        return this;
    }

    public CustomAlertDialogBuilder setCanceledOnTouchOutside (boolean cancelOnTouchOutside) {
        mCancelOnTouchOutside = cancelOnTouchOutside;
        return this;
    }



    @Override
    public AlertDialog create() {
        throw new UnsupportedOperationException("CustomAlertDialogBuilder.create(): use show() instead..");
    }

    @Override
    public AlertDialog show() {
        final AlertDialog alertDialog = super.create();

        DialogInterface.OnClickListener emptyOnClickListener = new DialogInterface.OnClickListener() {
            @Override
            public void onClick(DialogInterface dialog, int which) { }
        };


        // Enable buttons (needed for Android 1.6) - otherwise later getButton() returns null
        if (mPositiveButtonText != null) {
            alertDialog.setButton(AlertDialog.BUTTON_POSITIVE, mPositiveButtonText, emptyOnClickListener);
        }

        if (mNegativeButtonText != null) {
            alertDialog.setButton(AlertDialog.BUTTON_NEGATIVE, mNegativeButtonText, emptyOnClickListener);
        }

        if (mNeutralButtonText != null) {
            alertDialog.setButton(AlertDialog.BUTTON_NEUTRAL, mNeutralButtonText, emptyOnClickListener);
        }

        // Set OnDismissListener if available
        if (mOnDismissListener != null) {
            alertDialog.setOnDismissListener(mOnDismissListener);
        }

        if (mCancelOnTouchOutside != null) {
            alertDialog.setCanceledOnTouchOutside(mCancelOnTouchOutside);
        }

        alertDialog.show();

        // Set the OnClickListener directly on the Button object, avoiding the auto-dismiss feature
        // IMPORTANT: this must be after alert.show(), otherwise the button doesn't exist..
        // If the listeners are null don't do anything so that they will still dismiss the dialog when clicked
        if (mPositiveButtonListener != null) {
            alertDialog.getButton(AlertDialog.BUTTON_POSITIVE).setOnClickListener(new OnClickListener() {

                @Override
                public void onClick(View v) {
                    mPositiveButtonListener.onClick(alertDialog, AlertDialog.BUTTON_POSITIVE);
                }
            });
        }

        if (mNegativeButtonListener != null) {
            alertDialog.getButton(AlertDialog.BUTTON_NEGATIVE).setOnClickListener(new OnClickListener() {

                @Override
                public void onClick(View v) {
                    mNegativeButtonListener.onClick(alertDialog, AlertDialog.BUTTON_NEGATIVE);
                }
            });
        }

        if (mNeutralButtonListener != null) {
            alertDialog.getButton(AlertDialog.BUTTON_NEUTRAL).setOnClickListener(new OnClickListener() {

                @Override
                public void onClick(View v) {
                    mNeutralButtonListener.onClick(alertDialog, AlertDialog.BUTTON_NEUTRAL);
                }
            });
        }

        return alertDialog;
    }   
}

EDIT Berikut adalah contoh kecil tentang cara menggunakan CustomAlertDialogBuilder:

// Create the CustomAlertDialogBuilder
CustomAlertDialogBuilder dialogBuilder = new CustomAlertDialogBuilder(context);

// Set the usual data, as you would do with AlertDialog.Builder
dialogBuilder.setIcon(R.drawable.icon);
dialogBuilder.setTitle("Dialog title");
dialogBuilder.setMessage("Some text..");

// Set your buttons OnClickListeners
dialogBuilder.setPositiveButton ("Button 1", new DialogInterface.OnClickListener() {
    public void onClick (DialogInterface dialog, int which) {
        // Do something...

        // Dialog will not dismiss when the button is clicked
        // call dialog.dismiss() to actually dismiss it.
    }
});

// By passing null as the OnClickListener the dialog will dismiss when the button is clicked.               
dialogBuilder.setNegativeButton ("Close", null);

// Set the OnDismissListener (if you need it)       
dialogBuilder.setOnDismissListener(new DialogInterface.OnDismissListener() {
    public void onDismiss(DialogInterface dialog) {
        // dialog was just dismissed..
    }
});

// (optional) set whether to dismiss dialog when touching outside
dialogBuilder.setCanceledOnTouchOutside(false);

// Show the dialog
dialogBuilder.show();

Bersulang,

Yuvi

YuviDroid
sumber
Bagus. Tetapi tidak berhasil untuk saya. Namun demikian, Dialog tetap diberhentikan.
Leandros
Mmm itu terdengar aneh. Saya menggunakan itu di aplikasi saya dan hanya tombol di mana saya secara eksplisit memanggil dialog.dismiss () akan mengabaikan Dialog. Pada versi Android apa yang Anda uji? Bisakah Anda menunjukkan kode di mana Anda menggunakan CustomAlertDialogBuilder?
YuviDroid
Saya pikir itu disebabkan karena ini: (panggil dialog.show () setelah onClickListener) pastebin.com/uLnSu5v7 Jika saya mengklik positif, tetapi mereka akan diberhentikan jika boolean benar ...
Leandros
Saya tidak mengujinya menggunakan Activity.onCreateDialog (). Mungkin tidak bisa seperti itu. Saya akan mengedit 'jawaban' untuk menyertakan contoh kecil tentang bagaimana saya menggunakannya.
YuviDroid
4
Ini berfungsi untuk saya dengan hasil edit saat ini! Namun: Satu peringatan lagi. Builder.getContext () hanya tersedia di API 11+. Tambahkan bidang Context mContextdan setel di konstruktor sebagai gantinya.
Oleg Vaskevich
28

Ini ada sesuatu jika Anda menggunakan DialogFragment- yang merupakan cara yang disarankan untuk menangani Dialog.

Apa yang terjadi dengan setButton()metode AlertDialog (dan saya bayangkan hal yang sama dengan AlertDialogBuilder's setPositiveButton()dan setNegativeButton()) adalah bahwa tombol yang Anda atur (misalnya AlertDialog.BUTTON_POSITIVE) dengan itu akan benar-benar memicu DUA OnClickListenerobjek berbeda ketika ditekan.

Pertama makhluk DialogInterface.OnClickListener , yang merupakan parameter untuk setButton(), setPositiveButton(), dan setNegativeButton().

Yang lainnya adalah View.OnClickListener , yang akan diatur untuk secara otomatis mengabaikan Anda AlertDialogketika salah satu tombolnya ditekan - dan diatur dengan AlertDialogsendirinya.

Apa yang dapat Anda lakukan adalah dengan menggunakan setButton()dengan nullsebagai DialogInterface.OnClickListener, untuk membuat tombol, dan kemudian memanggil kustom Anda metode tindakan dalam View.OnClickListener. Sebagai contoh,

@Override
public Dialog onCreateDialog(Bundle savedInstanceState)
{
    AlertDialog alertDialog = new AlertDialog(getActivity());
    // set more items...
    alertDialog.setButton(AlertDialog.BUTTON_POSITIVE, "OK", null);

    return alertDialog;
}

Kemudian, Anda dapat mengganti tombol AlertDialog' default ' View.OnClickListener(yang akan mengabaikan dialog) dalam metode DialogFragment' onResume():

@Override
public void onResume()
{
    super.onResume();
    AlertDialog alertDialog = (AlertDialog) getDialog();
    Button okButton = alertDialog.getButton(AlertDialog.BUTTON_POSITIVE);
    okButton.setOnClickListener(new View.OnClickListener() { 
        @Override
        public void onClick(View v)
        {
            performOkButtonAction();
        }
    });
}

private void performOkButtonAction() {
    // Do your stuff here
}

Anda perlu mengatur ini dalam onResume()metode karena getButton()akan kembali nullsampai setelah dialog ditampilkan!

Ini akan menyebabkan metode tindakan khusus Anda hanya dipanggil sekali, dan dialog tidak akan diabaikan secara default.

Zhuiguang Liu
sumber
21

Terinspirasi oleh jawaban Tom, saya yakin idenya di sini adalah:

  • Atur onClickListenerselama pembuatan dialognull
  • Kemudian atur onClickListenersetelah dialog ditampilkan.

Anda dapat menimpa onShowListenerTom seperti itu. Atau, Anda bisa

  1. dapatkan tombol setelah memanggil AlertDialog's show()
  2. atur tombolnya onClickListenersebagai berikut (saya pikir sedikit lebih mudah dibaca).

Kode:

AlertDialog.Builder builder = new AlertDialog.Builder(context);
// ...
final AlertDialog dialog = builder.create();
dialog.show();
// now you can override the default onClickListener
Button b = dialog.getButton(AlertDialog.BUTTON_POSITIVE);
b.setOnClickListener(new View.OnClickListener() {
    @Override
    public void onClick(View view) {
        Log.i(TAG, "ok button is clicked");
        handleClick(dialog);
    }
});
ericn
sumber
8

Untuk pra API 8 saya memecahkan masalah menggunakan bendera boolean, pendengar pemberhentian dan panggilan dialog.show lagi jika dalam kasus konten editText tidak benar. Seperti ini:

case ADD_CLIENT:
        LayoutInflater factoryClient = LayoutInflater.from(this);
        final View EntryViewClient = factoryClient.inflate(
                R.layout.alert_dialog_add_client, null);

        EditText ClientText = (EditText) EntryViewClient
                .findViewById(R.id.client_edit);

        AlertDialog.Builder builderClient = new AlertDialog.Builder(this);
        builderClient
                .setTitle(R.string.alert_dialog_client)
                .setCancelable(false)
                .setView(EntryViewClient)
                .setPositiveButton("Save",
                        new DialogInterface.OnClickListener() {
                            public void onClick(DialogInterface dialog,
                                    int whichButton) {
                                EditText newClient = (EditText) EntryViewClient
                                        .findViewById(R.id.client_edit);
                                String newClientString = newClient
                                        .getText().toString();
                                if (checkForEmptyFields(newClientString)) {
                                    //If field is empty show toast and set error flag to true;
                                    Toast.makeText(getApplicationContext(),
                                            "Fields cant be empty",
                                            Toast.LENGTH_SHORT).show();
                                    add_client_error = true;
                                } else {
                                    //Here save the info and set the error flag to false
                                    add_client_error = false;
                                }
                            }
                        })
                .setNegativeButton("Cancel",
                        new DialogInterface.OnClickListener() {
                            public void onClick(DialogInterface dialog,
                                    int id) {
                                add_client_error = false;
                                dialog.cancel();
                            }
                        });
        final AlertDialog alertClient = builderClient.create();
        alertClient.show();

        alertClient
                .setOnDismissListener(new DialogInterface.OnDismissListener() {

                    @Override
                    public void onDismiss(DialogInterface dialog) {
                        //If the error flag was set to true then show the dialog again
                        if (add_client_error == true) {
                            alertClient.show();
                        } else {
                            return;
                        }

                    }
                });
        return true;
Steve
sumber
onDismiss aneh tidak dipanggil, milikku adalah api level 21
duckduckgo
7

Jawaban di tautan ini adalah solusi sederhana, dan yang kompatibel segera kembali ke API 3. Sangat mirip dengan solusi Tom Bollwitt, tetapi tanpa menggunakan OnShowListener yang kurang kompatibel.

Ya kamu bisa. Anda pada dasarnya perlu:

  1. Buat dialog dengan DialogBuilder
  2. tampilkan () dialog
  3. Temukan tombol dalam dialog yang ditunjukkan dan ganti onClickListener mereka

Saya membuat sedikit adaptasi terhadap kode Kamen karena saya sedang memperpanjang EditTextPreference.

@Override
protected void showDialog(Bundle state) {
  super.showDialog(state);

  class mocl implements OnClickListener{
    private final AlertDialog dialog;
    public mocl(AlertDialog dialog) {
          this.dialog = dialog;
      }
    @Override
    public void onClick(View v) {

        //checks if EditText is empty, and if so tells the user via Toast
        //otherwise it closes dialog and calls the EditTextPreference's onClick
        //method to let it know that the button has been pressed

        if (!IntPreference.this.getEditText().getText().toString().equals("")){
        dialog.dismiss();
        IntPreference.this.onClick(dialog,DialogInterface.BUTTON_POSITIVE);
        }
        else {
            Toast t = Toast.makeText(getContext(), "Enter a number!", Toast.LENGTH_SHORT);
            t.show();
        }

    }
  }

  AlertDialog d = (AlertDialog) getDialog();
  Button b = d.getButton(DialogInterface.BUTTON_POSITIVE);
  b.setOnClickListener(new mocl((d)));
}

Sangat menyenangkan!

lukeuser
sumber
4

Kode ini akan bekerja untuk Anda, karena saya punya masalah yang sama dan ini bekerja untuk saya. :)

1- Metode Override Onstart () di kelas dialog-fragmen Anda.

@Override
public void onStart() {
    super.onStart();
    final AlertDialog D = (AlertDialog) getDialog();
    if (D != null) {
        Button positive = (Button) D.getButton(Dialog.BUTTON_POSITIVE);
        positive.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View arg0) {
                if (edittext.equals("")) {
   Toast.makeText(getActivity(), "EditText empty",Toast.LENGTH_SHORT).show();
                } else {
                D.dismiss(); //dissmiss dialog
                }
            }
        });
    }
}
Luis Nuñez
sumber
3

Untuk ProgressDialogs

Untuk mencegah dialog ditolak secara otomatis, Anda harus mengatur OnClickListenersetelah ProgressDialogditampilkan, seperti:

connectingDialog = new ProgressDialog(this);

connectingDialog.setCancelable(false);
connectingDialog.setCanceledOnTouchOutside(false);

// Create the button but set the listener to a null object.
connectingDialog.setButton(DialogInterface.BUTTON_NEGATIVE, "Cancel", 
        (DialogInterface.OnClickListener) null )

// Show the dialog so we can then get the button from the view.
connectingDialog.show();

// Get the button from the view.
Button dialogButton = connectingDialog.getButton( DialogInterface.BUTTON_NEGATIVE);

// Set the onClickListener here, in the view.
dialogButton.setOnClickListener( new View.OnClickListener() {

    @Override
    public void onClick ( View v ) {

        // Dialog will not get dismissed until you call dismiss() explicitly.

    }

});
Joshua Pinter
sumber
3
public class ComentarDialog extends DialogFragment{
private EditText comentario;

@Override
public Dialog onCreateDialog(Bundle savedInstanceState) {

    AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());

    LayoutInflater inflater = LayoutInflater.from(getActivity());
    View v = inflater.inflate(R.layout.dialog_comentar, null);
    comentario = (EditText)v.findViewById(R.id.etxt_comentar_dialog);

    builder.setTitle("Comentar")
           .setView(v)
           .setPositiveButton("OK", null)
           .setNegativeButton("CANCELAR", new DialogInterface.OnClickListener() {
               public void onClick(DialogInterface dialog, int id) {

               }
           });

    return builder.create();
}

@Override
public void onStart() {
    super.onStart();

    //Obtenemos el AlertDialog
    AlertDialog dialog = (AlertDialog)getDialog();

    dialog.setCanceledOnTouchOutside(false);
    dialog.setCancelable(false);//Al presionar atras no desaparece

    //Implementamos el listener del boton OK para mostrar el toast
    dialog.getButton(AlertDialog.BUTTON_POSITIVE).setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View v) {
            if(TextUtils.isEmpty(comentario.getText())){
               Toast.makeText(getActivity(), "Ingrese un comentario", Toast.LENGTH_SHORT).show();
               return;
            }
            else{
                ((AlertDialog)getDialog()).dismiss();
            }
        }
    });

    //Personalizamos
    Resources res = getResources();

    //Buttons
    Button positive_button = dialog.getButton(DialogInterface.BUTTON_POSITIVE);
    positive_button.setBackground(res.getDrawable(R.drawable.btn_selector_dialog));

    Button negative_button =  dialog.getButton(DialogInterface.BUTTON_NEGATIVE);
    negative_button.setBackground(res.getDrawable(R.drawable.btn_selector_dialog));

    int color = Color.parseColor("#304f5a");

    //Title
    int titleId = res.getIdentifier("alertTitle", "id", "android");
    View title = dialog.findViewById(titleId);
    if (title != null) {
        ((TextView) title).setTextColor(color);
    }

    //Title divider
    int titleDividerId = res.getIdentifier("titleDivider", "id", "android");
    View titleDivider = dialog.findViewById(titleDividerId);
    if (titleDivider != null) {
        titleDivider.setBackgroundColor(res.getColor(R.color.list_menu_divider));
    }
}
}
Eragonz91
sumber
3

Anda dapat menambahkan builder.show (); setelah pesan validasi sebelum kembali;

seperti ini

    public void login()
{
    final AlertDialog.Builder builder = new AlertDialog.Builder(this);
    builder.setView(R.layout.login_layout);
    builder.setTitle("Login");



    builder.setNegativeButton("Cancel", new DialogInterface.OnClickListener()
    {
        @Override
        public void onClick(DialogInterface dialog, int id)
        {
            dialog.cancel();
        }
    });// put the negative button before the positive button, so it will appear

    builder.setPositiveButton("Ok", new DialogInterface.OnClickListener()
    {
        @Override
        public void onClick(DialogInterface dialog, int id)
        {
            Dialog d = (Dialog) dialog;
            final EditText etUserName = (EditText) d.findViewById(R.id.etLoginName);
            final EditText etPassword = (EditText) d.findViewById(R.id.etLoginPassword);
            String userName = etUserName.getText().toString().trim();
            String password = etPassword.getText().toString().trim();

            if (userName.isEmpty() || password.isEmpty())
            {

                Toast.makeText(getApplicationContext(),
                        "Please Fill all fields", Toast.LENGTH_SHORT).show();
                builder.show();// here after validation message before retrun
                               //  it will reopen the dialog
                              // till the user enter the right condition
                return;
            }

            user = Manager.get(getApplicationContext()).getUserByName(userName);

            if (user == null)
            {
                Toast.makeText(getApplicationContext(),
                        "Error ethier username or password are wrong", Toast.LENGTH_SHORT).show();
                builder.show();
                return;
            }
            if (password.equals(user.getPassword()))
            {
                etPassword.setText("");
                etUserName.setText("");
                setLogged(1);
                setLoggedId(user.getUserId());
                Toast.makeText(getApplicationContext(),
                        "Successfully logged in", Toast.LENGTH_SHORT).show();
               dialog.dismiss();// if every thing is ok then dismiss the dialog
            }
            else
            {
                Toast.makeText(getApplicationContext(),
                        "Error ethier username or password are wrong", Toast.LENGTH_SHORT).show();
                builder.show();
                return;
            }

        }
    });

    builder.show();

}
Orang x Person212
sumber
3

Untuk mencegah kotak Dialog dari menutup ketika diklik dan itu hanya akan ditutup ketika internet tersedia

Saya mencoba melakukan hal yang sama, karena saya tidak ingin kotak dialog ditutup sampai dan kecuali internet terhubung.

Ini kode saya:

AlertDialog.Builder builder=new AlertDialog.Builder(MainActivity.this); builder.setTitle("Internet Not Connected");
    if(ifConnected()){

        Toast.makeText(this, "Connected or not", Toast.LENGTH_LONG).show();
    }
    else{
        builder.setPositiveButton("Retry", new DialogInterface.OnClickListener() {
            @Override
            public void onClick(DialogInterface dialogInterface, int i) {
               if(!ifConnected())
               {
                   builder.show();
               }
            }
        }).setNegativeButton("Cancel", new DialogInterface.OnClickListener() {
            @Override
            public void onClick(DialogInterface dialogInterface, int i) {
                finish();
            }
        });
        builder.show();

    }

Dan inilah kode manajer Konektivitas saya:

 private boolean ifConnected()
{
    ConnectivityManager connectivityManager= (ConnectivityManager) getSystemService(Context.CONNECTIVITY_SERVICE);
    NetworkInfo networkInfo=connectivityManager.getActiveNetworkInfo();
   return networkInfo!=null && networkInfo.isConnected();
}
karan1.singh
sumber
Ini pintar, tetapi saya mendapatkan pesan kesalahan ini:The specified child already has a parent. You must call removeView() on the child's parent first
Dan Chaltiel
2

Jika Anda menggunakan material designsaya akan menyarankan memeriksa bahan-dialog . Ini memperbaiki beberapa masalah bagi saya terkait dengan bug Android yang saat ini terbuka (lihat 78088 ), tetapi yang paling penting untuk tiket ini memiliki autoDismissbendera yang dapat diatur ketika menggunakan Builder.

theblang
sumber
1

Gunakan tata letak khusus untuk Anda DialogFragmentdan tambahkan LinearLayoutkonten Anda di bawah yang dapat ditata sebagai tanpa batas agar sesuai dengan Desain Bahan Google. Kemudian cari tombol yang baru dibuat dan ganti OnClickListener.

Contoh:

public class AddTopicFragment extends DialogFragment {

    @Override
    public Dialog onCreateDialog(Bundle savedInstanceState) {
        final AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
        // Get the layout inflater
        LayoutInflater inflater = getActivity().getLayoutInflater();
        final View dialogView = inflater.inflate(R.layout.dialog_add_topic, null);

        Button saveTopicDialogButton = (Button) dialogView.findViewById(R.id.saveTopicDialogButton);
        Button cancelSaveTopicDialogButton = (Button) dialogView.findViewById(R.id.cancelSaveTopicDialogButton);

        final AppCompatEditText addTopicNameET = (AppCompatEditText) dialogView.findViewById(R.id.addTopicNameET);
        final AppCompatEditText addTopicCreatedByET = (AppCompatEditText) dialogView.findViewById(R.id.addTopicCreatedByET);

        saveTopicDialogButton.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                // validate inputs
                if(addTopicNameET.getText().toString().trim().isEmpty()){
                    addTopicNameET.setError("Topic name can't be empty");
                    addTopicNameET.requestFocus();
                }else if(addTopicCreatedByET.getText().toString().trim().isEmpty()){
                    addTopicCreatedByET.setError("Topic created by can't be empty");
                    addTopicCreatedByET.requestFocus();
                }else {
                    // save topic to database
                    Topic topic = new Topic();
                    topic.name = addTopicNameET.getText().toString().trim();
                    topic.createdBy = addTopicCreatedByET.getText().toString().trim();
                    topic.createdDate = new Date().getTime();
                    topic.save();
                    AddTopicFragment.this.dismiss();
                }
            }
        });

        cancelSaveTopicDialogButton.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                AddTopicFragment.this.dismiss();
            }
        });

        // Inflate and set the layout for the dialog
        // Pass null as the parent view because its going in the dialog layout
        builder.setView(dialogView)
               .setMessage(getString(R.string.add_topic_message));

        return builder.create();
    }

}

dialog_add_topic.xml :

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:orientation="vertical"
    android:padding="@dimen/activity_horizontal_margin"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <android.support.design.widget.TextInputLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        app:errorEnabled="true">

        <android.support.v7.widget.AppCompatEditText
            android:id="@+id/addTopicNameET"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:hint="Topic Name"
            android:inputType="textPersonName"
            android:maxLines="1" />

    </android.support.design.widget.TextInputLayout>

    <android.support.design.widget.TextInputLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        app:errorEnabled="true">

        <android.support.v7.widget.AppCompatEditText
            android:id="@+id/addTopicCreatedByET"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:hint="Created By"
            android:inputType="textPersonName"
            android:maxLines="1" />

    </android.support.design.widget.TextInputLayout>

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:orientation="horizontal">
        <Button
            android:text="@string/cancel"
            android:layout_weight="1"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:id="@+id/cancelSaveTopicDialogButton"
            style="@style/Widget.AppCompat.Button.ButtonBar.AlertDialog" />

        <Button
            android:text="@string/save"
            android:layout_weight="1"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:id="@+id/saveTopicDialogButton"
            style="@style/Widget.AppCompat.Button.ButtonBar.AlertDialog" />

    </LinearLayout>


</LinearLayout>

Ini adalah hasil akhir.

Ibrahim Hassan
sumber
0

Itu bisa dibangun dengan cara termudah:

Dialog Peringatan dengan Tampilan Kustom dan dengan dua Tombol (Positif & Negatif).

AlertDialog.Builder builder = new AlertDialog.Builder(getActivity()).setTitle(getString(R.string.select_period));
builder.setPositiveButton(getString(R.string.ok), null);

 builder.setNegativeButton(getString(R.string.cancel), new DialogInterface.OnClickListener() {
    @Override
    public void onClick(DialogInterface dialog, int which) {

    // Click of Cancel Button

   }
 });

  LayoutInflater li = LayoutInflater.from(getActivity());
  View promptsView = li.inflate(R.layout.dialog_date_picker, null, false);
  builder.setView(promptsView);

  DatePicker startDatePicker = (DatePicker)promptsView.findViewById(R.id.startDatePicker);
  DatePicker endDatePicker = (DatePicker)promptsView.findViewById(R.id.endDatePicker);

  final AlertDialog alertDialog = builder.create();
  alertDialog.show();

  Button theButton = alertDialog.getButton(DialogInterface.BUTTON_POSITIVE);
  theButton.setOnClickListener(new CustomListener(alertDialog, startDatePicker, endDatePicker));

CustomClickLister dari Tombol Positif dari Siaga dailog :

private class CustomListener implements View.OnClickListener {
        private final Dialog dialog;
        private DatePicker mStartDp, mEndDp;
    public CustomListener(Dialog dialog, DatePicker dS, DatePicker dE) {
        this.dialog = dialog;
        mStartDp = dS;
        mEndDp = dE;
    }

    @Override
    public void onClick(View v) {

        int day1  = mStartDp.getDayOfMonth();
        int month1= mStartDp.getMonth();
        int year1 = mStartDp.getYear();
        Calendar cal1 = Calendar.getInstance();
        cal1.set(Calendar.YEAR, year1);
        cal1.set(Calendar.MONTH, month1);
        cal1.set(Calendar.DAY_OF_MONTH, day1);


        int day2  = mEndDp.getDayOfMonth();
        int month2= mEndDp.getMonth();
        int year2 = mEndDp.getYear();
        Calendar cal2 = Calendar.getInstance();
        cal2.set(Calendar.YEAR, year2);
        cal2.set(Calendar.MONTH, month2);
        cal2.set(Calendar.DAY_OF_MONTH, day2);

        if(cal2.getTimeInMillis()>=cal1.getTimeInMillis()){
            dialog.dismiss();
            Log.i("Dialog", "Dismiss");
            // Condition is satisfied so do dialog dismiss
            }else {
            Log.i("Dialog", "Do not Dismiss");
            // Condition is not satisfied so do not dialog dismiss
        }

    }
}

Selesai

Hiren Patel
sumber
-1

Ini mungkin balasan yang sangat terlambat, tetapi menggunakan setCancelable akan membantu.

alertDial.setCancelable(false);
Navneeth T
sumber
10
Dari dokumen: "Setel apakah dialog ini dapat dibatalkan dengan kunci BACK." Ini tidak ada hubungannya dengan tombol positif menolak dialog ..
clauziere
3
Tidak bekerja untuk saya, masih menolak ketika mengklik tombol positif
Hugo
1
Ini tidak ada hubungannya dengan OP
MatPag
1
Tidak menjawab pertanyaan
Kevin Crain