Як запобігти закриттю діалогового вікна при натисканні кнопки


731

У мене діалогове вікно EditTextдля введення. Коли я натискаю кнопку "так" у діалоговому вікні, вона підтвердить введення та закриє діалогове вікно. Однак якщо введення помилкове, я хочу залишатися в тому ж діалозі. Кожен раз, незалежно від вводу, діалогове вікно має бути автоматично закрито, коли я натискаю кнопку "ні". Як я можу відключити це? До речі, я використовував PositiveButton і NegativeButton для кнопки в діалоговому вікні.

Відповіді:


916

EDIT: Це працює лише на API 8+, як зазначено в деяких коментарях.

Це пізня відповідь, але ви можете додати onShowListener до AlertDialog, де потім зможете замінити onClickListener кнопки.

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();

7
Гей, краще пізніше, ніж ніколи, я шукав саме це, спасибі, +1 :) Це елегантний спосіб додавання перевірки до діалогу, особливо коли у вас вже є клас обговорення помічників для вирішення сповіщень
Гійом

11
Не працює. AlertDialog.Builder.setOnShowListener не існує. developer.android.com/reference/android/app/…
Leandros

4
За допомогою API до 8 ви можете зателефонувати на d.getButton (AlertDialog.BUTTON_POSITIVE); як це загальнодоступний метод, але його потрібно викликати show (); було видано, інакше ви отримаєте нуль від нього
Hurda

13
Ви можете зробити це навіть чистішим засобом, встановивши нульовий OnClickListener для конструктора діалогових вікон (зберігає порожній "// це буде відмінено" слухачем).
Стів Хейлі

1
Також добре працює з DialogFragments, коли AlertDialog створюється в методі onCreateDialog (Bundle saveInstanceState).
Крістіан Лішніг

654

Ось декілька рішень для всіх типів діалогів, включаючи рішення для AlertDialog.Builder, які працюватимуть на всіх рівнях API (працює нижче API 8, іншого відповіді тут немає). Існують рішення для AlertDialogs за допомогою AlertDialog.Builder, DialogFragment та DialogPreference.

Нижче наведено приклади коду, що показують, як змінити загальний обробник кнопок за замовчуванням та запобігти закриттю діалогу для цих різних форм діалогів. Усі приклади показують, як запобігти закриттю діалогового вікна позитивної кнопки.

Примітка: Опис того, як працює закриття діалогового вікна під кришкою для базових класів Android та чому наступні підходи вибираються після прикладів, для тих, хто хоче більше деталей


AlertDialog.Builder - Змініть обробник кнопок за замовчуванням відразу після 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 - перевизначення 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 - переосмислити 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.
                }
            });
}

Пояснення підходів:

Переглядаючи вихідний код Android, реалізація за замовчуванням AlertDialog працює, зареєструвавши загальний обробник кнопок для всіх фактичних кнопок у OnCreate (). Після натискання кнопки звичайний обробник кнопок пересилає подію натискання на той обробник, який ви передали в setButton (), а потім виклики відхиляє діалогове вікно.

Якщо ви хочете не допустити закриття діалогового вікна при натисканні однієї з цих кнопок, вам слід замінити звичайний обробник кнопок на фактичний вигляд кнопки. Оскільки він призначений в OnCreate (), ви повинні замінити його після виклику реалізації за замовчуванням OnCreate (). OnCreate викликається в процесі методу show (). Ви можете створити спеціальний клас діалогового вікна та замінити OnCreate () для виклику super.OnCreate (), а потім замінить обробники кнопок, але якщо ви зробите спеціальний діалог, ви не отримаєте Builder безкоштовно, і в цьому випадку в чому справа ?

