Android PopupWindow处于活动状态时模糊或暗淡背景

时间:2010-07-11 01:25:47

标签: android popupwindow android-popupwindow

当我使用popup.showAtLocation显示弹出窗口时,我希望能够模糊或调暗背景,并在调用popup.dismiss时将背景解开/调暗。

我尝试将布局参数FLAG_BLUR_BEHINDFLAG_DIM_BEHIND应用到我的活动中,但是在我的应用启动后,这似乎只是模糊和暗淡背景。

如何使用弹出框进行模糊/调光?

11 个答案:

答案 0 :(得分:100)

关于Popupwindow课程的问题,但每个人都给出了使用Dialog课程的答案。如果你需要使用Popupwindow类,这几乎没用,因为Popupwindow没有getWindow()方法。

我找到了一个实际适用于Popupwindow的解决方案。它只要求您用于后台活动的xml文件的根目录为FrameLayout。您可以为Framelayout元素添加android:foreground标记。此标记的作用是指定一个可绘制的资源,该资源将在整个活动之上分层(即,如果Framelayout是xml文件中的根元素)。然后,您可以控制前景drawable的不透明度(setAlpha())。

您可以使用任何您喜欢的可绘制资源,但如果您只想要调暗效果,请在drawable文件夹中创建一个xml文件,其中<shape>标记为root。

<?xml version="1.0" encoding="utf-8"?>
<shape
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:shape="rectangle" >
    <solid android:color="#000000" />
</shape>

(有关shape元素的更多信息,请参阅http://developer.android.com/guide/topics/resources/drawable-resource.html#Shape)。 请注意,我没有在颜色标记中指定使可绘制项目透明的alpha值(例如#ff000000)。原因是任何硬编码的alpha值似乎都会覆盖我们在代码中通过setAlpha()设置的任何新alpha值,因此我们不希望这样。 但是,这意味着可绘制项目最初将是不透明的(实心,不透明)。因此,我们需要在活动的onCreate()方法中使其透明。

这是Framelayout xml元素代码:

<FrameLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/mainmenu"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    android:foreground="@drawable/shape_window_dim" >
...
... your activity's content
...
</FrameLayout>

这是Activity的onCreate()方法:

public void onCreate( Bundle savedInstanceState)
{
  super.onCreate( savedInstanceState);

  setContentView( R.layout.activity_mainmenu);

  //
  // Your own Activity initialization code
  //

  layout_MainMenu = (FrameLayout) findViewById( R.id.mainmenu);
  layout_MainMenu.getForeground().setAlpha( 0);
}

最后,调暗活动的代码:

layout_MainMenu.getForeground().setAlpha( 220); // dim

layout_MainMenu.getForeground().setAlpha( 0); // restore

alpha值从0(不透明)到255(不可见)。 当您关闭Popupwindow时,您应该取消调整活动。

我没有提供显示和解散Popupwindow的代码,但是这里有一个如何完成的链接:http://www.mobilemancer.com/2011/01/08/popup-window-in-android/

答案 1 :(得分:64)

由于PopupWindow只是将View添加到WindowManager,您可以使用updateViewLayout (View view, ViewGroup.LayoutParams params)来更新LayoutParams的{​​{1}} PopupWindow 1}}在调用show ..()之后。

设置窗口标志contentView将使窗口后面的所有内容变暗。使用FLAG_DIM_BEHIND来控制暗淡的数量(1.0表示完全不透明,0.0表示没有暗淡)。

请注意,如果您为dimAmount设置背景,则会将PopupWindow放入容器中,这意味着您需要更新其父级。

有背景:

contentView

没有背景:

PopupWindow popup = new PopupWindow(contentView, width, height);
popup.setBackgroundDrawable(background);
popup.showAsDropDown(anchor);

View container = (View) popup.getContentView().getParent();
WindowManager wm = (WindowManager) getSystemService(Context.WINDOW_SERVICE);
WindowManager.LayoutParams p = (WindowManager.LayoutParams) container.getLayoutParams();
// add flag
p.flags |= WindowManager.LayoutParams.FLAG_DIM_BEHIND;
p.dimAmount = 0.3f;
wm.updateViewLayout(container, p);

棉花糖更新:

