PopupWindow: ignora quando si fa clic all'esterno


93

Ho una PopupWindow sulla mia attività, il fatto è che la mia PopupWindow viene ancora visualizzata anche quando sto interagendo con la mia attività (ad esempio scorrendo la mia lista). Posso scorrere la mia lista e PopupWindow è ancora lì.

Quello che voglio ottenere è quando tocco / scorro / faccio clic su / ecc. Sullo schermo che non è la Finestra Popup, voglio chiudere la Finestra Popup. Proprio come funziona un menu. Se hai fatto clic al di fuori del menu, il menu verrà ignorato.

Ho provato setOutsideTouchable(true)ma non chiude la finestra. Grazie.

Risposte:


129

Si prega di provare a impostare setBackgroundDrawablesu PopupWindowche dovrebbe chiudere la finestra se si tocca all'esterno di essa.


5
L'ho perso. Stai usando setBackgroundDrawable nella tua finestra popup? So che l'impostazione dello sfondo disegnabile su null uccide OnTouchListener
Marcin S.

31
questo è tutto! grazie uomo! in questo caso, anche gli eventi di tocco possono essere gestiti correttamente. popupWindow.setOutsideTouchable (true); popupWindow.setTouchable (true); popupWindow.setBackgroundDrawable (new BitmapDrawable ()); popupWindow.setTouchInterceptor (new OnTouchListener () {@Override public boolean onTouch (View v, MotionEvent event) {if (AppContext.isDebugMode ()) Log.d ("POPUP_WINDOW", "v:" + v.getTag () + " | evento: "+ event.getAction ()); popupWindow.dismiss (); return true;}});
tempesta di pioggia

3
L'impostazione di sfondo drawable su null non funziona per me. Se qualcun altro ha problemi, vedere la mia risposta.
mpellegr

2
@WareNinja, il tuo commento ha funzionato! Forse faresti meglio a lasciare un'intera risposta a questa domanda, sarebbe utile per gli altri
Anton Kizema

3
@WareNinja BitmapDrawable()è deprecato . Usa ColorDrawable()invece.
Srujan Barai

125

Ho scoperto che nessuna delle risposte fornite ha funzionato per me, tranne il commento di WareNinja sulla risposta accettata, e probabilmente funzionerà anche quella di Marcin S. Ecco la parte che funziona per me:

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

In alternativa:

myPopupWindow.setFocusable(true);

Non sono sicuro di quali siano le differenze, ma il codice sorgente di ListPopupWindow utilizza effettivamente quest'ultimo quando la sua modalità è impostata su true con setModal, quindi almeno gli sviluppatori Android considerano questo un approccio praticabile, ed è solo una riga.


6
Grazie mille. Nessuna delle altre risposte ha funzionato per me o l'ha spiegato abbastanza bene. La seconda opzione però non funziona per me.
JDN

2
Inoltre noto che BitmapDrawable è deprecato. Sarebbe bello avere una vera soluzione al problema, in quanto sembrano soluzioni temporanee non garantite per essere supportate nelle versioni API più recenti.
HAL9000

per non utilizzare il costruttore deprecato BitmapDrawable, fare riferimento a qui: stackoverflow.com/a/21680637/2048266 . popupWindow.setBackgroundDrawable (new BitmapDrawable (getResources (), ""));
nommer

Durante l'utilizzo del metodo alternativo di setFocusable, dobbiamo fare clic due volte sul pulsante (dove il pulsante è posizionato all'esterno del popup) dove come nel primo metodo funziona bene :)
Joy Rex

BitmapDrawable()è deprecato. Usa ColorDrawable()invece.
Srujan Barai

59

Ho riscontrato gli stessi problemi e l'ho risolto come sotto i codici. Funziona bene per me.

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

BTW, non utilizzare il costruttore deprecato BitmapDrawable, usa questo nuovo ColorDrawable (android.R.color.transparent) per sostituire lo sfondo predefinito.

Divertiti@.@


3
Assicurati di aggiungere questo codice prima di mostrare il tuo popoupWindow
snersesyan

Ho davvero bisogno di impostare focusable su true se il popup non necessita di focus?
Levor

Sono stupito che funzioni, ma è richiesto dall'API 21. Ciò ha anche risolto il fatto che la mia finestra popup si animava in modo errato.
EpicPandaForce

24

So che è tardi, ma noto che le persone hanno ancora problemi con la finestra popup. Ho deciso di scrivere un esempio completamente funzionante in cui è possibile chiudere la finestra popup toccando o facendo clic all'esterno di essa o semplicemente toccando la finestra stessa. Per farlo, crea una nuova classe PopupWindow e copia questo codice:

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

Ora crea il layout per la finestra popup: 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>      

Nella tua attività principale crea un'istanza della classe PopupWindow:

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

dove YOUR_MAIN_LAYOUT è il layout dell'attività corrente in cui apparirà popupWindow