Отже, використовуючи діалоговий вигляд, як він розроблений, але контролюючи його відхилення, одним із підходів є спочатку викликати dialog.Show (), потім отримати посилання на кнопку, використовуючи dialog.getButton (), щоб змінити обробник кліків. Іншим підходом є використання setOnShowListener () та реалізація пошуку перегляду кнопок та заміни обробника в OnShowListener. Функціональна різниця між цими двома - «майже» нульова, залежно від того, який потік створює екземпляр діалога. Переглядаючи вихідний код, onShowListener викликається повідомленням, розміщеним на обробнику, що працює на потоці, який створив це діалогове вікно. Отже, оскільки ваш OnShowListener викликається повідомленням, розміщеним у черзі повідомлень, технічно можливо, що виклик слухача затримується на деякий час після завершення шоу.

Тому я вважаю, що найбезпечнішим підходом є перший: викликати show.Dialog (), потім негайно в тому ж шляху виконання замінити обробники кнопок. Оскільки ваш код, який викликає show (), буде працювати в головному потоці графічного інтерфейсу, це означає, що будь-який код, за яким ви слідуєте show (), буде виконуватися перед будь-яким іншим кодом у цьому потоці, тоді як час використання методу OnShowListener знаходиться на милі черга повідомлень.


12
Це, безумовно, найпростіша реалізація і працює ідеально. Я використовував AlertDialog.Builder - змініть обробник кнопок за замовчуванням відразу після show (), і він працює як шарм.
Райнгерд

1
@sogger чувак, я цілком сміливо відредагував вашу дивовижну відповідь, бо в розділі 1 ви звільнили (); замість того, що я вважаю dialog.dismiss (); велике спасибі за дивовижну відповідь!
Fattie

Чи є якийсь спосіб запобігти закриттю а, ProgressDialogколи на ньому натискається кнопка?
Джошуа Пінтер

1
свята корова, чим більше я знаю про Android, тим більше я відчуваю огиду ... все це лише для того, щоб простий діалог працював належним чином. потрібні години, щоб з'ясувати, як відобразити діалог
SpaceMonkey

1
@harsh_v оновив відповідь на використання onResume () для наступної людини, дякую!
Соггер

37

Альтернативне рішення

Я хотів би представити альтернативну відповідь з точки зору UX.

Чому ви хочете не допустити закриття діалогового вікна при натисканні кнопки? Імовірно, це тому, що у вас є власне діалогове вікно, в якому користувач не зробив вибір або ще не повністю заповнив усе. І якщо вони не закінчені, то ви не повинні дозволити їм взагалі натискати позитивну кнопку. Просто відключіть його, поки все не буде готове.

Інші відповіді тут дають безліч хитрощів для перебору позитивного натискання кнопки. Якби це було важливо зробити, чи не зробив би Android зручний метод для цього? Вони цього не зробили.

Натомість посібник із проектування Dialogs показує приклад такої ситуації. Кнопка ОК відключена, поки користувач не зробить вибір. Ніяких переважаючих хитрощів взагалі не потрібно. Користувачеві очевидно, що щось ще потрібно зробити, перш ніж продовжувати.

введіть тут опис зображення

Як відключити позитивну кнопку

Див. Документацію для Android щодо створення користувацького діалогового макета . Рекомендує розмістити свою AlertDialogвнутрішню частину DialogFragment. Тоді все, що вам потрібно зробити, це встановити слухачів на елементи макета, щоб знати, коли ввімкнути або вимкнути позитивну кнопку.

  • Якщо у вашому користувальницькому діалоговому вікні є перемикачі, використовуйте RadioGroup.OnCheckedChangeListener .
  • Якщо у вашому користувальницькому діалоговому вікні встановлені прапорці, використовуйте CompoundButton.OnCheckedChangeListener .
  • Якщо у вашому користувальницькому діалоговому вікні є EditText, використовуйте TextWatcher .

Позитивну кнопку можна відключити так:

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

Ось ціла робота DialogFragmentз відключеною позитивною кнопкою, яка може бути використана на зображенні вище.

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);
    }
}

Власне діалогове вікно можна запустити з такої діяльності:

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

