PopupWindow - Wird geschlossen, wenn außerhalb geklickt wird

93

Ich habe ein PopupWindow für meine Aktivität. Mein PopupWindow wird auch dann noch angezeigt, wenn ich mit meiner Aktivität interagiere (z. B. Scrollen in meiner Liste). Ich kann durch meine Liste scrollen und das PopupWindow ist immer noch da.

Was ich erreichen möchte, ist, wenn ich auf dem Bildschirm, der nicht das PopupWindow ist, berühre / scrolle / klicke / usw., möchte ich das PopupWindow schließen. Genau wie ein Menü funktioniert. Wenn Sie außerhalb des Menüs geklickt haben, wird das Menü geschlossen.

Ich habe es versucht, setOutsideTouchable(true)aber es wird das Fenster nicht schließen. Vielen Dank.

Dorfbewohner
quelle

Antworten:

129

Bitte versuchen Sie es zu Satz setBackgroundDrawableauf PopupWindowdas sollte das Fenster schließen , wenn Sie außerhalb davon berühren.

Marcin S.
quelle
5
Ich habe es vermisst. Verwenden Sie setBackgroundDrawable in Ihrem Popup-Fenster? Ich weiß, dass das Setzen des Hintergrunds auf Null den OnTouchListener
Marcin S.
31
das ist es! Danke Mann! In diesem Fall können sogar Berührungsereignisse ordnungsgemäß behandelt werden. popupWindow.setOutsideTouchable (true); popupWindow.setTouchable (true); popupWindow.setBackgroundDrawable (neues BitmapDrawable ()); popupWindow.setTouchInterceptor (neuer OnTouchListener () {@Override public boolean onTouch (View v, MotionEvent-Ereignis) {if (AppContext.isDebugMode ()) Log.d ("POPUP_WINDOW", "v:" + v.getTag () + " | event: "+ event.getAction ()); popupWindow.dismiss (); return true;}});
Guleryuz
3
Das Setzen des Hintergrunds zum Zeichnen auf Null funktioniert bei mir nicht. Wenn jemand andere Probleme hat, siehe meine Antwort.
mpellegr
2
@WareNinja, dein Kommentar hat funktioniert! Vielleicht sollten Sie dieser Frage eine ganze Antwort überlassen, sie wäre für andere nützlich
Anton Kizema
3
@WareNinja BitmapDrawable()ist beraubt. Verwenden Sie ColorDrawable()stattdessen.
Srujan Barai
125

Ich stellte fest, dass keine der Antworten für mich funktionierte, außer WareNinjas Kommentar zur akzeptierten Antwort, und Marcin S. wird wahrscheinlich auch funktionieren. Hier ist der Teil, der für mich funktioniert:

myPopupWindow.setBackgroundDrawable(new BitmapDrawable());
myPopupWindow.setOutsideTouchable(true);

Alternative:

myPopupWindow.setFocusable(true);

Ich bin mir nicht sicher, was die Unterschiede sind, aber der ListPopupWindow-Quellcode verwendet letzteres tatsächlich, wenn seine Modalität mit setModal auf true gesetzt ist. Zumindest die Android-Entwickler halten dies für einen praktikablen Ansatz, und es ist nur eine Zeile.

mpellegr
quelle
6
Ich danke dir sehr. Keine der anderen Antworten hat für mich funktioniert oder es gut genug erklärt. Die zweite Option funktioniert bei mir allerdings nicht.
JDN
2
Außerdem stelle ich fest, dass BitmapDrawable veraltet ist. Es wäre schön, eine echte Lösung für das Problem zu haben, da diese wie eine vorübergehende Problemumgehung aussehen, die in neueren API-Versionen nicht garantiert unterstützt wird.
HAL9000
Informationen zum Veralten des veralteten BitmapDrawable-Konstruktors finden Sie hier: stackoverflow.com/a/21680637/2048266 . popupWindow.setBackgroundDrawable (neues BitmapDrawable (getResources (), ""));
Nommer
Bei Verwendung der alternativen Methode von setFocusablemüssen wir zweimal auf die Schaltfläche klicken (wobei die Schaltfläche außerhalb des Popups platziert ist), wo sie wie bei der ersten Methode einwandfrei funktioniert :)
Joy Rex
BitmapDrawable()ist beraubt. Verwenden Sie ColorDrawable()stattdessen.
Srujan Barai
59