On M PopupWindow将contentView包装在名为mDecorView的FrameLayout中。如果你深入了解PopupWindow源代码,你会发现像PopupWindow popup = new PopupWindow(contentView, width, height); popup.setBackgroundDrawable(null); popup.showAsDropDown(anchor); WindowManager wm = (WindowManager) getSystemService(Context.WINDOW_SERVICE); WindowManager.LayoutParams p = (WindowManager.LayoutParams) contentView.getLayoutParams(); // add flag p.flags |= WindowManager.LayoutParams.FLAG_DIM_BEHIND; p.dimAmount = 0.3f; wm.updateViewLayout(contentView, p); 这样的东西.mDecorView的主要目的是处理事件调度和内容转换,它们是M的新东西。这意味着我们需要再添加一个.getParent()访问容器。

背景需要更改为:

createDecorView(View contentView)

API 18 +的更好替代方案

使用View container = (View) popup.getContentView().getParent().getParent();

的解决方案

1)获取所需的根布局

ViewGroupOverlay

2)致电ViewGroup root = (ViewGroup) getWindow().getDecorView().getRootView(); applyDim(root, 0.5f);

clearDim()

答案 2 :(得分:27)

在你的xml文件中添加这样的宽度和高度为&#39; match_parent&#39;。

<RelativeLayout
        android:id="@+id/bac_dim_layout"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:background="#C0000000"
        android:visibility="gone" >
</RelativeLayout>

在您的活动中创建

//setting background dim when showing popup
back_dim_layout = (RelativeLayout) findViewById(R.id.share_bac_dim_layout);

最后在显示弹出窗口时显示,并在退出弹出窗口时使其显示消失。

back_dim_layout.setVisibility(View.VISIBLE);
back_dim_layout.setVisibility(View.GONE);

答案 3 :(得分:11)

另一个技巧是使用2个弹出窗口而不是一个。第一个弹出窗口将只是一个半透明背景的虚拟视图,提供暗淡效果。第二个弹出窗口是您想要的弹出窗口。

创建弹出窗口时的顺序: 显示虚拟弹出窗口1st,然后显示预期的弹出窗口。

摧毁时的序列: 关闭预期的弹出窗口,然后关闭虚拟弹出窗口。

链接这两者的最佳方法是添加OnDismissListener并覆盖预期的onDismiss()方法,以便从他们的虚拟弹出窗口中删除。

虚拟弹出窗口的代码:

fadepopup.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical" 
    android:id="@+id/fadePopup"
    android:background="#AA000000">
</LinearLayout>

显示淡入淡出弹出以使背景变暗

private PopupWindow dimBackground() {

    LayoutInflater inflater = (LayoutInflater) EPGGRIDActivity.this
            .getSystemService(Context.LAYOUT_INFLATER_SERVICE);
    final View layout = inflater.inflate(R.layout.fadepopup,
            (ViewGroup) findViewById(R.id.fadePopup));
    PopupWindow fadePopup = new PopupWindow(layout, windowWidth, windowHeight, false);
    fadePopup.showAtLocation(layout, Gravity.NO_GRAVITY, 0, 0);
    return fadePopup;
}

答案 4 :(得分:5)

我找到了一个解决方案

创建一个自定义透明对话框,在该对话框中打开弹出窗口:

dialog = new Dialog(context, android.R.style.Theme_Translucent_NoTitleBar);
emptyDialog = LayoutInflater.from(context).inflate(R.layout.empty, null);

/* blur background*/
WindowManager.LayoutParams lp = dialog.getWindow().getAttributes();  
lp.dimAmount=0.0f;  
dialog.getWindow().setAttributes(lp);  
dialog.getWindow().addFlags(WindowManager.LayoutParams.FLAG_BLUR_BEHIND); 
dialog.setContentView(emptyDialog);
dialog.setCanceledOnTouchOutside(true);
dialog.setOnShowListener(new OnShowListener()
{
    @Override
    public void onShow(DialogInterface dialogIx)
    {
        mQuickAction.show(emptyDialog); //open the PopupWindow here
    }
});
dialog.show();

对话框的xml(R.layout.empty):

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
     android:layout_height="match_parent" android:layout_width="match_parent"
     style="@android:style/Theme.Translucent.NoTitleBar" />

