弹出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. 完整代码
完整代码可以在这里找到。