PopupWindow - Dispensar quando clicado fora

93

Eu tenho uma PopupWindow em minha atividade, o que acontece é que minha PopupWindow ainda é exibida mesmo quando estou interagindo com minha atividade (digamos, rolando em minha lista). Posso rolar minha lista e a PopupWindow ainda está lá.

O que eu quero alcançar é quando estou tocando / rolando / clicando / etc na tela que não é a PopupWindow, eu quero descartar a PopupWindow. Exatamente como funciona um menu. Se você clicou fora do menu, o menu será descartado.

Já tentei, setOutsideTouchable(true)mas não fecha a janela. Obrigado.

aldeão
fonte

Respostas:

129

Por favor, tente conjunto setBackgroundDrawableem PopupWindowque deve fechar a janela se você tocar fora dela.

Marcin S.
fonte
5
Eu perdi isso. Você está usando setBackgroundDrawable em seu popupWindow? Eu sei que definir o drawable do plano de fundo como null mata o OnTouchListener
Marcin S.
31
é isso aí! thnx man! neste caso, até mesmo eventos de toque podem ser tratados adequadamente. popupWindow.setOutsideTouchable (true); popupWindow.setTouchable (true); popupWindow.setBackgroundDrawable (new BitmapDrawable ()); popupWindow.setTouchInterceptor (new OnTouchListener () {@Override public boolean onTouch (Ver v, evento MotionEvent) {if (AppContext.isDebugMode ()) Log.d ("POPUP_WINDOW", "v:" + v.getTag () + " | evento: "+ event.getAction ()); popupWindow.dismiss (); retornar verdadeiro;}});
beerstorm de
3
Definir o drawable em segundo plano como nulo não funciona para mim. Se alguém mais tiver problemas, veja minha resposta.
mpellegr
2
@WareNinja, seu comentário funcionou! Talvez seja melhor você deixar uma resposta inteira para esta pergunta, seria útil para outros
Anton Kizema
3
@WareNinja BitmapDrawable()está obsoleto. Use em seu ColorDrawable()lugar.
Srujan Barai
125

Descobri que nenhuma das respostas fornecidas funcionou para mim, exceto o comentário do WareNinja sobre a resposta aceita, e o de Marcin S. provavelmente também funcionará. Aqui está a parte que funciona para mim:

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

Alternativamente:

myPopupWindow.setFocusable(true);

Não tenho certeza de quais são as diferenças, mas o código-fonte ListPopupWindow realmente usa o último quando sua modalidade é definida como verdadeira com setModal, então pelo menos os desenvolvedores do Android consideram esta uma abordagem viável, e é apenas uma linha.

mpellegr
fonte
6
Muito obrigado. Nenhuma das outras respostas funcionou para mim ou explicou bem o suficiente. A segunda opção não está funcionando para mim.
JDN de
2
Também observo que BitmapDrawable está obsoleto. Seria bom ter uma solução real para o problema, pois isso parece uma solução temporária sem garantia de suporte nas versões mais recentes da API.
HAL9000
para não usar o construtor obsoleto BitmapDrawable, consulte aqui: stackoverflow.com/a/21680637/2048266 . popupWindow.setBackgroundDrawable (new BitmapDrawable (getResources (), ""));
nommer
Ao usar o método alternativo de setFocusable, precisamos clicar no botão duas vezes (onde o botão é colocado fora do pop-up) onde, como no primeiro método, funciona bem :)
Joy Rex
BitmapDrawable()é depreciado. Use em seu ColorDrawable()lugar.
Srujan Barai
59

Eu encontrei os mesmos problemas e corrigi-los conforme os códigos abaixo. Isso funciona bem para mim.

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

BTW, não use o construtor obsoleto BitmapDrawable, use este novo ColorDrawable (android.R.color.transparent) para substituir o fundo padrão.

Diverta-se@.@

Luna Kong
fonte
3
Certifique-se de adicionar este código antes de mostrar seu popoupWindow
snersesyan
Eu realmente preciso definir o foco como verdadeiro se o pop-up não precisar de foco?
Levor
Estou surpreso que isso funcione, mas é necessário na API 21. Isso também corrigiu que minha janela pop-up estava animando incorretamente.
EpicPandaForce
24

Eu sei que é tarde, mas noto que as pessoas ainda têm problemas com a janela pop-up. Decidi escrever um exemplo totalmente funcional onde você pode descartar a janela pop-up tocando ou clicando fora dela ou apenas tocando na própria janela. Para fazer isso, crie uma nova classe PopupWindow e 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);
   }
}

Agora crie o layout para a janela pop-up: 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>      

Em sua atividade principal, crie uma instância da classe PopupWindow:

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

onde YOUR_MAIN_LAYOUT é o layout da atividade atual em que popupWindow aparecerá