1
Grazie - questo ha funzionato per me. Solo una piccola nota è piuttosto usare un altro nome diverso da PopupWindow per la tua classe personalizzata, magari chiamalo MyPopupWindow invece di Popupwindow in modo che Android non si confonda tra la tua classe Android standard e la tua classe personalizzata.
Simon

@Marcin S. findViewById (R.id.YOUR_MAIN_LAYOUT) ?? Sarà R.layout.My_Layout
Ankesh kumar Jaisansaria

@Simon findViewById (R.id.YOUR_MAIN_LAYOUT) ?? Sarà R.layout.My_Layout?
Ankesh kumar Jaisansaria

15

Grazie per la risposta di @ LunaKong e la conferma di @ HourGlass. Non voglio fare un commento duplicato, ma voglio solo renderlo chiaro e conciso.

// 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.


Volevo poter chiudere la finestra popup facendo clic all'esterno di essa, ma quando l'ho fatto, le visualizzazioni sottostanti (non parte della finestra popup, ma parte dell'attività) sono state cliccate. setFocusabl (true) era quello che stavo cercando. Grazie!
hellaandrew

@hellaandrew, felice che ti aiuti, :)
Nguyen Tan Dat

8

Per un ListPopupWindowset la finestra deve essere un modale quando viene mostrata.

mListPopupWindow.setModal(true);

In questo modo, facendo clic al di fuori di ListPopupWindowverrà chiuso.


Grazie, stavo solo cercando questo. Questo non solo imposta listpopupwindow in modo da essere ignorato dopo aver toccato al di fuori della visualizzazione, ma non passa nemmeno l'evento tocco ad altre visualizzazioni che sono accanto alla listpopwindow. Lo stavo cercando disperatamente perché nel mio caso toccare fuori dalla finestra listpop stava passando l'evento a recyclerview che era sotto di essa accanto a chiudere listpopupwindow, e veniva selezionato l'elemento recyclerview che non volevo.
shankar_vl

Potrebbe anche essere necessario mListPopupWindow.setInputMethodMode(PopupWindow.INPUT_METHOD_NOT_NEEDED);, per evitare che la finestra popup interferisca con la tastiera su schermo.
Mr-IDE

6

Si noti che per annullare con popupWindow.setOutsideTouchable(true), è necessario creare larghezza e altezza wrap_contentcome il codice seguente:

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

5
  popupWindow.setTouchable(true);
  popupWindow.setFocusable(true);
  popupWindow.showAtLocation(popupView, Gravity.CENTER, 0, 0);

Chiuderà la finestra Popup quando si fa clic / tocco sullo schermo.Assicurati di aver impostato focusable true prima di showAtLocation.


1
Si prega di aggiungere del testo esplicativo per elaborare come questo fornisce una risposta accurata alla domanda posta. Grazie.
philantrovert

Grazie! È necessario chiamare i setter prima di chiamare showAtLocation ().
droid256

5

È possibile utilizzare isOutsideTouchable OR isFocusable per chiudere la finestra popup quando si tocca all'esterno

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

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

Nota

  • Attualmente, dopo il test vedo setBackgroundDrawable che non ci aiuta a chiudere la finestra popup

  • Se guardi il codice per ignorare in PopupWindow( PopupWindow->PopupDecorView->dispatchKeyEvente PopupWindow->PopupDecorView->onTouchEvent). Vedrai che quando premi il pulsante Indietro, si chiudono ACTION_UPe quando tocchi fuori si chiudono su ACTION_UPoACTION_OUTSIDE


4

Il lavoro di suggerimento di @LunaKong è come un fascino.

Ma l'impostazione di mPopupWindow.setFocusable (false). rimuove il tocco non necessario necessario per far scomparire la finestra popup.

Ad esempio: si consideri che sullo schermo è presente una finestra popup e si sta per fare clic su un pulsante. Quindi, in questo caso, (se mpopwindow.setFocusable (true)) al primo clic di un pulsante la finestra popup verrà chiusa. Ma devi fare di nuovo clic per far funzionare il pulsante. se ** (mpopwindwo.setFocusable (false) ** clic singolo del pulsante ignora la finestra popup e attiva il clic del pulsante. Spero che aiuti.


1
Grazie mille Stavo esattamente cercando lo stesso
Ganesh

3
mPopWindow.setFocusable(true);

Questa è l'unica cosa richiesta. Non capisco perché la risposta accettata sia così fortemente votata.
sziraqui

3

Imposta lo sfondo della finestra trasparente:

PopupWindow.getBackground().setAlpha(0);

Dopo aver impostato lo sfondo nel layout. Funziona bene.


1
getBackground () potrebbe essere nullo.
Jared Rummler

1

In alcuni casi rendere il popup attivabile non è desiderabile (ad esempio potresti non volere che rubi il focus da un'altra vista).

Un approccio alternativo utilizza un intercettore tattile:

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

0

Usa Visualizza popupView per chiudere la finestra popup

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

`Se lo usi, puoi anche impostareOnClickListener su qualsiasi pulsante all'interno della finestra popup

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.