当我使用 显示我的弹出窗口时,我希望能够模糊或调暗背景popup.showAtLocation
,并在调用时取消模糊/调暗背景popup.dismiss
。
我已经尝试将布局参数应用FLAG_BLUR_BEHIND
到FLAG_DIM_BEHIND
我的活动中,但这似乎只是在我的应用程序启动后使背景变得模糊和变暗。
如何仅使用弹出窗口进行模糊/变暗?
当我使用 显示我的弹出窗口时,我希望能够模糊或调暗背景popup.showAtLocation
,并在调用时取消模糊/调暗背景popup.dismiss
。
我已经尝试将布局参数应用FLAG_BLUR_BEHIND
到FLAG_DIM_BEHIND
我的活动中,但这似乎只是在我的应用程序启动后使背景变得模糊和变暗。
如何仅使用弹出窗口进行模糊/变暗?
问题是关于Popupwindow
班级的,但每个人都给出了使用Dialog
班级的答案。Popupwindow
如果您需要使用该类,那几乎没用,因为Popupwindow
没有getWindow()
方法。
我找到了一个真正适用于Popupwindow
. 它只要求您用于后台活动的 xml 文件的根是FrameLayout
. 你可以给Framelayout
元素一个android:foreground
标签。这个标签的作用是指定一个可绘制资源,该资源将分层在整个活动之上(也就是说,如果 Framelayout 是 xml 文件中的根元素)。然后,您可以控制setAlpha()
前景可绘制对象的不透明度 ( )。
你可以使用任何你喜欢的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>
(有关该元素的更多信息,请参阅http://developer.android.com/guide/topics/resources/drawable-resource.html#Shape )。shape
请注意,我没有在颜色标签中指定使可绘制项目透明的 alpha 值(例如 #ff000000
)。原因是任何硬编码的 alpha 值似乎都会覆盖我们通过setAlpha()
代码中设置的任何新 alpha 值,所以我们不希望这样。但是,这意味着可绘制项目最初是不透明的(实心的,不透明的)。onCreate()
所以我们需要在activity的方法中让它透明。
这是 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/
由于PopupWindow
只需添加一个View
,您就可以在调用 show..() 后WindowManager
使用它updateViewLayout (View view, ViewGroup.LayoutParams params)
来更新LayoutParams
您PopupWindow
的。contentView
设置窗口标志FLAG_DIM_BEHIND
将使窗口后面的所有内容变暗。用于dimAmount
控制暗淡量(1.0 表示完全不透明,0.0 表示没有暗淡)。
请记住,如果您为您设置背景,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);
无背景:
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);
棉花糖更新:
在 M PopupWindow 上,将 contentView 包装在名为 mDecorView 的 FrameLayout 中。如果您深入研究 PopupWindow 源代码,您会发现类似createDecorView(View contentView)
.mDecorView 的主要目的是处理事件调度和内容转换,这对 M 来说是新的。这意味着我们需要再添加一个 .getParent() 来访问容器。
背景需要更改为:
View container = (View) popup.getContentView().getParent().getParent();
API 18+ 的更好替代方案
一个不那么 hacky 的解决方案,使用ViewGroupOverlay
:
1)获取所需的根布局
ViewGroup root = (ViewGroup) getWindow().getDecorView().getRootView();
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();
}
在您的 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>
在您的活动 oncreate
//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);
另一个技巧是使用 2 个弹出窗口而不是一个。第一个弹出窗口将只是一个具有半透明背景的虚拟视图,提供暗淡的效果。第二个弹出窗口是您想要的弹出窗口。
创建弹出窗口时 的顺序:首先显示虚拟弹出窗口,然后显示预期的弹出窗口。
销毁时的顺序: 关闭预期的弹出窗口,然后关闭虚拟弹出窗口。
链接这两者的最佳方法是添加一个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;
}
我找到了解决方案
创建一个自定义透明对话框并在该对话框中打开弹出窗口:
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" />
现在你想在弹出窗口关闭时关闭对话框。所以
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 上完成
也许这个 repo 会对你有所帮助:BasePopup
这是我的repo,用来解决PopupWindow的各种问题。
在使用库的情况下,如果需要虚化背景,只需调用setBlurBackgroundEnable(true).
详情见wiki。(zh-cn语言)</p>
findViewById(R.id.drawer_layout).setAlpha((float) 0.7);
R.id.drawer_layout
是要调暗亮度的布局的 ID。
对我来说,像 Abdelhak Mouaamou 的回答一样有效,在 API 级别 16 和 27 上进行了测试。
我没有使用popupWindow.getContentView().getParent()
并将结果转换为View
(在 API 级别 16 上崩溃导致它返回一个ViewRootImpl
不是 的实例的对象View
),我只使用.getRootView()
它已经返回了一个视图,因此不需要在那里进行转换。
希望它可以帮助某人:)
完整的工作示例从其他 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);
}
}
你可以用它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">
好的,所以当弹出窗口打开时,我按照uhmdown 的回答来调暗背景活动。但这给我带来了问题。它是调暗活动并包括弹出窗口(意味着在活动和弹出窗口上都分层的暗黑色,它不能将它们分开)。
所以我尝试了这种方式,
为调光效果创建一个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);
它对我有用,也解决了BaDo评论的问题。有了这个Actionbar
也可以变暗。
Ps 我并不是说uhmdown是错误的。我从他的答案中学习并尝试针对我的问题进行改进。我也很困惑这是否是一个好方法。
任何建议也很感激,也很抱歉我的英语不好。
此代码有效
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);