web-dev-qa-db-fra.com

Comment fermer le dialogue en cliquant sur en dehors du dialogue?

J'ai implémenté un dialogue personnalisé pour mon application. Je veux implémenter que lorsque l'utilisateur clique en dehors de la boîte de dialogue, celle-ci sera fermée.

137
iDroid Explorer

Vous pouvez utiliser dialog.setCanceledOnTouchOutside(true); qui ferme 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 dialogue est non-modèle alors,

1 - Définissez l'indicateur -FLAG_NOT_TOUCH_MODAL pour 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 - Ajouter un autre indicateur aux propriétés de Windows, FLAG_WATCH_OUTSIDE_TOUCH - celui-ci sert à la boîte de dialogue pour recevoir un événement tactile en dehors de sa zone visible.

3 - Remplacez onTouchEvent() de la boîte de dialogue et vérifiez 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. Ainsi, dans ce cas, vous pouvez modifier votre dialogue ou décider de ce que vous voulez exécuter.

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 des points de contact? and Comment fermer votre dialogue non modal lorsqu'il est touché en dehors de la zone de dialogue

327
user370305

Vous pouvez utiliser cette implémentation de onTouchEvent. Cela empêche de réagir sous l’activité à l’événement tactile (comme mentionné précédemment).

@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

16
Lukas Novak

Simplement utiliser 

dialog.setCanceledOnTouchOutside(true);
14
Ebin Sebastian

Ou, si vous personnalisez le dialogue en utilisant un thème défini dans votre style xml, insérez cette ligne dans votre thème:

<item name="Android:windowCloseOnTouchOutside">true</item>
9
Chris.Zou
dialog.setCanceledOnTouchOutside(true); 

pour fermer le dialogue sur contact extérieur.

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

dialog.setCanceledOnTouchOutside(false);
6
Naveen

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

Supprimer 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 écrasez l'événement tactile avec cette

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

Vous pouvez essayer ceci: -

AlterDialog alterdialog;
alertDialog.setCanceledOnTouchOutside(true);

ou

alertDialog.setCancelable(true);

Et si vous avez un AlterDialog.Builder Ensuite, vous pouvez essayer ceci: -

alertDialogBuilder.setCancelable(true);
4
Mohammad Julfikar

Ce code est utilisé lorsque, lorsque vous utilisez, cliquez sur la boîte de dialogue indiquant l’heure du transfert, et lorsque l’utilisateur clique sur le côté extérieur de la boîte de dialogue, ce qui signifie que les deux entrées logiques et logicielles 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;
    }
};
2
Maulik Santoki

Une autre solution, ce code a été coupé 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'empêcher cela? - comment

2
Lemberg

Appelez dialog.setCancelable(false); à partir de votre activité/fragment.

0
EKN

Vous pouvez créer une background occupant toute la taille d'écran transparent et écouter l'événement onClick en dismiss.

0
oriolpons