【问题标题】:PopupWindow - Dismiss when clicked outsidePopupWindow - 在外部单击时关闭
【发布时间】:2012-08-27 07:08:20
【问题描述】:

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

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

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

【问题讨论】:

    标签: android popupwindow android-menu


    【解决方案1】:

    请尝试在PopupWindow 上设置setBackgroundDrawable,如果您触摸它的外部,它应该会关闭窗口。

    【讨论】:

    • 我错过了。你在 popupWindow 上使用 setBackgroundDrawable 吗?我知道将背景可绘制对象设置为 null 会杀死 OnTouchListener
    • 就是这样!谢谢你!在这种情况下,即使是触摸事件也可以正确处理。 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; } });
    • 将背景可绘制设置为 null 对我不起作用。如果其他人有问题,请参阅我的回答。
    • @WareNinja ,您的评论有效!也许您最好对这个问题留下一个完整的答案,这对其他人有用
    • @WareNinja BitmapDrawable() 已弃用。请改用ColorDrawable()
    【解决方案2】:

    我知道已经晚了,但我注意到人们仍然对弹出窗口有疑问。我决定编写一个完整的工作示例,您可以通过触摸或单击弹出窗口外部或仅触摸窗口本身来关闭弹出窗口。为此,创建一个新的 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 将在其中弹出的当前活动的布局

    【讨论】:

    • 谢谢 - 这对我有用。只是一个小提示是宁愿为您的自定义类使用 PopupWindow 以外的其他名称,也许将其称为 MyPopupWindow 而不是 Popupwindow,这样 android 就不会在您的标准 android 类和您的自定义类之间混淆。
    • @Marcin S.findViewById(R.id.YOUR_MAIN_LAYOUT) ??会不会是 R.layout.My_Layout
    • @Simon findViewById(R.id.YOUR_MAIN_LAYOUT) ??会是 R.layout.My_Layout 吗?
    【解决方案3】:

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

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

    或者:

    myPopupWindow.setFocusable(true);
    

    不知道有什么区别,但是 ListPopupWindow 源代码实际上是在使用 setModal 将其模态设置为 true 时使用后者,所以至少 Android 开发人员认为这是一种可行的方法,而且它只有一行。

    【讨论】:

    • 非常感谢。其他答案都没有对我有用或解释得不够好。第二个选项对我不起作用。
    • 我还注意到 BitmapDrawable 已被弃用。有一个真正的解决方案会很好,因为这些看起来像是临时解决方法,不能保证在较新的 API 版本中得到支持。
    • 不使用 BitmapDrawable 已弃用的构造函数,请参阅此处:stackoverflow.com/a/21680637/2048266。 popupWindow.setBackgroundDrawable(new BitmapDrawable(getResources(), ""));
    • 在使用setFocusable 的替代方法时,我们需要单击按钮两次(按钮位于弹出窗口之外的位置),与第一种方法一样,它可以正常工作:)跨度>
    • BitmapDrawable() 已弃用。请改用ColorDrawable()
    【解决方案4】:
    mPopWindow.setFocusable(true);
    

    【讨论】:

    • 这是唯一需要的。我不明白为什么接受的答案如此受欢迎。
    【解决方案5】:

    设置窗口背景透明:

    PopupWindow.getBackground().setAlpha(0);
    

    在布局中设置背景之后。工作正常。

    【讨论】:

    • getBackground() 可能为空。
    【解决方案6】:

    对于ListPopupWindow,将窗口设置为显示时的模式。

    mListPopupWindow.setModal(true);
    

    这样,在ListPopupWindow 之外单击将关闭它。

    【讨论】:

    • 谢谢,我只是在找这个。这不仅设置 listpopupwindow 在触摸视图外部后关闭,而且不会将触摸事件传递给 listpopwindow 旁边的其他视图。我一直在拼命寻找这个,因为在我的情况下,在 listpopwindow 之外触摸将事件传递给 recyclerview,它在关闭 listpopupwindow 旁边,并且 recyclerview 项目被选中,这是我不想要的。
    • 您可能还需要mListPopupWindow.setInputMethodMode(PopupWindow.INPUT_METHOD_NOT_NEEDED);,以防止弹出窗口干扰屏幕键盘。
    【解决方案7】:

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

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

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

    玩得开心@.@

    【讨论】:

    • 一定要在显示你的popoupWindow之前添加这个代码
    • 如果弹出窗口不需要焦点,我真的需要将 focusable 设置为 true 吗?
    • 我很惊讶它的工作原理,但它是 API 21 所必需的。这也解决了我的弹出窗口动画不正确的问题。
    【解决方案8】:

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

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

    例如: 假设屏幕上有一个可见的弹出窗口,您将要单击一个按钮。 所以在这种情况下,(如果 mpopwindow.setFocusable(true)) 第一次单击按钮弹出窗口将关闭。 但是您必须再次单击才能使按钮起作用。 如果**(mpopwindwo.setFocusable(假)** 单击按钮关闭弹出窗口并触发按钮单击。 希望能帮助到你。

    【讨论】:

    • 非常感谢!我正在寻找相同的
    【解决方案9】:
      popupWindow.setTouchable(true);
      popupWindow.setFocusable(true);
      popupWindow.showAtLocation(popupView, Gravity.CENTER, 0, 0);
    

    当点击/触摸屏幕时它会关闭 PopupWindow。确保你在 showAtLocation 之前设置了 focusable true。

    【讨论】:

    • 请添加一些解释性文字来详细说明这如何为所提问题提供准确的答案。谢谢。
    • 谢谢!您需要在调用 showAtLocation() 之前调用 setter。
    【解决方案10】:

    请注意,使用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);
    

    【讨论】:

      【解决方案11】:

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

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

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

      【讨论】:

        【解决方案12】:

        感谢@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));
        

        时间。

        【讨论】:

        • 我希望能够通过在弹出窗口外部单击来关闭它,但是当我这样做时,正在单击它下面的视图(不是弹出窗口的一部分,而是活动的一部分)。 setFocusabl(true) 是我想要的。谢谢!
        • @hellaandrew,很高兴它对你有帮助,:)
        【解决方案13】:

        使用 View popupView 关闭 popupWindow

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

        ` 如果您使用它,您还可以将 OnClickListener 设置为 popupWindow 内的任何按钮

        【讨论】:

          【解决方案14】:

          您可以使用isOutsideTouchable OR isFocusable 关闭外部触摸时弹出窗口

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

          注意

          • 目前,经过测试我看到setBackgroundDrawable 不要帮助我们关闭弹出窗口

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

          【讨论】:

            【解决方案15】:

            如果此弹出窗口是另一个活动,并且您将其大小减小到原始屏幕 并且您想启用或禁用外部区域。您可以通过以下代码简单地启用或禁用外部区域:

            启用:

            YourActivity.this.setFinishOnTouchOutside(true);

            禁用:

            YourActivity.this.setFinishOnTouchOutside(false);

            【讨论】:

              猜你喜欢
              • 1970-01-01
              • 2014-09-16
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 2019-07-12
              相关资源
              最近更新 更多