弹出窗口-单击外部时解除

我有一个弹出窗口在我的活动,事情是我的弹出窗口仍然显示,即使当我与我的活动(说滚动在我的列表)。我可以滚动我的列表,弹出窗口仍然存在。

我想要实现的是,当我在屏幕上触摸/滚动/点击/等,而不是弹出窗口,我想取消弹出窗口。就像菜单一样。如果你点击了菜单之外,菜单将被解散。

我试过 setOutsideTouchable(true),但它无法关闭窗口。谢谢。

95899 次浏览

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

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

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.

mPopWindow.setFocusable(true);

Set the window background transparent:

PopupWindow.getBackground().setAlpha(0);

After it set your background in layout. Works fine.

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.

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

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

  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.

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

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

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.

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

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

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