Comment fermer la boîte de dialogue en cliquant en dehors de la boîte de dialogue?

156

J'ai implémenté une boîte de dialogue personnalisée pour mon application. Je veux implémenter que lorsque l'utilisateur clique en dehors de la boîte de dialogue, la boîte de dialogue sera fermée. Que dois-je faire pour cela?

Shreyash Mahajan
la source

Réponses:

356

Vous pouvez utiliser dialog.setCanceledOnTouchOutside(true);ce qui fermera la boîte de dialogue si vous touchez en dehors de la boîte de dialogue.

Quelque chose comme,

  Dialog dialog = new Dialog(context)
  dialog.setCanceledOnTouchOutside(true);

Ou si votre boîte de dialogue n'est pas un modèle alors,

1 - Définissez le drapeau- FLAG_NOT_TOUCH_MODALpour l'attribut de fenêtre de votre boîte de dialogue

Window window = this.getWindow();
window.setFlags(WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL,
WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL);

2 - Ajoutez un autre drapeau aux propriétés de Windows ,, FLAG_WATCH_OUTSIDE_TOUCH- celui-ci est pour que le dialogue reçoive un événement tactile en dehors de sa région visible.

3 - Remplacer la onTouchEvent()boîte de dialogue et vérifier le type d'action. si le type d'action est « MotionEvent.ACTION_OUTSIDE» signifie que l'utilisateur interagit en dehors de la zone de dialogue. Donc, dans ce cas, vous pouvez fermer votre boîte de dialogue ou décider de ce que vous souhaitez effectuer. voir le papier ordinaire?

public boolean onTouchEvent(MotionEvent event)  
{  

       if(event.getAction() == MotionEvent.ACTION_OUTSIDE){  
        System.out.println("TOuch outside the dialog ******************** ");  
               this.dismiss();  
       }  
       return false;  
}  

Pour plus d'informations, consultez Comment fermer une boîte de dialogue personnalisée basée sur les points de contact? et Comment fermer votre boîte de dialogue non modale, lorsqu'elle est touchée en dehors de la zone de dialogue

user370305
la source
9
Cela fonctionne très bien, sauf que l'activité en dessous réagit également à l'événement tactile. Y a-t-il un moyen d'éviter cela?
howettl
Ouais. window.setFlags (WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL, WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL); provoque ce problème. J'ai posté une solution ci-dessous :)
Unknownweirdo
Est-il possible de propager des événements «au contact de l'extérieur» à l'activité sous-jacente en utilisant également une boîte de dialogue non personnalisée?
jc
1
@howettl J'ai résolu votre problème dans ma solution que j'ai publiée ci-dessous où je n'ai pas besoin de définir d'indicateur sur window.
Roman Nazarevych
@MuhammedRefaat - Veuillez consulter ce fil de discussion groups.google.com/forum/#!topic/android-developers/VhaiIMl6E_w . Ils l'ont bien décrit.
user370305
18

Utilisez simplement

dialog.setCanceledOnTouchOutside(true);
Ebin Sebastian
la source
Je sais que cela devrait être la bonne réponse, mais cela ne fonctionne pas pour moi, et je ne sais tout simplement pas pourquoi.
IgniteCoders
16

Vous pouvez utiliser cette implémentation de onTouchEvent. Il empêche de réagir sous l'activité à l'événement tactile (comme mentionné howettl).

@Override
public boolean onTouchEvent ( MotionEvent event ) {
  // I only care if the event is an UP action
  if ( event.getAction () == MotionEvent.ACTION_UP ) {
    // create a rect for storing the window rect
    Rect r = new Rect ( 0, 0, 0, 0 );
    // retrieve the windows rect
    this.getWindow ().getDecorView ().getHitRect ( r );
    // check if the event position is inside the window rect
    boolean intersects = r.contains ( (int) event.getX (), (int) event.getY () );
    // if the event is not inside then we can close the activity
    if ( !intersects ) {
      // close the activity
      this.finish ();
      // notify that we consumed this event
      return true;
    }
  }
  // let the system handle the event
  return super.onTouchEvent ( event );
}

Source: http://blog.twimager.com/2010/08/closing-activity-by-touching-outside.html

Lukas Novak
la source
9

Ou, si vous personnalisez la boîte de dialogue à l'aide d'un thème défini dans votre style xml, mettez cette ligne dans votre thème:

<item name="android:windowCloseOnTouchOutside">true</item>
Chris.Zou
la source
Cela ne fonctionne pas pour moi sur Samsung Galaxy Tab 2 WiFi. dialog.setCanceledOnTouchOutside(true);fonctionne à merveille.
doplumi
7
dialog.setCanceledOnTouchOutside(true); 

pour fermer le dialogue au toucher à l'extérieur.

Et si vous ne voulez pas fermer au toucher à l'extérieur, utilisez le code ci-dessous:

dialog.setCanceledOnTouchOutside(false);
Naveen
la source
6

Cette méthode doit complètement éviter les activités sous la zone grise de récupération des événements de clic.