Marcin S.
fonte
1
Obrigado - isso funcionou para mim. Apenas uma pequena observação é preferir usar outro nome diferente de PopupWindow para sua classe personalizada, talvez chamá-la de MyPopupWindow em vez de Popupwindow para que o android não se confunda entre sua classe android padrão e sua classe personalizada.
Simon
@Marcin S. findViewById (R.id.YOUR_MAIN_LAYOUT) ?? Será R.layout.My_Layout
Ankesh kumar Jaisansaria
@Simon findViewById (R.id.YOUR_MAIN_LAYOUT) ?? Será R.layout.My_Layout?
Ankesh kumar Jaisansaria
15

Obrigado pela resposta de @LunaKong e confirmação de @ HourGlass. Não quero fazer um comentário duplicado, mas apenas torná-lo claro 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.

Nguyen Tan Dat
fonte
Eu queria poder fechar a janela pop-up clicando fora dela, mas quando o fiz, as visualizações abaixo dela (não parte da janela pop-up, mas parte da atividade) estavam sendo clicadas. setFocusabl (true) era o que eu procurava. Obrigado!
hellaandrew de
@hellaandrew, que bom que ajudou você :)
Nguyen Tan Dat
8

Para ListPopupWindowdefinir a janela como modal quando exibida.

mListPopupWindow.setModal(true);

Dessa forma, clicar fora do ListPopupWindowirá dispensá-lo.

toobsco42
fonte
Obrigado, eu só estava cuidando disso. Isso não apenas define listpopupwindow descartável após tocar fora da visualização, mas também não passa o evento de toque para outras visualizações que estão ao lado da janela listpop. Eu estava procurando desesperadamente por isso, pois no meu caso tocar fora da janela listpop era passar o evento para recyclerview que estava abaixo dele, ao lado de descartar listpopupwindow, e um item de recyclerview estava sendo selecionado que eu não queria.
shankar_vl
Também pode ser necessário mListPopupWindow.setInputMethodMode(PopupWindow.INPUT_METHOD_NOT_NEEDED);evitar que a janela pop-up interfira no teclado na tela.
Mr-IDE
6

Observe que para cancelar com popupWindow.setOutsideTouchable(true), você precisa fazer largura e altura wrap_contentcomo o código abaixo:

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 Note
fonte
5
  popupWindow.setTouchable(true);
  popupWindow.setFocusable(true);
  popupWindow.showAtLocation(popupView, Gravity.CENTER, 0, 0);

Ele irá dispensar a PopupWindow quando clicar / tocar na tela. Certifique-se de definir o focusable true antes de showAtLocation.

andróide
fonte
1
Adicione algum texto explicativo para elaborar como isso fornece uma resposta precisa à pergunta feita. Obrigado.
philantrovert
Obrigado! Você precisa chamar os setters antes de chamar showAtLocation ().
droid256 de
5

Você pode usar isOutsideTouchable OU isFocusable para ignorar a janela pop-up ao tocar fora

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

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

Nota

  • Atualmente, após o teste, não vejo setBackgroundDrawable como nos ajudar a dispensar a janela pop-up

  • Se você olhar o código para dispensar em PopupWindow( PopupWindow->PopupDecorView->dispatchKeyEvente PopupWindow->PopupDecorView->onTouchEvent). Você verá que, ao pressionar o botão Voltar, eles dispensam ACTION_UPe, quando tocam externamente, dispensam ACTION_UPouACTION_OUTSIDE

Phan Van Linh
fonte
4

O trabalho de sugestões do @LunaKong é um encanto.

Mas configurando mPopupWindow.setFocusable (false). remove o toque desnecessário necessário para fazer a janela pop-up desaparecer.

Por exemplo: Vamos considerar que há uma janela pop-up visível na tela e você está prestes a clicar em um botão. Portanto, neste caso, (if mpopwindow.setFocusable (true)) no primeiro clique de um botão a janela popup será descartada. Mas você tem que clicar novamente para fazer o botão funcionar. if ** (mpopwindwo.setFocusable (false) ** um único clique no botão ignora a janela pop-up e também aciona o clique do botão. Espero que ajude.

Ampulheta
fonte
1
Muito obrigado! Eu estava exatamente procurando o mesmo
Ganesh
3
mPopWindow.setFocusable(true);
Muhammad Aamir Ali
fonte
Esta é a única coisa necessária. Não entendo por que a resposta aceita é tão votada.
sziraqui
3

Defina o fundo da janela como transparente:

PopupWindow.getBackground().setAlpha(0);

Depois de definir o plano de fundo no layout. Funciona bem.

amak
fonte
1
getBackground () pode ser nulo.
Jared Rummler
1

Em alguns casos, tornar o pop-up focalizável não é desejável (por exemplo, você pode não querer que ele roube o foco de outra visualização).

Uma abordagem alternativa é usar um interceptor de toque:

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
fonte
0

Use View popupView para dispensar a popupWindow

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

`Se você usar isso, você também pode definirOnClickListener para qualquer botão dentro da janela pop-up

Prabhat Kumar Singh
fonte