Ich habe die gleichen Probleme festgestellt und sie wie unten beschrieben behoben. Es funktioniert gut für mich.

    // Closes the popup window when touch outside.
    mPopupWindow.setOutsideTouchable(true);
    mPopupWindow.setFocusable(true);
    // Removes default background.
    mPopupWindow.setBackgroundDrawable(new ColorDrawable(Color.TRANSPARENT));

Übrigens, verwenden Sie keinen veralteten BitmapDrawable-Konstruktor. Verwenden Sie dieses neue ColorDrawable (android.R.color.transparent) , um den Standardhintergrund zu ersetzen.

Habe Spaß@.@

Luna Kong
quelle
3
Stellen Sie sicher, dass Sie diesen Code hinzufügen, bevor Sie Ihre popoupWindow
snersesyan
Muss ich wirklich focusable auf true setzen, wenn Popup keinen Fokus benötigt?
Levor
Ich bin erstaunt, dass dies funktioniert, aber es ist für API 21 erforderlich. Dadurch wurde auch behoben, dass mein Popup-Fenster falsch animiert wurde.
EpicPandaForce
24

Ich weiß, dass es spät ist, aber ich stelle fest, dass die Leute immer noch ein Problem mit dem Popup-Fenster haben. Ich habe beschlossen, ein voll funktionsfähiges Beispiel zu schreiben, in dem Sie das Popup-Fenster schließen können, indem Sie es berühren oder darauf klicken oder einfach das Fenster selbst berühren. Erstellen Sie dazu eine neue PopupWindow-Klasse und kopieren Sie diesen Code:

PopupWindow.class

public class PopupWindow extends android.widget.PopupWindow
{
Context ctx;
Button btnDismiss;
TextView lblText;
View popupView;

public PopupWindow(Context context)
{
    super(context);

    ctx = context;
    popupView = LayoutInflater.from(context).inflate(R.layout.popup, null);
    setContentView(popupView);

    btnDismiss = (Button)popupView.findViewById(R.id.btn_dismiss);
    lblText = (TextView)popupView.findViewById(R.id.text);

    setHeight(WindowManager.LayoutParams.WRAP_CONTENT);
    setWidth(WindowManager.LayoutParams.WRAP_CONTENT);

    // Closes the popup window when touch outside of it - when looses focus
    setOutsideTouchable(true);
    setFocusable(true);

    // Removes default black background
    setBackgroundDrawable(new BitmapDrawable());

    btnDismiss.setOnClickListener(new Button.OnClickListener(){

        @Override
        public void onClick(View v) {


         dismiss();
        }});

    // Closes the popup window when touch it
/*     this.setTouchInterceptor(new View.OnTouchListener() {

        @Override
        public boolean onTouch(View v, MotionEvent event) {

            if (event.getAction() == MotionEvent.ACTION_MOVE) {
                dismiss();
            }
            return true;
        }
    }); */   
   } // End constructor

   // Attaches the view to its parent anchor-view at position x and y
   public void show(View anchor, int x, int y)
   {
      showAtLocation(anchor, Gravity.CENTER, x, y);
   }
}

Erstellen Sie nun das Layout für das Popup-Fenster: popup.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout     
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:layout_margin="1dp"
    android:orientation="vertical"
    android:padding="10dp" >

<TextView 
    android:id="@+id/text" 
    android:layout_width="wrap_content" 
    android:layout_height="wrap_content"  
    android:gravity="center" 
    android:padding="5dp" 
    android:text="PopupWindow Example"
    android:textColor="#000000" 
    android:textSize="17sp" 
    android:textStyle="italic" />

<FrameLayout
    android:layout_width="match_parent" 
    android:layout_height="wrap_content" 
    android:layout_gravity="center_vertical">

    <Button
        android:id="@+id/btn_dismiss" 
        style="?android:attr/buttonStyleSmall" 
        android:layout_width="wrap_content" 
        android:layout_height="wrap_content" 
        android:text="Dismiss" 
        android:visibility="gone" />

    <TextView
        android:id="@+id/lbl_dismiss"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:gravity="center"
        android:text="Touch outside of this box to dismiss"
        android:textColor="#ffffff"
        android:textStyle="bold" />

