Диалоговое окно Android, держите диалог открытым, когда кнопка нажата.

Я хотел бы оставить мой диалог открытым, когда я нажимаю кнопку. На данный момент он закрывается.

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

builder.setMessage("Are you sure you want to exit?")

   .setCancelable(false)
   .setPositiveButton("Yes", new DialogInterface.OnClickListener() {
       public void onClick(DialogInterface dialog, int id) {
            MyActivity.this.finish();
       }
   })
   .setNegativeButton("No", new DialogInterface.OnClickListener() {
       public void onClick(DialogInterface dialog, int id) {
            dialog.cancel();
       }
   });
AlertDialog alert = builder.create();

Ответ 1

Да, вы можете. Вам в основном нужно:

  • Создайте диалог с DialogBuilder
  • Показать() диалог
  • Найдите кнопки в показанном диалоговом окне и переопределите их onClickListener

Итак, создайте класс слушателя:

class CustomListener implements View.OnClickListener {
  private final Dialog dialog;

  public CustomListener(Dialog dialog) {
    this.dialog = dialog;
  }

  @Override
  public void onClick(View v) {

    // Do whatever you want here

    // If you want to close the dialog, uncomment the line below
    //dialog.dismiss();
  }
}

Затем при показе диалога используйте:

AlertDialog dialog = dialogBuilder.create();
dialog.show();
Button theButton = dialog.getButton(DialogInterface.BUTTON_POSITIVE);
theButton.setOnClickListener(new CustomListener(dialog));

Помните, что вам нужно показать диалог, иначе кнопка не будет доступна. Кроме того, обязательно измените DialogInterface.BUTTON_POSITIVE на любое значение, которое вы использовали для добавления кнопки. Также обратите внимание, что при добавлении кнопок в DialogBuilder вам нужно предоставить onClickListeners - вы не можете добавить туда пользовательский прослушиватель, однако - диалог все равно будет упущен, если вы не переопределите слушателей после show().

Ответ 2

Спасибо Sogger за ваш ответ, но есть одно изменение, которое мы должны сделать здесь, то есть перед созданием диалогового окна мы должны установить в качестве традиционного способа опциональную кнопку (и отрицательную кнопку, если есть необходимость) в AlertDialog.

Ссылка на Sogger.

Вот пример примера...

AlertDialog.Builder builder = new AlertDialog.Builder(this);
        builder.setMessage("Test for preventing dialog close");
        builder.setTitle("Test");

        builder.setPositiveButton("OK", new OnClickListener() {

            @Override
            public void onClick(DialogInterface dialog, int which) {
                // TODO Auto-generated method stub

            }
        });
    builder.setNegativeButton("Cancel", new OnClickListener() {

            @Override
            public void onClick(DialogInterface dialog, int which) {
                // TODO Auto-generated method stub

            }
        });

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

        dialog.getButton(AlertDialog.BUTTON_NEGATIVE).setOnClickListener(new View.OnClickListener()
          {            
              @Override
              public void onClick(View v)
              {
                  Boolean wantToCloseDialog = true;
                  //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.
              }
          });

Ответ 3

Я считаю, что ответ byKamen верен, вот пример того же подхода, который использует анонимный класс, поэтому он все в одном потоке кода:

AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
builder.setMessage("Test for preventing dialog close");
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)
                  dismiss();
              //else dialog stays open. Make sure you have an obvious way to close the dialog especially if you set cancellable to false.
          }
      });

Я написал более подробную запись, чтобы ответить на тот же вопрос здесь fooobar.com/questions/13601/..., который также имеет примеры для других диалогов, таких как DialogFragment и DialogPreference.

Ответ 4

Вот как мне удается создать постоянное всплывающее окно при смене пароля.

// Login Activity
AlertDialog.Builder alert = new AlertDialog.Builder(this);
alert.SetIcon(Resource.Drawable.padlock);
alert.SetCancelable(false);

var changepass = LayoutInflater.From(this);
var changePassLayout = changepass.Inflate(Resource.Layout.ChangePasswordLayout, null);

alert.SetView(changePassLayout);

txtChangePassword = (EditText)changePassLayout.FindViewById(Resource.Id.txtChangePassword);
txtChangeRetypePassword = (EditText)changePassLayout.FindViewById(Resource.Id.txtChangeRetypePassword);

