Oto niektóre rozwiązania dla wszystkich typów okien dialogowych, w tym rozwiązanie dla AlertDialog.Builder, które będzie działać na wszystkich poziomach API (działa poniżej API 8, czego druga odpowiedź tutaj nie robi). Istnieją rozwiązania dla AlertDialogs za pomocą AlertDialog.Builder, DialogFragment i DialogPreference.
Poniżej znajdują się przykłady kodu pokazujące, jak zastąpić domyślną procedurę obsługi przycisków wspólnych i zapobiec zamknięciu okna dialogowego dla tych różnych form okien dialogowych. Wszystkie przykłady pokazują, jak zapobiec zamykaniu okna dialogowego przez przycisk dodatni.
Uwaga: opis działania zamknięcia okna dialogowego pod maską dla podstawowych klas Androida i dlaczego wybrano następujące podejścia po przykładach dla tych, którzy chcą więcej szczegółów
AlertDialog.Builder - Zmień domyślną procedurę obsługi przycisków natychmiast po 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 - przesłonięcie 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 - przesłonięcie 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.
}
});
}
Wyjaśnienie podejść:
Przeglądając kod źródłowy Androida, domyślna implementacja AlertDialog działa poprzez rejestrację wspólnej procedury obsługi przycisków dla wszystkich rzeczywistych przycisków w OnCreate (). Po kliknięciu przycisku wspólny moduł obsługi przycisku przekazuje zdarzenie click do dowolnego modułu obsługi przekazanego w setButton (), a następnie wywołuje zamknięcie okna dialogowego.
Jeśli chcesz uniemożliwić zamknięcie okna dialogowego po naciśnięciu jednego z tych przycisków, musisz zastąpić zwykłą procedurę obsługi przycisków dla rzeczywistego widoku przycisku. Ponieważ jest on przypisany w OnCreate (), należy go zastąpić po wywołaniu domyślnej implementacji OnCreate (). Funkcja OnCreate jest wywoływana w procesie metody show (). Możesz utworzyć niestandardową klasę Dialog i przesłonić OnCreate (), aby wywołać funkcję super.OnCreate (), a następnie przesłonić procedury obsługi przycisków, ale jeśli utworzysz niestandardowe okno dialogowe, nie otrzymasz Konstruktora za darmo, w takim przypadku o co chodzi ?
Tak więc, używając okna dialogowego tak, jak zostało zaprojektowane, ale kontrolując, kiedy jest ono usuwane, jednym z podejść jest wywołanie dialog.Show (), a następnie uzyskanie odwołania do przycisku za pomocą dialog.getButton () w celu zastąpienia modułu obsługi kliknięć. Innym podejściem jest użycie setOnShowListener () i implementacja znajdowania widoku przycisku i zastępowania modułu obsługi w OnShowListener. Różnica funkcjonalna między nimi to „prawie” zero, w zależności od tego, który wątek oryginalnie tworzy instancję okna dialogowego. Przeglądając kod źródłowy, onShowListener zostaje wywołany przez komunikat wysłany do modułu obsługi działającego w wątku, który utworzył to okno dialogowe. Tak więc, ponieważ Twój OnShowListener jest wywoływany przez wiadomość umieszczoną w kolejce komunikatów, technicznie możliwe jest, że wywołanie twojego odbiornika zostanie opóźnione po pewnym czasie po zakończeniu pokazu.
Dlatego uważam, że najbezpieczniejszym podejściem jest pierwsze: wywołać show.Dialog (), a następnie natychmiast w tej samej ścieżce wykonania zastąpić procedury obsługi przycisków. Ponieważ kod wywołujący metodę show () będzie działał w głównym wątku GUI, oznacza to, że dowolny kod, po którym następuje show (), zostanie wykonany przed jakimkolwiek innym kodem w tym wątku, podczas gdy czas metody OnShowListener jest na łasce kolejka wiadomości.