</FrameLayout>      

Erstellen Sie in Ihrer Hauptaktivität eine Instanz der PopupWindow-Klasse:

final PopupWindow popupWindow = new PopupWindow(this);
popupWindow.show(findViewById(R.id.YOUR_MAIN_LAYOUT), 0, -250);

Dabei ist YOUR_MAIN_LAYOUT das Layout der aktuellen Aktivität, in der popupWindow angezeigt wird

Marcin S.
quelle
1
Danke - das hat bei mir funktioniert. Nur eine kleine Anmerkung ist, lieber einen anderen Namen als PopupWindow für Ihre benutzerdefinierte Klasse zu verwenden. Nennen Sie ihn möglicherweise MyPopupWindow anstelle von Popupwindow, damit Android nicht zwischen Ihrer Standard-Android-Klasse und Ihrer benutzerdefinierten Klasse verwechselt wird.
Simon
@Marcin S. findViewById (R.id.YOUR_MAIN_LAYOUT) ?? Wird es R.layout.My_Layout sein
Ankesh Kumar Jaisansaria
@ Simon findViewById (R.id.YOUR_MAIN_LAYOUT) ?? Wird es R.layout.My_Layout sein?
Ankesh Kumar Jaisansaria
15

Vielen Dank für die Antwort von @ LunaKong und die Bestätigung von @ HourGlass. Ich möchte keinen doppelten Kommentar abgeben, sondern nur klar und prägnant.

// Closes the popup window when touch outside. This method was written informatively in Google's docs.
mPopupWindow.setOutsideTouchable(true);

// Set focus true to prevent a touch event to go to a below view (main layout), which works like a dialog with 'cancel' property => Try it! And you will know what I mean.
mPopupWindow.setFocusable(true);

// Removes default background.
mPopupWindow.setBackgroundDrawable(new ColorDrawable(Color.TRANSPARENT));

Mttdat.

Nguyen Tan Dat
quelle
Ich wollte in der Lage sein, das Popup-Fenster zu schließen, indem ich außerhalb davon klickte, aber als ich dies tat, wurden Ansichten darunter (nicht Teil des Popup-Fensters, sondern Teil der Aktivität) angeklickt. setFocusabl (true) war das, wonach ich gesucht habe. Vielen Dank!
Hellaandrew
@ Hellaandrew, froh, dass es Ihnen hilft, :)
Nguyen Tan Dat
8

Für ein ListPopupWindowSet ist das Fenster modal, wenn es angezeigt wird.

mListPopupWindow.setModal(true);

Auf diese Weise wird es durch Klicken außerhalb von geschlossen ListPopupWindow.

toobsco42
quelle
Danke, ich habe nur darauf geachtet. Dadurch wird das Listenpopup-Fenster nicht nur nach Berühren außerhalb der Ansicht deaktiviert, sondern das Berührungsereignis wird auch nicht an andere Ansichten übergeben, die sich neben dem Listenpopup-Fenster befinden. Ich habe verzweifelt danach gesucht, da in meinem Fall das Berühren von außerhalb von listpopwindow das Ereignis an recyclerview weiterleitete, das sich darunter befand, und listpopupwindow geschlossen wurde, und das Element recyclerview ausgewählt wurde, das ich nicht wollte.
Shankar_vl
Möglicherweise müssen Sie auch mListPopupWindow.setInputMethodMode(PopupWindow.INPUT_METHOD_NOT_NEEDED);verhindern, dass das Popup-Fenster die Bildschirmtastatur beeinträchtigt.
Mr-IDE
6

Beachten Sie, dass Sie zum Abbrechen mit popupWindow.setOutsideTouchable(true)Breite und Höhe wrap_contentwie folgt festlegen müssen:

PopupWindow popupWindow = new PopupWindow(
            G.layoutInflater.inflate(R.layout.lay_dialog_support, null, false),
            WindowManager.LayoutParams.WRAP_CONTENT,
            WindowManager.LayoutParams.WRAP_CONTENT, true);