Примітки

  • Для стислості я пропустив комунікаційний інтерфейс, щоб повернути інформацію про вибір користувача назад до діяльності. У документації показано , як це робиться, хоча.
  • Кнопка все ще nullвключена, onCreateDialogтому я її відключив onResume. Це призводить до небажаного ефекту відключення його знову, якщо користувач переходить на інший додаток, а потім повертається, не відхиляючи діалогове вікно. Це можна вирішити, скасувавши вибір користувачів, або зателефонувавши Runnableз, onCreateDialogщоб відключити кнопку в наступному циклі запуску.

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

Пов'язані


33

Я написав простий клас (AlertDialogBuilder), який можна використовувати для відключення функції автоматичного відключення при натисканні кнопок діалогу.

Він сумісний і з Android 1.6, тому він не використовує OnShowListener (який доступний лише API> = 8).

Отже, замість використання AlertDialog.Builder ви можете використовувати цей CustomAlertDialogBuilder. Найважливіша частина - це те, що вам не слід телефонувати create () , а лише метод show () . Я додав такі методи, як setCanceledOnTouchOutside () та setOnDismissListener, щоб ви могли все-таки встановити їх безпосередньо в програмі.

Я тестував його на Android 1.6, 2.x, 3.x і 4.x, тому він повинен працювати досить добре. Якщо у вас виникли проблеми, прокоментуйте тут.

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 Ось невеликий приклад того, як користуватися 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();

Ура,

Юві


Приємно. Але мені не вийшло. Діалог все ж звільняють.
Леандрос

Ммм, це звучить дивно. Я використовую це у своєму додатку, і лише кнопки, де я явно дзвоню dialog.dismiss (), відхилять Діалог. На якій версії Android ви тестуєте? Чи можете ви показати свій код, де ви використовували CustomAlertDialogBuilder?
YuviDroid

Я думаю, що це викликано через це: (виклик dialog.show () після onClickListener) pastebin.com/uLnSu5v7 Якщо я натискаю позитивну кнопку, вони будуть звільнені, якщо булева правда ...
Leandros

Я не перевіряв це за допомогою Activity.onCreateDialog (). Напевно, це не може працювати таким чином. Я відредагую "відповідь", щоб включити невеликий приклад того, як я її використовую.
YuviDroid

4
Це працює для мене з поточною редакцією! Однак: Ще один застереження. Builder.getContext () доступний лише для API 11+. Додайте поле Context mContextта встановіть його замість нього в конструкторі.
Олег Васкевич

28

Ось щось, якщо ви використовуєте DialogFragment- який у будь-якому випадку є рекомендованим способом обробки діалогів.

Те, що відбувається з setButton()методом AlertDialog (і я думаю, те саме саме з AlertDialogBuilder's setPositiveButton()і setNegativeButton()), - це те, що кнопка, яку ви встановили (наприклад AlertDialog.BUTTON_POSITIVE) з нею, насправді запустить ДВІ різніOnClickListener об'єкта при натисканні.

Перше істота DialogInterface.OnClickListener , яка є параметром setButton(), setPositiveButton()і setNegativeButton().

Інший - View.OnClickListener , який буде налаштовано автоматично відхиляти ваш AlertDialogпри натисканні будь-якої його кнопки - і встановлюється AlertDialogсам.

Що ви можете зробити, це використовувати за setButton()допомогою nullкнопки DialogInterface.OnClickListener, створити кнопку, а потім зателефонувати на ваш власний метод дії всередині View.OnClickListener. Наприклад,

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

    return alertDialog;
}

Тоді ви можете змінити за замовчуванням AlertDialogкнопки ' View.OnClickListener(які б інакше відхилили діалогове вікно) у методі DialogFragment' s 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
}

Вам потрібно буде встановити це в onResume()методі, оскільки getButton()повернеться nullдо тих пір, поки не буде показано діалогове вікно!

Це повинно викликати ваш власний метод дії лише один раз, і діалогове вікно не буде відхилено за замовчуванням.


21