Supprimez cette ligne si vous l'avez:

window.setFlags(WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL, WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL);

Mettez ceci sur votre activité créée

getWindow().setFlags(LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH, LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH);

puis écraser l'événement tactile avec ce

@Override
public boolean onTouchEvent(MotionEvent ev)
{
    if(MotionEvent.ACTION_DOWN == ev.getAction())
    {
        Rect dialogBounds = new Rect();
        getWindow().getDecorView().getHitRect(dialogBounds);
        if (!dialogBounds.contains((int) ev.getX(), (int) ev.getY())) {
            // You have clicked the grey area
            displayYourDialog();
            return false; // stop activity closing
        }
    }

    // Touch events inside are fine.
    return super.onTouchEvent(ev);
}
Inconnu
la source
4

Vous pouvez essayer ceci: -

AlterDialog alterdialog;
alertDialog.setCanceledOnTouchOutside(true);

ou

alertDialog.setCancelable(true);

Et si vous avez un AlterDialog.Builderalors vous pouvez essayer ceci: -

alertDialogBuilder.setCancelable(true);
Julfikar
la source
4

Ce code est utilisé lors de l'utilisation, cliquez sur la boîte de dialogue pour masquer l'entrée logicielle et lorsque l'utilisateur clique sur le côté extérieur de la boîte de dialogue, lorsque l'entrée logicielle et la boîte de dialogue sont fermées.

dialog = new Dialog(act) {
    @Override
    public boolean onTouchEvent(MotionEvent event) {
        // Tap anywhere to close dialog.
        Rect dialogBounds = new Rect();
        getWindow().getDecorView().getHitRect(dialogBounds);
        if (!dialogBounds.contains((int) event.getX(),
                (int) event.getY())) {
            // You have clicked the grey area
            InputMethodManager inputMethodManager = (InputMethodManager) act
                    .getSystemService(act.INPUT_METHOD_SERVICE);
            inputMethodManager.hideSoftInputFromWindow(dialog
                    .getCurrentFocus().getWindowToken(), 0);
            dialog.dismiss();
            // stop activity closing
        } else {
            InputMethodManager inputMethodManager = (InputMethodManager) act
                    .getSystemService(act.INPUT_METHOD_SERVICE);
            inputMethodManager.hideSoftInputFromWindow(dialog
                    .getCurrentFocus().getWindowToken(), 0);
        }

        return true;
    }
};
Maulik Santoki
la source
2

Une autre solution, ce code a été tiré du code source Android de Window Vous devez simplement ajouter ces deux méthodes au code source de votre boîte de dialogue.

@Override
public boolean onTouchEvent(MotionEvent event) {        
    if (isShowing() && (event.getAction() == MotionEvent.ACTION_DOWN
            && isOutOfBounds(getContext(), event) && getWindow().peekDecorView() != null)) {
        hide();
    }
    return false;
}

private boolean isOutOfBounds(Context context, MotionEvent event) {
    final int x = (int) event.getX();
    final int y = (int) event.getY();
    final int slop = ViewConfiguration.get(context).getScaledWindowTouchSlop();
    final View decorView = getWindow().getDecorView();
    return (x < -slop) || (y < -slop)
            || (x > (decorView.getWidth()+slop))
            || (y > (decorView.getHeight()+slop));
}

Cette solution n'a pas ce problème:

Cela fonctionne très bien, sauf que l'activité en dessous réagit également à l'événement tactile. Y a-t-il un moyen d'éviter cela? - hurlement

Roman Nazarevych
la source
Ne pouvez-vous pas simplement rendre votre boîte de dialogue modale si vous ne voulez pas que d'autres fenêtres reçoivent des événements?
1

Appelez dialog.setCancelable(false);depuis votre activité / fragment.

EKN
la source
1

La suite a fonctionné pour moi:

myDialog.setCanceledOnTouchOutside(true);
Akanshi Srivastava
la source
0

Vous pouvez faire un backgroundoccupant toute la taille de l'écran transparentet écouter l' onClickévénement dismiss.

oriolpons
la source
10
Très mauvaise réponse! Bien sûr, cela peut être fait, mais faites-le de la bonne façon!
jc
-1

Voici le code

    dialog.getWindow().getDecorView().setOnTouchListener(new View.OnTouchListener() {
        @Override
        public boolean onTouch(View v, MotionEvent ev) {

            if(MotionEvent.ACTION_DOWN == ev.getAction())
            {
                Rect dialogBounds = new Rect();
                dialog. getWindow().getDecorView().getHitRect(dialogBounds);
                if (!dialogBounds.contains((int) ev.getX(), (int) ev.getY())) {
                    // You have clicked the grey area
                    UiUtils.hideKeyboard2(getActivity());
                    return false; // stop activity closing
                }
            }
            getActivity().dispatchTouchEvent(ev);
            return false;
        }
    });

Essaye celui-là . vous pouvez masquer le clavier lorsque vous touchez l'extérieur

Saljith Kj
la source