现在你想在Popup窗口解散时关闭对话框。所以

mQuickAction.setOnDismissListener(new OnDismissListener()
{
    @Override
    public void onDismiss()
    {
        if(dialog!=null)
        {
            dialog.dismiss(); // dismiss the empty dialog when the PopupWindow closes
            dialog = null;
        }
    }
});

注意:我在这里使用NewQuickAction插件来创建PopupWindow。它也可以在原生Popup Windows上完成

答案 5 :(得分:1)

findViewById(R.id.drawer_layout).setAlpha((float) 0.7);

R.id.drawer_layout是您要调暗亮度的布局的ID。

答案 6 :(得分:0)

您可以使用android:theme="@android:style/Theme.Dialog"来执行此操作。 创建活动并在AndroidManifest.xml中将活动定义为:

    <activity android:name=".activities.YourActivity"
              android:label="@string/your_activity_label"
              android:theme="@android:style/Theme.Dialog">

答案 7 :(得分:0)

好的,所以我遵循uhmdown's的答案来打开弹出窗口时调暗背景活动。但这给我带来了问题。它是活动的变暗状态,并包含弹出窗口(意味着活动和弹出式窗口上都呈暗黑色分层,不能将它们分开)。

所以我尝试了这种方式,

创建一个 dimming_black.xml 文件以使效果变暗,

 <?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
    android:shape="rectangle">
    <solid android:color="#33000000" />
</shape>

并在background中将FrameLayout作为根xml标签添加,也将我的其他控件放在LinearLayout中,就像这样layout.xml

<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    android:background="@drawable/ff_drawable_black">

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:orientation="vertical"
        android:layout_gravity="bottom"
        android:background="@color/white">

        // other codes...
    </LinearLayout>

</FrameLayout>

最后,我在MainActivity上显示弹出式窗口,并设置了一些额外的参数,如下所示。

           //instantiate popup window
            popupWindow = new PopupWindow(viewPopup, LinearLayout.LayoutParams.MATCH_PARENT, LinearLayout.LayoutParams.MATCH_PARENT, true);

            //display the popup window
            popupWindow.showAtLocation(layout_ff, Gravity.BOTTOM, 0, 0);

结果: enter image description here

它对我有用,也解决了 BaDo 所说的问题。与此Actionbar一起也可以变暗。

P.s我并不是说 uhmdown's 是错误的。我从他的答案中学到了东西,并尝试着解决我的问题。我也很困惑这是否是一个好方法。

对于我的英语不好,任何建议也表示赞赏。

答案 8 :(得分:0)

对我来说,类似于Abdelhak Mouaamou的答案的作品在API级别16和27上进行了测试。

与其使用popupWindow.getContentView().getParent()并将结果强制转换为View(在API级别16崩溃,原因是它返回了一个ViewRootImpl对象,该对象不是{{1}的实例})我只使用View,它已经返回了一个视图,因此在那里不需要强制转换。

希望它对某人有帮助:)

完整的工作示例是从其他stackoverflow帖子中打乱而来的,只需将其复制粘贴,例如,在按钮的onClick侦听器中:

.getRootView()

答案 9 :(得分:0)

也许此仓库会为您提供帮助:BasePopup

这是我的仓库,用于解决PopupWindow的各种问题。

在使用该库的情况下,如果您需要模糊背景,只需调用setBlurBackgroundEnable(true).

有关更多详细信息,请参见Wiki。(zh-cn中的语言)

BasePopup:wiki

答案 10 :(得分:-1)

此代码工作

        pwindo = new PopupWindow(layout, ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT, true);
        pwindo.showAtLocation(layout, Gravity.CENTER, 0, 0);
        pwindo.setOutsideTouchable(false);

        View container = (View) pwindo.getContentView().getParent();
        WindowManager wm = (WindowManager) getSystemService(Context.WINDOW_SERVICE);
        WindowManager.LayoutParams p = (WindowManager.LayoutParams) container.getLayoutParams();
        p.flags = WindowManager.LayoutParams.FLAG_DIM_BEHIND;
        p.dimAmount = 0.3f;
        wm.updateViewLayout(container, p);