113

I have a PopupWindow on my activity, the thing is my PopupWindow still shows even when I'm interacting with my activity (say scrolling on my list). I can scroll through my list and the PopupWindow is still there.

What I want to achieve is when I'm touching/scrolling/clicking/etc on the screen which is not the PopupWindow, I want to dismiss the PopupWindow. Just like how a menu works. If you clicked outside of the menu, the menu will be dismissed.

I've tried setOutsideTouchable(true) but it won't dismiss the window. Thanks.

Charles
  • 50,943
  • 13
  • 104
  • 142
lorraine batol
  • 6,001
  • 16
  • 55
  • 114

15 Answers15

138

Please try to set setBackgroundDrawable on PopupWindow that should close the window if you touch outside of it.

W4R10CK
  • 5,502
  • 2
  • 19
  • 30
Marcin S.
  • 11,161
  • 6
  • 50
  • 63
  • but this is not a dialog though, it's a PopupWindow – lorraine batol Sep 02 '12 at 01:40
  • 5
    I have missed it. Are you using setBackgroundDrawable on your popupWindow? I know that setting the background drawable to null kills the OnTouchListener – Marcin S. Sep 02 '12 at 01:58
  • You got it. Setting the backgroundDrawable works. You might want to edit your answer, so I can mark it as accepted. :) Thanks pal. – lorraine batol Sep 02 '12 at 02:06
  • 34
    thats it! thnx man! in this case, even touch events can be handled properly. 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() + " | event: "+event.getAction()); popupWindow.dismiss(); return true; } }); – Yilmaz Guleryuz Feb 05 '13 at 15:27
  • 3
    Setting background drawable to null does not work for me. If anyone else has issues, see my answer. – mpellegr Jul 31 '13 at 15:33
  • Getting "Attempted to finish an input event but the input event receiver has already been disposed." Any fix? – Georgian Benetatos Sep 23 '14 at 08:12
  • 2
    @WareNinja , your comment worked! Maybe you would better leave an entire answeir to this quesiton, it would be useful for others – Anton Kizema Mar 03 '15 at 18:08
  • 4
    @WareNinja `BitmapDrawable()` is depricated. Use `ColorDrawable()` instead. – Srujan Barai Nov 18 '15 at 17:40
  • 1
    @guleryuz, its dismissed popup but its click out side view also... How to prevent click on outside view at the time of dismissing popup.??? – AndyBoy Aug 02 '16 at 14:56
  • All these doesn't work for me. I have set background, I have set all touchable and focusable. It is still there – Cyph3rCod3r Jun 21 '17 at 07:07
138

I found that none of the answers supplied worked for me, except WareNinja's comment on the accepted answer, and Marcin S.'s will probably also work. Here's the part that works for me:

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

Alternatively:

myPopupWindow.setFocusable(true);

Not sure what the differences are, but the ListPopupWindow source code actually uses the latter when it's modality is set to true with setModal, so at least the Android developers consider this a viable approach, and it's only one line.

mpellegr
  • 3,072
  • 3
  • 22
  • 36
  • 6
    Thank you so much. None of the other answers worked for me or explained it well enough. The second option isn't working for me though. – JDN Aug 17 '13 at 05:27
  • 2
    Also I note that BitmapDrawable is deprecated. It would be nice to have a real solution to the problem, as these look like temporary workaround not guaranteed to be supported in newer API versions. – HAL9000 Dec 09 '13 at 14:09
  • 1
    to not use BitmapDrawable deprecated constructor, refer to here: http://stackoverflow.com/a/21680637/2048266. popupWindow.setBackgroundDrawable(new BitmapDrawable(getResources(), "")); – nommer Mar 18 '14 at 21:58
  • While using the alternative method of `setFocusable`, we need to click the button twice (where the button is placed outside the pop-up) where as in the 1st method it works fine :) – Joy Rex Jul 21 '15 at 08:57
  • `BitmapDrawable()` is depricated. Use `ColorDrawable()` instead. – Srujan Barai Nov 18 '15 at 17:38
  • Be sure to add this code before showing your popoupWindow – snersesyan Dec 14 '17 at 14:35
69

I met the same issues, and fixed it as below codes. It works fine for me.

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

BTW, Don't use BitmapDrawable deprecated constructor, use this new ColorDrawable(android.R.color.transparent) to replace default background.

Have fun@.@

Ion Aalbers
  • 7,830
  • 3
  • 37
  • 50
Luna Kong
  • 3,065
  • 25
  • 20
25

I know it's late but I notice that people still have an issue with the popup window. I have decided to write a fully working example where you can dismiss the popup window by touching or clicking outside of it or just touching the window itself. To do so create a new PopupWindow class and copy this 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);
   }
}

Now create the layout for the popup window: 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>      

In your main activity create an instance of the PopupWindow class:

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

where YOUR_MAIN_LAYOUT is the layout of the current activity in which popupWindow will pop up

