Android PopupWindow 活动时背景模糊或变暗
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/3221488/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Blur or dim background when Android PopupWindow active
提问by k_day
I would like to be able to either blur or dim the background when I show my popup window using popup.showAtLocation
, and unblur/dim the background when popup.dismiss
is called.
我希望能够在使用 显示弹出窗口时使背景模糊或变暗popup.showAtLocation
,并在popup.dismiss
调用时取消模糊/变暗背景。
I have tried applying layout params FLAG_BLUR_BEHIND
and FLAG_DIM_BEHIND
to my activity, but this appears to just blur and dim the background as soon my app is started.
我曾尝试应用布局PARAMSFLAG_BLUR_BEHIND
和FLAG_DIM_BEHIND
我的活动,但是这似乎只是模糊和朦胧的背景,一旦我的应用程序已启动。
How can I do blurring/dimming just with popups?
如何仅使用弹出窗口进行模糊/变暗?
回答by uhmdown
The question was about the Popupwindow
class, yet everybody has given answers that use the Dialog
class. Thats pretty much useless if you need to use the Popupwindow
class, because Popupwindow
doesn't have a getWindow()
method.
问题是关于Popupwindow
班级的,但每个人都给出了使用Dialog
班级的答案。如果您需要使用Popupwindow
该类,那几乎没有用,因为Popupwindow
它没有getWindow()
方法。
I've found a solution that actually works with Popupwindow
. It only requires that the root of the xml file you use for the background activity is a FrameLayout
. You can give the Framelayout
element an android:foreground
tag. What this tag does is specify a drawable resource that will be layered on top of the entire activity (that is, if the Framelayout is the root element in the xml file). You can then control the opacity (setAlpha()
) of the foreground drawable.
我找到了一个实际适用于Popupwindow
. 它只需要您用于后台活动的 xml 文件的根目录是FrameLayout
. 你可以给Framelayout
元素一个android:foreground
标签。该标签的作用是指定一个可绘制资源,该资源将位于整个活动的顶部(即,如果 Framelayout 是 xml 文件中的根元素)。然后,您可以控制setAlpha()
前景可绘制对象的不透明度 ( )。
You can use any drawable resource you like, but if you just want a dimming effect, create an xml file in the drawable folder with the <shape>
tag as root.
你可以使用任何你喜欢的 drawable 资源,但如果你只是想要一个变暗的效果,在 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>
(See http://developer.android.com/guide/topics/resources/drawable-resource.html#Shapefor more info on the shape
element).
Note that I didn't specify an alpha value in the color tag that would make the drawable item transparent (e.g #ff000000
). The reason for this is that any hardcoded alpha value seems to override any new alpha values we set via the setAlpha()
in our code, so we don't want that.
However, that means that the drawable item will initially be opaque (solid, non-transparent). So we need to make it transparent in the activity's onCreate()
method.
(有关该元素的更多信息,请参阅http://developer.android.com/guide/topics/resources/drawable-resource.html#Shapeshape
)。请注意,我没有在颜色标签中指定使可绘制项目透明的 alpha 值(例如 #ff000000
)。这样做的原因是任何硬编码的 alpha 值似乎都会覆盖我们通过setAlpha()
代码中设置的任何新的 alpha 值,所以我们不希望那样。但是,这意味着可绘制项目最初是不透明的(实心的、不透明的)。所以我们需要在活动的onCreate()
方法中让它透明。
Here's the Framelayout xml element code:
这是 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>
Here's the Activity's onCreate() method:
这是 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);
}
Finally, the code to dim the activity:
最后,使活动变暗的代码:
layout_MainMenu.getForeground().setAlpha( 220); // dim
layout_MainMenu.getForeground().setAlpha( 0); // restore
The alpha values go from 0
(opaque) to 255
(invisible).
You should un-dim the activity when you dismiss the Popupwindow.
alpha 值从0
(不透明)到255
(不可见)。当您关闭弹出窗口时,您应该取消活动的亮度。
I haven't included code for showing and dismissing the Popupwindow, but here's a link to how it can be done: http://www.mobilemancer.com/2011/01/08/popup-window-in-android/
我没有包含用于显示和关闭 Popupwindow 的代码,但这里有一个如何完成的链接:http: //www.mobilemancer.com/2011/01/08/popup-window-in-android/
回答by Markus Rubey
Since PopupWindow
just adds a View
to WindowManager
you can use updateViewLayout (View view, ViewGroup.LayoutParams params)
to update the LayoutParams
of your PopupWindow
's contentView
after calling show..().
由于PopupWindow
只是添加了一个View
toWindowManager
你可以用来在调用 show..() 后updateViewLayout (View view, ViewGroup.LayoutParams params)
更新LayoutParams
你的PopupWindow
's contentView
。
Setting the window flag FLAG_DIM_BEHIND
will dimm everything behind the window. Use dimAmount
to control the amount of dim (1.0 for completely opaque to 0.0 for no dim).
设置窗口标志FLAG_DIM_BEHIND
将使窗口后面的所有内容变暗。使用dimAmount
以控制暗淡的(1.0完全不透明到0.0为无暗淡)的量。
Keep in mind that if you set a background to your PopupWindow
it will put your contentView
into a container, which means you need to update it's parent.
请记住,如果您为您设置背景,PopupWindow
它将把您contentView
放入一个容器中,这意味着您需要更新它的父级。
With background:
有背景:
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);
Without background:
无背景:
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);
Marshmallow Update:
棉花糖更新:
On M PopupWindow wraps the contentView inside a FrameLayout called mDecorView. If you dig into the PopupWindow source you will find something like createDecorView(View contentView)
.The main purpose of mDecorView is to handle event dispatch and content transitions, which are new to M. This means we need to add one more .getParent() to access the container.
在 M PopupWindow 上,将 contentView 包装在一个名为 mDecorView 的 FrameLayout 中。如果你深入研究 PopupWindow 源代码,你会发现类似createDecorView(View contentView)
.mDecorView 的主要目的是处理事件调度和内容转换,这对 M 来说是新的。这意味着我们需要再添加一个 .getParent() 来访问容器。
With background that would require a change to something like:
背景需要更改为:
View container = (View) popup.getContentView().getParent().getParent();
Better alternative for API 18+
API 18+ 的更好选择
A less hacky solution using ViewGroupOverlay
:
一个不那么hacky的解决方案使用ViewGroupOverlay
:
1) Get a hold of the desired root layout
1) 获取所需的根布局
ViewGroup root = (ViewGroup) getWindow().getDecorView().getRootView();
2) Call applyDim(root, 0.5f);
or clearDim()
2) 打电话applyDim(root, 0.5f);
或clearDim()
public static void applyDim(@NonNull ViewGroup parent, float dimAmount){
Drawable dim = new ColorDrawable(Color.BLACK);
dim.setBounds(0, 0, parent.getWidth(), parent.getHeight());
dim.setAlpha((int) (255 * dimAmount));
ViewGroupOverlay overlay = parent.getOverlay();
overlay.add(dim);
}
public static void clearDim(@NonNull ViewGroup parent) {
ViewGroupOverlay overlay = parent.getOverlay();
overlay.clear();
}
回答by user2257590
In your xml file add something like this with width and height as 'match_parent'.
在您的 xml 文件中添加类似这样的内容,宽度和高度为“match_parent”。
<RelativeLayout
android:id="@+id/bac_dim_layout"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#C0000000"
android:visibility="gone" >
</RelativeLayout>
In your activity oncreate
在你的活动 oncreate
//setting background dim when showing popup
back_dim_layout = (RelativeLayout) findViewById(R.id.share_bac_dim_layout);
Finally make visible when you show your popupwindow and make its visible gone when you exit popupwindow.
最后在显示 popupwindow 时使其可见,并在退出 popupwindow 时使其可见。
back_dim_layout.setVisibility(View.VISIBLE);
back_dim_layout.setVisibility(View.GONE);
回答by Abhishek Nandi
Another trick is to use 2 popup windows instead of one. The 1st popup window will simply be a dummy view with translucent background which provides the dim effect. The 2nd popup window is your intended popup window.
另一个技巧是使用 2 个弹出窗口而不是一个。第一个弹出窗口将只是一个带有半透明背景的虚拟视图,提供昏暗的效果。第二个弹出窗口是您想要的弹出窗口。
Sequence while creating pop up windows:Show the dummy pop up window 1st and then the intended popup window.
创建弹出窗口时的顺序:首先显示虚拟弹出窗口,然后显示预期的弹出窗口。
Sequence while destroying:Dismiss the intended pop up window and then the dummy pop up window.
销毁时的顺序:关闭预期的弹出窗口,然后关闭虚拟弹出窗口。
The best way to link these two is to add an OnDismissListenerand override the onDismiss()
method of the intended to dimiss the dummy popup window from their.
链接这两者的最佳方法是添加一个OnDismissListener并覆盖onDismiss()
旨在从它们中关闭虚拟弹出窗口的方法。
Code for the dummy popup window:
虚拟弹出窗口的代码:
fadepopup.xml
弹出窗口.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>
Show fade popup to dim the background
显示淡入淡出弹出窗口使背景变暗
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;
}
回答by PC.
I've found a solution for this
我已经找到了解决方案
Create a custom transparent dialog and inside that dialog open the popup window:
创建一个自定义透明对话框并在该对话框内打开弹出窗口:
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 for the dialog(R.layout.empty):
对话框的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" />
now you want to dismiss the dialog when Popup window dismisses. so
现在您想在弹出窗口关闭时关闭对话框。所以
mQuickAction.setOnDismissListener(new OnDismissListener()
{
@Override
public void onDismiss()
{
if(dialog!=null)
{
dialog.dismiss(); // dismiss the empty dialog when the PopupWindow closes
dialog = null;
}
}
});
Note: I've used NewQuickAction
plugin for creating PopupWindow here. It can also be done on native Popup Windows
注意:我在NewQuickAction
这里使用插件来创建 PopupWindow。它也可以在本机弹出窗口上完成
回答by chrisi1698
For me, something like Abdelhak Mouaamou's answer works, tested on API level 16 and 27.
对我来说,像 Abdelhak Mouaamou 的答案一样有效,在 API 级别 16 和 27 上进行了测试。
Instead of using popupWindow.getContentView().getParent()
and casting the result to View
(which crashes on API level 16 cause there it returns a ViewRootImpl
object which isn't an instance of View
) I just use .getRootView()
which returns a view already, so no casting required there.
而不是使用popupWindow.getContentView().getParent()
并将结果转换为View
(它在 API 级别 16 上崩溃,导致它返回一个ViewRootImpl
不是 的实例的对象View
)我只是使用.getRootView()
它已经返回一个视图,因此不需要在那里进行转换。
Hope it helps someone :)
希望它可以帮助某人:)
complete working example scrambled together from other stackoverflow posts, just copy-paste it, e.g., in the onClick listener of a button:
从其他 stackoverflow 帖子中拼凑而成的完整工作示例,只需复制粘贴它,例如,在按钮的 onClick 侦听器中:
// inflate the layout of the popup window
LayoutInflater inflater = (LayoutInflater)getSystemService(LAYOUT_INFLATER_SERVICE);
if(inflater == null) {
return;
}
//View popupView = inflater.inflate(R.layout.my_popup_layout, null); // this version gives a warning cause it doesn't like null as argument for the viewRoot, c.f. https://stackoverflow.com/questions/24832497 and https://stackoverflow.com/questions/26404951
View popupView = View.inflate(MyParentActivity.this, R.layout.my_popup_layout, null);
// create the popup window
final PopupWindow popupWindow = new PopupWindow(popupView,
LinearLayout.LayoutParams.WRAP_CONTENT,
LinearLayout.LayoutParams.WRAP_CONTENT,
true // lets taps outside the popup also dismiss it
);
// do something with the stuff in your popup layout, e.g.:
//((TextView)popupView.findViewById(R.id.textview_popup_helloworld))
// .setText("hello stackoverflow");
// dismiss the popup window when touched
popupView.setOnTouchListener(new View.OnTouchListener() {
@Override
public boolean onTouch(View v, MotionEvent event) {
popupWindow.dismiss();
return true;
}
});
// show the popup window
// which view you pass in doesn't matter, it is only used for the window token
popupWindow.showAtLocation(view, Gravity.CENTER, 0, 0);
//popupWindow.setOutsideTouchable(false); // doesn't seem to change anything for me
View container = popupWindow.getContentView().getRootView();
if(container != null) {
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;
if(wm != null) {
wm.updateViewLayout(container, p);
}
}
回答by razerdp
Maybe this repo will help for you:BasePopup
也许这个 repo 对你有帮助:BasePopup
This is my repo, which is used to solve various problems of PopupWindow.
这是我的repo,用来解决PopupWindow的各种问题。
In the case of using the library, if you need to blur the background, just call setBlurBackgroundEnable(true).
在使用库的情况下,如果需要模糊背景,只需调用 setBlurBackgroundEnable(true).
See the wiki for more details.(Language in zh-cn)
详见wiki。(zh-cn中的语言)
回答by Devbrat Anuragi
findViewById(R.id.drawer_layout).setAlpha((float) 0.7);
R.id.drawer_layout
is the id of the layout of which you want to dim the brightness.
R.id.drawer_layout
是要调暗亮度的布局的 id。
回答by Sahil M.
ok, so i follow uhmdown'sanswer for dimming background activity when pop window is open. But it creates problem for me. it was dimming activity and include popup window (means dimmed-black layered on both activity and popup also, it can not be separate them).
好的,所以我按照uhmdown 的答案在弹出窗口打开时调暗背景活动。但它给我带来了问题。它是变暗的活动并包括弹出窗口(意味着在活动和弹出窗口上也有变暗的黑色分层,它不能将它们分开)。
so i tried this way,
所以我尝试了这种方式,
create an dimming_black.xmlfile for dimming effect,
创建一个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>
And add as background
in FrameLayout
as root xml tag, also put my other controls in LinearLayout
like this layout.xml
而作为添加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>
at last i show popup on my MainActivity
with some extra parameter set as below.
最后我在我的弹出窗口中显示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);
it works for me, also solved problem as commented by BaDo. With this Actionbar
also can be dimmed.
它对我有用,也解决了BaDo评论的问题。有了这个Actionbar
也可以变暗。
P.s i am not saying uhmdown'sis wrong. i learnt form his answer and try to evolve for my problem. I also confused whether this is a good way or not.
Ps 我并不是说uhmdown是错误的。我从他的答案中学习并尝试针对我的问题进行改进。我也很困惑这是否是一个好方法。
Any suggestions is also appreciated also sorry for my bad English.
任何建议也很感激,也很抱歉我的英语不好。
回答by Macarse
You can use android:theme="@android:style/Theme.Dialog"
to do that.
Create an activity and in your AndroidManifest.xml
define the activity as:
你可以用它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">