Wie kann ich den Dialog mit einem Klick außerhalb des Dialogs schließen?

156

Ich habe einen benutzerdefinierten Dialog für meine Anwendung implementiert. Ich möchte implementieren, dass der Dialog geschlossen wird, wenn der Benutzer außerhalb des Dialogfelds klickt. Was muss ich dafür tun?

Shreyash Mahajan
quelle

Antworten:

356

Sie können verwenden dialog.setCanceledOnTouchOutside(true);, um den Dialog zu schließen, wenn Sie außerhalb des Dialogs berühren.

Etwas wie,

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

Oder wenn Ihr Dialog dann nicht modelliert ist,

1 - Setzen Sie das Flag FLAG_NOT_TOUCH_MODALfür das Fensterattribut Ihres Dialogfelds

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

2 - Fügen Sie den Windows-Eigenschaften ein weiteres Flag hinzu. FLAG_WATCH_OUTSIDE_TOUCH- Dieses Flag dient zum Empfangen von Berührungsereignissen außerhalb des sichtbaren Bereichs.

3 - onTouchEvent()Dialog überschreiben und nach Aktionstyp suchen. Wenn der Aktionstyp ' MotionEvent.ACTION_OUTSIDE' bedeutet, interagiert der Benutzer außerhalb des Dialogbereichs. In diesem Fall können Sie Ihren Dialog verkleinern oder entscheiden, was Sie ausführen möchten. Klartext anzeigen?

public boolean onTouchEvent(MotionEvent event)  
{  

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

Weitere Informationen finden Sie unter So schließen Sie ein benutzerdefiniertes Dialogfeld basierend auf Berührungspunkten. und So schließen Sie Ihren nicht modalen Dialog, wenn Sie ihn außerhalb des Dialogbereichs berühren

user370305
quelle
9
Dies funktioniert hervorragend, außer dass die Aktivität darunter auch auf das Berührungsereignis reagiert. Gibt es eine Möglichkeit, dies zu verhindern?
Howettl
Ja. window.setFlags (WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL, WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL); verursacht dieses Problem. Ich habe unten eine Lösung gepostet :)
Unknownweirdo
Ist es möglich, "On-Touch-Outside" -Ereignisse auch über einen nicht benutzerdefinierten Dialog an die darunter liegende Aktivität weiterzugeben?
JC
1
@howettl Ich habe Ihr Problem in meiner Lösung gelöst, die ich unten gepostet habe, wo ich keine Flags auf Fenster setzen muss.
Roman Nazarevych
@MuhammedRefaat - Bitte schauen Sie sich diesen Thread groups.google.com/forum/#!topic/android-developers/VhaiIMl6E_w an . Sie haben es gut beschrieben.
user370305
18

Einfach benutzen

dialog.setCanceledOnTouchOutside(true);
Ebin Sebastian
quelle
Ich weiß, dass dies die richtige Antwort sein sollte, funktioniert aber bei mir nicht und ich weiß einfach nicht warum.
IgniteCoders
16

Sie können diese Implementierung von onTouchEvent verwenden. Es verhindert, dass unter Aktivität auf das Berührungsereignis reagiert wird (wie bereits erwähnt).

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

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

Lukas Novak
quelle
9

Wenn Sie den Dialog mit einem in Ihrer XML-Stil definierten Thema anpassen, fügen Sie diese Zeile in Ihr Thema ein:

<item name="android:windowCloseOnTouchOutside">true</item>
Chris.Zou
quelle
Dies funktioniert bei Samsung Galaxy Tab 2 WiFi nicht. dialog.setCanceledOnTouchOutside(true);funktioniert wunderbar.
Doplumi
7
dialog.setCanceledOnTouchOutside(true); 

um den Dialog bei Berührung außerhalb zu schließen.

Und wenn Sie bei Berührung außerhalb nicht schließen möchten, verwenden Sie den folgenden Code:

dialog.setCanceledOnTouchOutside(false);
Naveen
quelle
6

Diese Methode sollte Aktivitäten unterhalb des grauen Bereichs, bei denen Klickereignisse abgerufen werden, vollständig vermeiden.

Entfernen Sie diese Zeile, wenn Sie es haben:

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

Setzen Sie dies auf Ihre erstellte Aktivität

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

Überschreiben Sie dann das Berührungsereignis damit

@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);
}
Unbekannter Weirdo
quelle
4

Sie können dies versuchen: -

AlterDialog alterdialog;
alertDialog.setCanceledOnTouchOutside(true);

oder

alertDialog.setCancelable(true);

Und wenn Sie eine haben AlterDialog.Builder, können Sie dies versuchen: -

alertDialogBuilder.setCancelable(true);
Julfikar
quelle
4

Dieser Code wird verwendet, wenn Sie beim Klicken auf das Dialogfeld klicken, um die Eingabe zu verbergen, und wenn der Benutzer zu diesem Zeitpunkt auf die Außenseite des Dialogfelds klickt, wenn sowohl die Soft-Eingabe als auch das Dialogfeld geschlossen sind.

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
quelle
2

Eine andere Lösung, dieser Code wurde aus dem Android-Quellcode von Window Sie sollten nur diese beiden Methoden zu Ihrem Dialog-Quellcode hinzufügen.

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

Diese Lösung hat dieses Problem nicht:

Dies funktioniert hervorragend, außer dass die Aktivität darunter auch auf das Berührungsereignis reagiert. Gibt es eine Möglichkeit, dies zu verhindern? - Howettl

Roman Nazarevych
quelle
Können Sie Ihren Dialog nicht einfach modal berühren, wenn Sie nicht möchten, dass andere Fenster Ereignisse empfangen?
1

Anruf dialog.setCancelable(false);von Ihrer Aktivität / Fragment.

EKN
quelle
1

Folgendes hat bei mir funktioniert:

myDialog.setCanceledOnTouchOutside(true);
Akanshi Srivastava
quelle
0

Sie können die backgroundgesamte Bildschirmgröße belegen transparentund das onClickEreignis anhören dismiss.

Oriolpons
quelle
10
Sehr schlechte Antwort! Natürlich kann dies getan werden, aber bitte machen Sie es richtig!
JC
-1

Hier ist der 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;
        }
    });

Probier diese . Sie können die Tastatur ausblenden, wenn Sie draußen berühren

Saljith Kj
quelle