我希望在使用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()
)。<shape>
标记作为根的xml文件。<?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()
方法中使其透明。
以下是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
仅将 View
添加到 WindowManager
,您可以使用 updateViewLayout (View view, ViewGroup.LayoutParams params)
在调用 show..() 后更新您的 PopupWindow
的 contentView
的 LayoutParams
。
设置窗口标志 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+的更好替代方案
使用ViewGroupOverlay
的较少hack的解决方案:
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();
}
WindowManager.LayoutParams
。有什么解决方法吗? - Robertif (p != null) { //相同的代码 } else { popupView.addOnLayoutChangeListener(new View.OnLayoutChangeListener() { public void onLayoutChange(View v, int left, int top, int right, int bottom, int oldLeft, int oldTop, int oldRight, int oldBottom) { v.removeOnLayoutChangeListener(this); WindowManager.LayoutParams p = (WindowManager.LayoutParams) v.getLayoutParams(); p.flags = WindowManager.LayoutParams.FLAG_DIM_BEHIND; p.dimAmount = 0.3f; wm.updateViewLayout(v, p); } }); }
- Beytan Kurt在你的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>
在您的activity的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);
另一个技巧是使用两个弹出窗口,而不是一个。第一个弹出窗口将只是带有半透明背景的虚拟视图,它提供了暗淡效果。第二个弹出窗口是您预期的弹出窗口。
创建弹出窗口时的顺序: 首先显示虚拟弹出窗口1,然后再显示预期的弹出窗口。
销毁时的顺序: 关闭预期的弹出窗口,然后关闭虚拟弹出窗口。
将这两个窗口链接在一起的最佳方式是添加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
插件来创建弹出窗口。这也可以在本机弹出窗口上完成。findViewById(R.id.drawer_layout).setAlpha((float) 0.7);
R.id.drawer_layout
是您想要调暗亮度的布局的 ID。
setBlurBackgroundEnable(true)
。popupWindow.getContentView().getParent()
并将结果转换为View
(在API级别16上会崩溃,因为它返回一个ViewRootImpl
对象,它不是View
的实例),我只是使用.getRootView()
,它已经返回一个视图,因此不需要强制转换。// 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://dev59.com/_GAf5IYBdhLWcg3wSQ4z and https://dev59.com/_18d5IYBdhLWcg3w1E50
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);
}
}
由于您正在尝试通过模糊背景屏幕来弹出对话框窗口,因此您必须使用以下一组代码行。首先需要获取对话框属性,然后为对话框属性设置一些 alpha 值。
现在,您的带有模糊背景的对话框已经准备好了。但是重要的因素是为窗口设置一个标志FLAG_DIM_BEHIND
。
现在结果就是您的了。希望对某人有所帮助...
WindowManager.LayoutParams lp = dialog.getWindow().getAttributes();
lp.dimAmount=0.6f;
dialog.getWindow().setAttributes(lp);
dialog.getWindow().addFlags(WindowManager.LayoutParams.FLAG_DIM_BEHIND);
您可以使用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">