popupWindow.setBackgroundDrawable(new ColorDrawable(Color.TRANSPARENT));
popupWindow.setOutsideTouchable(true);
popupWindow.setFocusable(true);
popupWindow.showAtLocation(view, Gravity.RIGHT, 0, 0);
Hadi Hinweis
quelle
5
  popupWindow.setTouchable(true);
  popupWindow.setFocusable(true);
  popupWindow.showAtLocation(popupView, Gravity.CENTER, 0, 0);

Das PopupWindow wird beim Klicken / Berühren auf dem Bildschirm geschlossen. Stellen Sie vor showAtLocation sicher, dass Sie focusable true festgelegt haben.

Android
quelle
1
Bitte fügen Sie einen erläuternden Text hinzu, um zu erläutern, wie dies eine genaue Antwort auf die gestellte Frage liefert. Vielen Dank.
Philantrovert
Vielen Dank! Sie müssen die Setter aufrufen, bevor Sie showAtLocation () aufrufen.
Droid256
5

Sie können isOutsideTouchable OR verwenden isFocusable , um das Popup-Fenster zu schließen, wenn Sie außerhalb berühren

popupWindow.isOutsideTouchable = true // dismiss popupwindow when touch outside

popupWindow.isFocusable = true // dismiss popupwindow when touch outside AND when press back button

Hinweis

  • Derzeit hilft uns nach dem Test setBackgroundDrawable nicht , das Popup-Fenster zu schließen

  • Wenn Sie sich den Code für die Entlassung in PopupWindow( PopupWindow->PopupDecorView->dispatchKeyEventund PopupWindow->PopupDecorView->onTouchEvent) ansehen . Sie werden sehen, dass sie beim Drücken der Zurück-Taste am ACTION_UPund bei Berührung außerhalb am ACTION_UPoder am entlassen werdenACTION_OUTSIDE

Phan Van Linh
quelle
4

@ LunaKong Vorschlag Arbeit ist wie ein Zauber.

Aber mPopupWindow.setFocusable einrichten (false). Entfernt unnötige Berührungen, die erforderlich sind, um das Popup-Fenster verschwinden zu lassen.

Beispiel: Angenommen, auf dem Bildschirm wird ein Popup-Fenster angezeigt, und Sie klicken auf eine Schaltfläche. In diesem Fall wird Popup-Fenster (wenn mpopwindow.setFocusable (true)) beim ersten Klicken auf eine Schaltfläche geschlossen. Sie müssen jedoch erneut klicken, damit die Schaltfläche funktioniert. if ** (mpopwindwo.setFocusable (false) ** einmaliger Klick auf die Schaltfläche schließt das Popup-Fenster und löst den Klick auf die Schaltfläche aus. Ich hoffe, es hilft.

Sanduhr
quelle
1
Vielen Dank! Ich war genau auf der Suche nach dem gleichen
Ganesh
3
mPopWindow.setFocusable(true);
Muhammad Aamir Ali
quelle
Dies ist das einzige, was erforderlich ist. Ich verstehe nicht, warum die akzeptierte Antwort so stark positiv bewertet wird.
Sziraqui
3

Stellen Sie den Fensterhintergrund transparent ein:

PopupWindow.getBackground().setAlpha(0);

Danach legen Sie Ihren Hintergrund im Layout fest. Funktioniert gut.

amak
quelle
1
getBackground () könnte null sein.
Jared Rummler
1

In einigen Fällen ist es nicht wünschenswert, das Popup fokussierbar zu machen (z. B. möchten Sie möglicherweise nicht, dass es den Fokus aus einer anderen Ansicht stiehlt).

Ein alternativer Ansatz ist die Verwendung eines Touch Interceptors:

popupWindow.setOutsideTouchable(true);
popupWindow.setTouchInterceptor(new View.OnTouchListener() {
    @Override
    public boolean onTouch(View v, MotionEvent event) {
        if (event.getAction() == MotionEvent.ACTION_OUTSIDE) {
            popupWindow.dismiss();
        }
        return false;
    }
});
dev.bmax
quelle
0

Verwenden Sie View popupView, um das popupWindow zu schließen

`popupView.setOnClickListener(new View.OnClickListener() {
                   @Override
                   public void onClick(View view) {
                       popupWindow.dismiss();
                   }
               }); 

`Wenn Sie dies verwenden, können Sie OnClickListener auch auf eine beliebige Schaltfläche im Popup-Fenster setzen

Prabhat Kumar Singh
quelle