Натхненний відповіддю Тома, я вважаю, що ідея тут така:

  • onClickListenerПід час створення діалогового вікна встановіть значення наnull
  • Потім встановіть a onClickListenerпісля того, як з'явиться діалогове вікно.

Ви можете перемогти onShowListenerподібного Тома. Як варіант, ви можете

  1. отримати кнопку після виклику AlertDialog's show()
  2. встановіть кнопки " onClickListenerтак (я думаю, трохи легше читати).

Код:

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);
    }
});

8

Для попереднього API 8 я вирішив проблему за допомогою булевого прапора, відхилення слухача та виклику dialog.how show again, якщо у випадку змісту editText не було правильним. Подобається це:

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;

дивно не звільнятись, не дзвонять, мій api рівень 21
качка

7

Відповідь за цим посиланням - це просте рішення, яке сумісне з API 3. Це дуже подібне до рішення Тома Болвітта, але без використання менш сумісного OnShowListener.

Так, ти можеш. В основному вам потрібно:

  1. Створіть діалогове вікно з DialogBuilder
  2. показати () діалогове вікно
  3. Знайдіть кнопки в діалоговому діалоговому вікні та замініть їх onClickListener

Я вніс незначні зміни в код Камена, оскільки розширював редакцію 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)));
}

Така забава!


4

Цей код буде працювати для вас, тому що у мене була однакова проблема, і це працювало для мене. :)

1- Перезазначити метод Onstart () у вашому класі діалогового діалогу.

@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
                }
            }
        });
    }
}

3

Для ProgressDialogs

Щоб запобігти автоматичному відхиленню діалогового вікна, вам слід встановити OnClickListenerпісля того ProgressDialog, як буде показано, як:

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.

    }

});

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));
    }
}
}

3

ви можете додати builder.show (); після повідомлення про перевірку перед поверненням;

подобається це

    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();

}

3

Щоб діалогове вікно не закривалося при натисканні, воно має закриватися лише тоді, коли доступний Інтернет

Я намагаюся зробити те саме, тому що я не хочу, щоб діалогове вікно було закрите до тих пір, поки не буде підключено Інтернет.

Ось мій код:

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();

    }

А ось мій код менеджера зв’язків:

 private boolean ifConnected()
{
    ConnectivityManager connectivityManager= (ConnectivityManager) getSystemService(Context.CONNECTIVITY_SERVICE);
    NetworkInfo networkInfo=connectivityManager.getActiveNetworkInfo();
   return networkInfo!=null && networkInfo.isConnected();
}

Це розумно, але я отримую це повідомлення про помилку:The specified child already has a parent. You must call removeView() on the child's parent first
Dan Chaltiel,

2

Якщо ви використовуєте, material designя б запропонував переглянути матеріали-діалоги . Для мене виправлено декілька проблем, пов’язаних із відкритими в даний час помилками Android (див. 78088 ), але найголовніше для цього квитка є autoDismissпрапор, який можна встановити при використанні Builder.


1

Використовуйте спеціальний макет для свого DialogFragmentі додайте LinearLayoutвміст під своїм вмістом, який можна оформити як без полів, щоб відповідати Google Material Design. Потім знайдіть новостворені кнопки та замініть їх OnClickListener.

Приклад:

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>

Це кінцевий результат.


0

Його можна побудувати найпростішим способом:

Діалогове вікно сповіщення за допомогою власного перегляду та двох кнопок (позитивні та негативні).

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 з Positive Баттона з оповіщення 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
        }

    }
}

Зроблено


-1

Це, мабуть, дуже пізня відповідь, але використання setCancelable зробить свою справу.

alertDial.setCancelable(false);

10
З документів: "Встановлює, чи буде це діалогове вікно відмінено клавішею НАЗАД." Це не має нічого спільного з позитивною кнопкою відхилення діалогу ..
clauziere

3
Не працює для мене, все ж відхиляючи, натиснувши позитивну кнопку
Hugo

1
Це не має нічого спільного з ОП
MatPag

1
Не стосується питання
Кевін Крейн
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.