alert.SetPositiveButton("Change", delegate {
    // You can leave this blank because you override the OnClick event using your custom listener
});

alert.SetNegativeButton("Cancel", delegate {
    Toast.MakeText(this, "Change password aborted!", ToastLength.Short).Show();
});

AlertDialog changePassDialog = alert.Create();
changePassDialog.Show();

// Override OnClick of Positive Button
Button btnPositive = changePassDialog.GetButton((int)Android.Content.DialogButtonType.Positive);
btnPositive.SetOnClickListener(new CustomListener(changePassDialog, empDetailsToValidate.EmployeeID));

// My Custom Class
class CustomListener : Java.Lang.Object, View.IOnClickListener, IDialogInterfaceOnDismissListener
{
    AlertDialog _dialog;
    EditText txtChangePassword;
    EditText txtChangeRetypePassword;

    EmployeeDetails _empDetails;
    string _workingEmployeeID;

    public CustomListener(AlertDialog dialog, string employeeID)
    {
        this._dialog = dialog;
        this._workingEmployeeID = employeeID;
    }
    public void OnClick (View v)
    {
        _empDetails = new EmployeeDetails(v.Context);

        txtChangePassword = (EditText)_dialog.FindViewById (Resource.Id.txtChangePassword);
        txtChangeRetypePassword = (EditText)_dialog.FindViewById (Resource.Id.txtChangeRetypePassword);

        if (!(txtChangePassword.Text.Equals(txtChangeRetypePassword.Text))) {
            Show ();
            Toast.MakeText(v.Context, "Password not match.", ToastLength.Short).Show();
        } else if (txtChangePassword.Text.Trim().Length < 6) {
            Show ();
            Toast.MakeText(v.Context, "Minimum password length is 6 characters.", ToastLength.Short).Show();
        } else if ((txtChangePassword.Text.Equals(LoginActivity.defaultPassword)) || (txtChangePassword.Text == "" || txtChangeRetypePassword.Text == "")) {
            Show ();
            Toast.MakeText(v.Context, "Invalid password. Please use other password.", ToastLength.Short).Show();
        } else {
            int rowAffected = _empDetails.UpdatePassword(_workingEmployeeID, SensoryDB.PassCrypto(txtChangePassword.Text, true));
            if (rowAffected > 0) {
                Toast.MakeText(v.Context, "Password successfully changed!", ToastLength.Short).Show();
                _dialog.Dismiss();
            } else {
                Toast.MakeText(v.Context, "Cant update password!", ToastLength.Short).Show();
                Show();
            }
        }
    }
    public void OnDismiss (IDialogInterface dialog)
    {
        if (!(txtChangePassword.Text.Equals (txtChangePassword.Text))) {
            Show ();
        } else {
            _dialog.Dismiss();
        }
    }
    public void Show ()
    {
        _dialog.Show ();
    }
}

Кстати, я использую Mono для Android, а не Eclipse.

Ответ 5

Вам, вероятно, нужно будет определить свой собственный макет, а не использовать "официальные" кнопки; поведение, о котором вы просите, не типично для диалога.

Ответ 6

Вы можете получить диалоговое окно, возвращаемое из метода show() alertBuidler.

AlertDialog.Builder adb = new AlertDialog.Builder(YourActivity.this);
//...code to add methods setPositive an setNegative buttons

Вызвать метод show() "adb" и получить диалоговое окно

final AlertDialog dialog = adb.show();

Таким образом, вы можете вызвать любую кнопку своего диалога в любой точке кода в своей деятельности:

dialog.getButton(DialogInterface.BUTTON_POSITIVE).performClick();//or
dialog.getButton(DialogInterface.BUTTON_NEGATIVE).performClick();//or
dialog.getButton(DialogInterface.BUTTON_NEUTRAL).performClick();

Ответ 7

Вам не нужно создавать пользовательский класс. Вы можете зарегистрировать View.OnClickListener для AlertDialog. Этот слушатель не отклонит AlertDialog. Трюк здесь заключается в том, что вам нужно зарегистрировать слушателя после того, как было показано диалоговое окно, но его можно аккуратно выполнить внутри OnShowListener. Вы можете использовать вспомогательную логическую переменную, чтобы проверить, было ли это уже сделано, чтобы она выполнялась только один раз:

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

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

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

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