弹出PopupWindow后让背景变暗的方法
在Android上使用AlertDialog和PopupWindow都可以很方便的实现弹窗,AlertDialog弹出后背景会变暗,而PopupWindow不具有此特性。StackOVerflow上的这个问题里给出了三种方法以实现弹出PopupWindow后让背景变暗的效果,整理如下。
1. 方法一
使用WindowManager.LayoutParams.FLAG_DIM_BEHIND可以实现变暗的效果。
private void dimBackground(PopupWindow popup, float dimAmount) {
ViewParent vp = popup.getContentView().getParent();
WindowManager wm = (WindowManager) getSystemService(Context.WINDOW_SERVICE);
if (vp instanceof View) {
// PopupWindow has background drawable set
View container = (View) popup.getContentView().getParent();
WindowManager.LayoutParams p = (WindowManager.LayoutParams) container.getLayoutParams();
p.flags = WindowManager.LayoutParams.FLAG_DIM_BEHIND;
p.dimAmount = dimAmount;
wm.updateViewLayout(container, p);
} else {
// PopupWindow has no background drawable
WindowManager.LayoutParams p =
(WindowManager.LayoutParams) popup.getContentView().getLayoutParams();
p.flags = WindowManager.LayoutParams.FLAG_DIM_BEHIND;
p.dimAmount = dimAmount;
wm.updateViewLayout(popup.getContentView(), p);
}
}
2. 方法二
为 RootView 的 ViewGroupOverlay 添加黑色 Drawable 并修改其透明度,也可以实现让整个背景窗口的效果。只适用于 API Level 18 及以上。
@TargetApi(Build.VERSION_CODES.JELLY_BEAN_MR2)
public void applyDim(float dimAmount){
ViewGroup parent = (ViewGroup) getWindow().getDecorView().getRootView();
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);
}
@TargetApi(Build.VERSION_CODES.JELLY_BEAN_MR2)
public void clearDim() {
ViewGroup parent = (ViewGroup) getWindow().getDecorView().getRootView();
ViewGroupOverlay overlay = parent.getOverlay();
overlay.clear();
}
3. 方法三
使用 FrameLayout 作为背景布局的 Root,并设置 FrameLayout 的 foreground 为黑色不透明的 shape,之后就可以通过修改 shape 的透明度,让整个窗口变暗。
所使用的的 shape (/drawable/dim.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>
注意其中颜色为黑色(#000000),没有指定Alpha通道(透明度)的值。如果在这里指定了Alpha通道,如使用#ff000000,该Alpha通道的值(0xff)就会固定,无法再通过setAlpha()方法设置。
把要变暗的区域放在 FrameLayout 中,并设置 FrameLayout 的 foreground 为上面定义的 dim.xml:
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/container"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:foreground="@drawable/dim"
tools:foreground="">
...
</FrameLayout>
由于 dim.xml 是不透明的黑色,这里还设置了tools:foreground="",以免在Preview窗口一团黑。
同样由于 dim.xml 是黑色的,在初始化时记得首先把它设置为透明:
mContainer = (FrameLayout) findViewById(R.id.container); mContainer.getForeground().setAlpha(0);
然后就可以通过setAlpha()让 FrameLayout 区域变暗或恢复:
mContainer.getForeground().setAlpha(127); mContainer.getForeground().setAlpha(0);
这种方法虽然麻烦,但适用性最广。
4. 完整代码
完整代码可以在这里找到。