PopupWindow - Descartar cuando se hace clic fuera


93

Tengo un PopupWindow en mi actividad, lo que pasa es que mi PopupWindow todavía se muestra incluso cuando estoy interactuando con mi actividad (por ejemplo, desplazándome por mi lista). Puedo desplazarme por mi lista y PopupWindow sigue ahí.

Lo que quiero lograr es cuando estoy tocando / desplazándome / haciendo clic / etc en la pantalla que no es PopupWindow, quiero descartar la PopupWindow. Como funciona un menú. Si hizo clic fuera del menú, el menú se cerrará.

Lo intenté, setOutsideTouchable(true)pero no cerrará la ventana. Gracias.

Respuestas:


129

Por favor trate de conjunto setBackgroundDrawableen PopupWindowel cual se cierra la ventana si se toca fuera de ella.


5
Lo he echado de menos. ¿Está utilizando setBackgroundDrawable en su ventana emergente? Sé que configurar el diseño de fondo en nulo mata al OnTouchListener
Marcin S.

31
¡Eso es! gracias hombre! en este caso, incluso los eventos táctiles se pueden manejar correctamente. popupWindow.setOutsideTouchable (verdadero); popupWindow.setTouchable (verdadero); popupWindow.setBackgroundDrawable (nuevo BitmapDrawable ()); popupWindow.setTouchInterceptor (new OnTouchListener () {@Override public boolean onTouch (View v, evento MotionEvent) {if (AppContext.isDebugMode ()) Log.d ("POPUP_WINDOW", "v:" + v.getTag () + " | evento: "+ event.getAction ()); popupWindow.dismiss (); devuelve verdadero;}});
Beerstorm

3
Establecer el diseño de fondo en nulo no me funciona. Si alguien más tiene problemas, vea mi respuesta.
mpellegr

2
@WareNinja, ¡tu comentario funcionó! Tal vez sea mejor que deje una respuesta completa a esta pregunta, sería útil para otros
Anton Kizema

3
@WareNinja BitmapDrawable()está depurado. Úselo en su ColorDrawable()lugar.
Srujan Barai

125

Descubrí que ninguna de las respuestas proporcionadas me funcionó, excepto el comentario de WareNinja sobre la respuesta aceptada, y el de Marcin S. probablemente también funcione. Aquí está la parte que me funciona:

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

Alternativamente:

myPopupWindow.setFocusable(true);

No estoy seguro de cuáles son las diferencias, pero el código fuente de ListPopupWindow en realidad usa este último cuando su modalidad se establece en verdadera con setModal, por lo que al menos los desarrolladores de Android consideran que este es un enfoque viable, y es solo una línea.


6
Muchas gracias. Ninguna de las otras respuestas funcionó para mí o lo explicó lo suficientemente bien. Sin embargo, la segunda opción no me funciona.
JDN

2
También observo que BitmapDrawable está en desuso. Sería bueno tener una solución real al problema, ya que parecen una solución temporal que no se garantiza que sea compatible con las versiones más recientes de la API.
HAL9000

para no utilizar el constructor obsoleto BitmapDrawable, consulte aquí: stackoverflow.com/a/21680637/2048266 . popupWindow.setBackgroundDrawable (nuevo BitmapDrawable (getResources (), ""));
nommer

Mientras usamos el método alternativo de setFocusable, debemos hacer clic en el botón dos veces (donde el botón se coloca fuera de la ventana emergente) donde, como en el primer método, funciona bien :)
Joy Rex

BitmapDrawable()esta depricada. Úselo en su ColorDrawable()lugar.
Srujan Barai

60

Me encontré con los mismos problemas y los solucioné como los siguientes códigos. Funciona bien para mí.

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

Por cierto, no use el constructor obsoleto BitmapDrawable, use este nuevo ColorDrawable (android.R.color.transparent) para reemplazar el fondo predeterminado.

Que te diviertas@.@


3
Asegúrese de agregar este código antes de mostrar su ventana emergente
snersesyan

¿Realmente necesito establecer focusable en verdadero si la ventana emergente no necesita enfoque?
Levor

Me sorprende que esto funcione, pero es necesario en la API 21. Esto también solucionó que mi ventana emergente se animaba incorrectamente.
EpicPandaForce

24

Sé que es tarde, pero noto que la gente todavía tiene problemas con la ventana emergente. He decidido escribir un ejemplo completamente funcional en el que puede descartar la ventana emergente tocando o haciendo clic fuera de ella o simplemente tocando la ventana misma. Para hacerlo, cree una nueva clase PopupWindow y copie este código:

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

Ahora cree el diseño para la ventana emergente: 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>      

En su actividad principal, cree una instancia de la clase PopupWindow:

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

donde YOUR_MAIN_LAYOUT es el diseño de la actividad actual en la que popupWindow aparecerá


1
Gracias, esto funcionó para mí. Solo una pequeña nota es preferir usar otro nombre que no sea PopupWindow para su clase personalizada, quizás llamarlo MyPopupWindow en lugar de Popupwindow para que Android no se confunda entre su clase estándar de Android y su clase personalizada.
Simon

