Voici quelques solutions pour tous les types de boîtes de dialogue, y compris une solution pour AlertDialog.Builder qui fonctionnera à tous les niveaux d'API (fonctionne en dessous de l'API 8, ce que l'autre réponse ici ne fait pas). Il existe des solutions pour AlertDialogs utilisant AlertDialog.Builder, DialogFragment et DialogPreference.
Vous trouverez ci-dessous des exemples de code montrant comment remplacer le gestionnaire de boutons communs par défaut et empêcher la boîte de dialogue de se fermer pour ces différentes formes de boîtes de dialogue. Tous les exemples montrent comment empêcher le bouton positif de fermer la boîte de dialogue.
Remarque: Une description du fonctionnement de la fermeture de la boîte de dialogue sous le capot pour les classes Android de base et des raisons pour lesquelles les approches suivantes sont choisies suit les exemples, pour ceux qui souhaitent plus de détails.
AlertDialog.Builder - Modifier le gestionnaire de boutons par défaut immédiatement après 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 - remplacer 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 - remplacer 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.
}
});
}
Explication des approches:
En parcourant le code source Android, l'implémentation par défaut d'AlertDialog fonctionne en enregistrant un gestionnaire de boutons commun à tous les boutons réels dans OnCreate (). Lorsqu'un bouton est cliqué, le gestionnaire de bouton commun transmet l'événement click au gestionnaire que vous avez passé dans setButton (), puis les appels rejette la boîte de dialogue.
Si vous souhaitez empêcher la fermeture d'une boîte de dialogue lorsque l'un de ces boutons est enfoncé, vous devez remplacer le gestionnaire de bouton commun pour l'affichage réel du bouton. Puisqu'il est attribué dans OnCreate (), vous devez le remplacer après l'appel de l'implémentation OnCreate () par défaut. OnCreate est appelé dans le processus de la méthode show (). Vous pouvez créer une classe Dialog personnalisée et remplacer OnCreate () pour appeler le super.OnCreate () puis remplacer les gestionnaires de boutons, mais si vous créez une boîte de dialogue personnalisée, vous n'obtenez pas le générateur gratuitement, auquel cas quel est le point ?
Ainsi, en utilisant une boîte de dialogue de la manière dont elle est conçue mais en contrôlant quand elle est fermée, une approche consiste à appeler dialog.Show () d'abord, puis à obtenir une référence au bouton à l'aide de dialog.getButton () pour remplacer le gestionnaire de clics. Une autre approche consiste à utiliser setOnShowListener () et à implémenter la recherche de la vue de bouton et le remplacement du gestionnaire dans OnShowListener. La différence fonctionnelle entre les deux est «presque» nulle, selon le thread qui crée à l'origine l'instance de dialogue. En parcourant le code source, onShowListener est appelé par un message publié sur un gestionnaire s'exécutant sur le thread qui a créé cette boîte de dialogue. Ainsi, puisque votre OnShowListener est appelé par un message publié dans la file d'attente de messages, il est techniquement possible que l'appel de votre écouteur soit retardé quelque temps après la fin de l'émission.
Par conséquent, je crois que l'approche la plus sûre est la première: appeler show.Dialog (), puis immédiatement dans le même chemin d'exécution remplacer les gestionnaires de boutons. Étant donné que votre code qui appelle show () fonctionnera sur le thread principal de l'interface graphique, cela signifie que le code que vous suivez show () sera exécuté avant tout autre code sur ce thread, tandis que le timing de la méthode OnShowListener est à la merci de la file d'attente de messages.