PopupWindow-在外部单击时关闭


93

我的活动上有一个PopupWindow,问题是即使我与活动进行交互(例如,滚动列表),我的PopupWindow仍然显示。我可以滚动浏览列表,而PopupWindow仍然存在。

我想要实现的是当我在非PopupWindow的屏幕上触摸/滚动/单击/等等时,我想关闭PopupWindow。就像菜单如何工作一样。如果您在菜单外单击,该菜单将被关闭。

我已经尝试过了,setOutsideTouchable(true)但不会关闭窗户。谢谢。

Answers:


129

请尝试设置setBackgroundDrawablePopupWindow,如果你触摸它的外面应该关闭该窗口。


5
我错过了。您是否在popupWindow上使用setBackgroundDrawable?我知道将可绘制背景设置为null会杀死OnTouchListener
Marcin S.

31
而已!天哪!在这种情况下,即使触摸事件也可以正确处理。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;}});
beerstorm

3
将背景可绘制设置为null不适用于我。如果其他人有问题,请参阅我的答案。
mpellegr 2013年

2
@WareNinja,您的评论起作用了!也许您最好将整个问题留给这个问题,这对其他人会很有用
Anton Kizema 2015年

3
@WareNinja BitmapDrawable()被描述。使用ColorDrawable()代替。
Srujan Barai 2015年

125

我发现,除了WareNinja对已接受答案的评论外,提供的答案都没有对我有用,Marcin S.的答案也可能适用。这是对我有用的部分:

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

或者:

myPopupWindow.setFocusable(true);

不确定差异是什么,但当setModal的modality设置为true时,ListPopupWindow源代码实际上会使用后者,因此至少Android开发人员认为这是一种可行的方法,并且只有一行。


6
非常感谢。没有其他答案对我有用或对它的解释足够好。第二个选项虽然对我不起作用。
JDN

2
我也注意到不推荐使用BitmapDrawable。真正解决该问题会很高兴,因为这些看起来似乎是临时的解决方法,不能保证在较新的API版本中也受支持。
HAL9000 2013年

要不使用不建议使用BitmapDrawable的构造函数,请参阅此处:stackoverflow.com/a/21680637/2048266。popupWindow.setBackgroundDrawable(new BitmapDrawable(getResources(),“”));
2014年

使用的替代方法时setFocusable,我们需要单击两次按钮(按钮位于弹出窗口之外),如在第一种方法中一样,它可以正常工作:)
Joy Rex 2015年

BitmapDrawable()被描述。使用ColorDrawable()代替。
Srujan Barai 2015年

59

我遇到了同样的问题,并将其修复为以下代码。这对我来说可以。

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

顺便说一句,不要使用不建议使用BitmapDrawable的构造函数,请使用此新的ColorDrawable(android.R.color.transparent)替换默认背景。

玩得开心@。@


3
确保显示您popoupWindow前添加以下代码
snersesyan

如果弹出窗口不需要焦点,我真的需要将focusable设置为true吗?
Levor

我对此感到惊讶,但API 21要求这样做。这也解决了我的弹出窗口动画不正确的问题。
EpicPandaForce

24

我知道已经晚了,但我注意到人们仍然对弹出窗口有疑问。我决定写一个完整的示例,在其中可以通过触摸或单击弹出窗口的外部或仅触摸窗口本身来关闭弹出窗口。为此,创建一个新的PopupWindow类并复制以下代码:

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

现在为弹出窗口创建布局: 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>      

在您的主要活动中,创建PopupWindow类的实例:

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

其中YOUR_MAIN_LAYOUT是popupWindow将在其中弹出的当前活动的布局


1
谢谢-这对我有用。只需注意一点,就是为自定义类使用PopupWindow以外的其他名称,也许将其命名为MyPopupWindow而不是Popupwindow,以便android不会在其标准android类和自定义类之间混淆。
西蒙(Simon)

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

@Simon findViewById(R.id.YOUR_MAIN_LAYOUT)?? 会是R.layout.My_Layout吗?
Ankesh kumar Jaisansaria

15

感谢@LunaKong的回答和@HourGlass的确认。我不想发表重复的评论,而只是想使其简洁明了。

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


我希望能够通过在弹出窗口之外单击来关闭弹出窗口,但是当我这样做时,正在单击其下方的视图(不是弹出窗口的一部分,而是活动的一部分)。setFocusabl(true)是我想要的。谢谢!
hellaandrew

@hellaandrew,很高兴能为您提供帮助,:)
Nguyen Tan Dat

8

对于一ListPopupWindow组,显示时该窗口为模态窗口。

mListPopupWindow.setModal(true);

这样,在的外部单击即可ListPopupWindow将其关闭。


谢谢,我只是在寻找这个。这不仅可以将listpopupwindowow设置为在视图外部触摸之后被禁用,而且不会将touch事件传递给listpopwindow旁边的其他视图。我拼命地寻找它,因为在我的情况下,触摸外部listpopwindow会将事件传递给位于其下方的recyclerview,同时关闭listpopupwindow,并且选择了我不想要的recyclerview项。
shankar_vl

您可能还需要mListPopupWindow.setInputMethodMode(PopupWindow.INPUT_METHOD_NOT_NEEDED);,以防止弹出窗口干扰屏幕键盘。
Mr-IDE

6

请注意,要取消popupWindow.setOutsideTouchable(true),您需要wrap_content像下面的代码那样设置宽度和高度:

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

当在屏幕上单击/触摸时,它将关闭PopupWindow。确保在showAtLocation之前将focusable设置为true。


1
请添加一些解释性文字,以详细说明如何为所提问题提供准确答案。谢谢。
philantrovert

谢谢!您需要在调用showAtLocation()之前先调用setter。
droid256 '19

5

您可以在外部触摸时使用“ isOutsideTouchable 或” isFocusable关闭弹出窗口

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

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

注意

  • 目前,经过测试,我发现setBackgroundDrawable 没有帮助我们关闭popupwindow

  • 如果您查看PopupWindowPopupWindow->PopupDecorView->dispatchKeyEventPopupWindow->PopupDecorView->onTouchEvent)中关闭代码。您会看到,按返回按钮时,它们关闭;ACTION_UP当触摸外部时,它们关闭ACTION_UPACTION_OUTSIDE


4

@LunaKong建议工作就像一种魅力。

但是设置mPopupWindow.setFocusable(false)。删除使弹出窗口消失所需的不必要的触摸。

例如:让我们考虑一下屏幕上有一个弹出窗口,您将要单击一个按钮。因此,在这种情况下,第一次单击按钮popupwindow时将关闭(如果mpopwindow.setFocusable(true))。但是您必须再次单击才能使按钮起作用。如果**(mpopwindwo.setFocusable(false)**,则单击按钮将关闭弹出窗口并触发按钮单击。 希望对您有所帮助。


1
非常感谢!我正在寻找相同的商品
Ganesh,2016年


3

将窗口背景设置为透明:

PopupWindow.getBackground().setAlpha(0);

之后,在布局中设置背景。工作良好。


1
getBackground()可以为null。
Jared Rummler,2015年

1

在某些情况下,使弹出窗口具有可聚焦性是不希望的(例如,您可能不希望其从另一个视图中夺取焦点)。

另一种方法是使用触摸拦截器:

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

使用View popupView关闭popupWindow

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

`如果使用此选项,还可以将onClickClickListener设置为popupWindow内部的任何按钮

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.