@Marcin S. findViewById (R.id.YOUR_MAIN_LAYOUT) ?? Will it be R.layout.My_Layout
Ankesh kumar Jaisansaria

@Simon findViewById (R.id.YOUR_MAIN_LAYOUT) ?? ¿Será R.layout.My_Layout?
Ankesh kumar Jaisansaria

15

Gracias por la respuesta de @ LunaKong y la confirmación de @ HourGlass. No quiero hacer un comentario duplicado, solo quiero que sea claro y 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.


Quería poder cerrar la ventana emergente haciendo clic fuera de ella, pero cuando lo hice, se hizo clic en las vistas debajo de ella (no parte de la ventana emergente, sino parte de la actividad). setFocusabl (verdadero) era lo que estaba buscando. ¡Gracias!
hellaandrew

@hellaandrew, me alegro de que te ayude :)
Nguyen Tan Dat

8

Para ListPopupWindowestablecer la ventana para que sea modal cuando se muestra.

mListPopupWindow.setModal(true);

De esa forma, al hacer clic fuera de la ListPopupWindowse descartará.


Gracias, solo estaba pendiente de esto. Esto no solo establece listpopupwindow descartable después de tocar fuera de la vista, sino que tampoco pasa el evento táctil a otras vistas que están al lado de listpopwindow. Estaba buscando desesperadamente esto, ya que en mi caso, tocar fuera de listpopwindow estaba pasando el evento a la vista de reciclaje que estaba debajo de él, al lado de descartar listpopupwindow, y el elemento de vista de reciclaje se estaba seleccionando, lo que no quería.
shankar_vl

Es posible que también lo necesite mListPopupWindow.setInputMethodMode(PopupWindow.INPUT_METHOD_NOT_NEEDED);para evitar que la ventana emergente interfiera con el teclado en pantalla.
Mr-IDE

6

Tenga en cuenta que para cancelar con popupWindow.setOutsideTouchable(true), debe hacer el ancho y el alto wrap_contentcomo el siguiente código:

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

Descartará PopupWindow cuando haga clic / toque en la pantalla. Asegúrese de haber establecido focusable verdadero antes de showAtLocation.


1
Agregue un texto explicativo para explicar cómo esto proporciona una respuesta precisa a la pregunta formulada. Gracias.
filantrovertido

¡Gracias! Debe llamar a los establecedores antes de llamar a showAtLocation ().
droid256

5

Puedes usar isOutsideTouchable OR isFocusable para descartar la ventana emergente cuando toque afuera

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

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

Nota

  • Actualmente, después de la prueba veo setBackgroundDrawable que no nos ayudan a descartar la ventana emergente

  • Si observa el código para descartar en PopupWindow( PopupWindow->PopupDecorView->dispatchKeyEventy PopupWindow->PopupDecorView->onTouchEvent). Verá que cuando presionan el botón Atrás, se desconectan ACTION_UPy cuando se tocan afuera, se desconectan en ACTION_UPoACTION_OUTSIDE


4
mPopWindow.setFocusable(true);

1
Esto es lo único que se requiere. No entiendo por qué la respuesta aceptada tiene tantos votos a favor.
sziraqui

4

El trabajo de sugerencia de @LunaKong es como un encanto.

Pero configurando mPopupWindow.setFocusable (false). elimina el toque innecesario necesario para hacer desaparecer la ventana emergente.

Por ejemplo: consideremos que hay una ventana emergente visible en la pantalla y está a punto de hacer clic en un botón. Entonces, en este caso, (si mpopwindow.setFocusable (true)) en el primer clic de un botón, la ventana emergente se cerrará. Pero debe hacer clic nuevamente para que el botón funcione. if ** (mpopwindwo.setFocusable (false) ** un solo clic del botón descarta la ventana emergente y activa el clic del botón . Espero que ayude.


1
¡Muchas gracias! Estaba buscando exactamente lo mismo
Ganesh

3

Establezca el fondo de la ventana transparente:

PopupWindow.getBackground().setAlpha(0);

Después de configurar su fondo en el diseño. Funciona bien.


1
getBackground () podría ser nulo.
Jared Rummler

1

En algunos casos, hacer que la ventana emergente se pueda enfocar no es deseable (por ejemplo, es posible que no desee que robe el enfoque de otra vista).

Un enfoque alternativo es usar un interceptor táctil:

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

1

Si esta ventana emergente es otra actividad, y disminuyó su tamaño a la pantalla original y desea habilitar o deshabilitar el área exterior, simplemente puede habilitar o deshabilitar el área exterior con este código:

habilitar:

YourActivity.this.setFinishOnTouchOutside(true);

inhabilitar:

YourActivity.this.setFinishOnTouchOutside(false);


0

Use Ver popupView para cerrar la ventana emergente

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

`Si usa esto, también puede establecerOnClickListener en cualquier botón dentro de la ventana emergente

Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.