Marcin S.
  • 11,161
  • 6
  • 50
  • 63
  • 1
    Thanks - this worked for me. Just one small note is to rather use another name other than PopupWindow for your custom class, maybe call it MyPopupWindow instead of Popupwindow so that android doesn't get confused between your its standard android class and your custom class. – Simon Aug 08 '15 at 10:42
  • @Marcin S. findViewById(R.id.YOUR_MAIN_LAYOUT) ?? Will it be R.layout.My_Layout – Ankesh kumar Jaisansaria May 04 '16 at 16:21
  • @Simon findViewById(R.id.YOUR_MAIN_LAYOUT) ?? Will it be R.layout.My_Layout ? – Ankesh kumar Jaisansaria May 04 '16 at 16:22
17

Thanks for @LunaKong's answer and @HourGlass's confirmation. I don't want to make a duplicated comment, but only want to make it clear and concise.

// 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
  • 3,780
  • 1
  • 23
  • 24
  • I wanted to be able to close the popup window by clicking outside of it, but when I did, views underneath it (not part of the popup window, but part of the activity) were being clicked. setFocusabl(true) was what I was looking for. Thanks! – hellaandrew Aug 16 '18 at 06:15
  • @hellaandrew, glad it helps you, :) – Nguyen Tan Dat Aug 16 '18 at 09:32
10

For a ListPopupWindow set the window to be a modal when shown.

mListPopupWindow.setModal(true);

That way, clicking outside of the ListPopupWindow will dismiss it.

Etienne Lawlor
  • 6,817
  • 18
  • 77
  • 89
  • Thanks, I was just looking out for this. This not only sets listpopupwindow dismissable after touching outside the view, but also does not pass the touch event to other views which are beside the listpopwindow. I was desperately looking for this as in my case touching outside listpopwindow was passing the event to recyclerview which was beneath it beside dismissing listpopupwindow, and recyclerview item was getting selected which I did not want. – shankar_vl Jul 04 '19 at 12:04
  • You may also need `mListPopupWindow.setInputMethodMode(PopupWindow.INPUT_METHOD_NOT_NEEDED);`, to prevent the popup window interfering with the on-screen keyboard. – Mr-IDE Aug 19 '19 at 19:08
7

Notice that for canceling with popupWindow.setOutsideTouchable(true), you need to make width and height wrap_content like below code:

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);
thehennyy
  • 4,020
  • 1
  • 22
  • 31
Hadi Note
  • 1,386
  • 17
  • 16
6

You can use isOutsideTouchable OR isFocusable to dissmiss popup window when touch outside

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

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

Note

  • Currently, after test I see setBackgroundDrawable don't help us dismiss popupwindow

  • If you look at the code for dismiss in PopupWindow (PopupWindow->PopupDecorView->dispatchKeyEvent and PopupWindow->PopupDecorView->onTouchEvent). You will see that when press back button, they dismiss on ACTION_UP and when touch outside they dismiss on ACTION_UP or ACTION_OUTSIDE

Linh
  • 57,942
  • 23
  • 262
  • 279
5
mPopWindow.setFocusable(true);
Muhammad Aamir Ali
  • 20,419
  • 10
  • 66
  • 57
  • 1
    This is the only thing required. I don't understand why the accepted answer is so heavily upvoted. – sziraqui Jan 07 '19 at 17:43
5
  popupWindow.setTouchable(true);
  popupWindow.setFocusable(true);
  popupWindow.showAtLocation(popupView, Gravity.CENTER, 0, 0);

It will dismiss the PopupWindow when click/touch on screen.Make sure you have set focusable true before showAtLocation.

android
  • 441
  • 1
  • 5
  • 17
4

@LunaKong suggestion work's like a charm.

But setting up mPopupWindow.setFocusable(false). removes unnecessary touch required to make popup window disappear.

For example: Let's consider there is a pop up window visible on screen, and you are about to click a button. So in this case, (if mpopwindow.setFocusable(true)) on the first click of a button popupwindow will dismiss. But you have to click again to make the button works. if**(mpopwindwo.setFocusable(false)** single click of button dismiss the popup window as well as trigger the button click. Hope it helps.

HourGlass
  • 1,805
  • 1
  • 15
  • 29
4

In some cases making the popup focusable is not desirable (e.g. you may not want it to steal focus from another view).

An alternative approach is using a touch interceptor:

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
  • 8,998
  • 3
  • 30
  • 41
3

Set the window background transparent:

PopupWindow.getBackground().setAlpha(0);

After it set your background in layout. Works fine.

CJBS
  • 15,147
  • 6
  • 86
  • 135
amak
  • 93
  • 1
  • 7
1

If this Popup Window is another activity,and you decreased its size to the original screen and you want to enable or disable the outside area.you can simply enable or disable the outside area by this code:

enable:

YourActivity.this.setFinishOnTouchOutside(true);

disable:

YourActivity.this.setFinishOnTouchOutside(false);

0

Use View popupView to dismiss the popupWindow

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

` If you use this you can also setOnClickListener to any button inside the popupWindow

Elletlar
  • 3,136
  • 7
  • 32
  • 38