1.背景变暗
在弹出PopupWindow的时候,设置Window的alpha(透明度)和dim(暗淡值)两个值。
final Window window = getWindow();
final WindowManager.LayoutParams params = window.getAttributes();
window.addFlags(WindowManager.LayoutParams.FLAG_DIM_BEHIND);
params.dimAmount = 0.7f;
params.alpha = 0.7f;
window.setAttributes(params);
popupWindow.setOnDismissListener(new PopupWindow.OnDismissListener() {
@Override
public void onDismiss() {
params.dimAmount = 1.0f;
params.alpha = 1.0f;
window.setAttributes(params);
}
});
效果如下图所示:
2.具体位置
设置PoppupWindow在具体位置,可以调用popupWindow.showAtLocation(View, int, int, int)方法。
/**
* <p>
* Display the content view in a popup window at the specified location. If the popup window
* cannot fit on screen, it will be clipped. See {@link android.view.WindowManager.LayoutParams}
* for more information on how gravity and the x and y parameters are related. Specifying
* a gravity of {@link android.view.Gravity#NO_GRAVITY} is similar to specifying
* <code>Gravity.LEFT | Gravity.TOP</code>.
* </p>
*
* @param parent a parent view to get the {@link android.view.View#getWindowToken()} token from
* @param gravity the gravity which controls the placement of the popup window
* @param x the popup's x location offset
* @param y the popup's y location offset
*/
public void showAtLocation(View parent, int gravity, int x, int y) {
showAtLocation(parent.getWindowToken(), gravity, x, y);
}
其中,参数parent为PopupWindow关联的View;参数gravity为PopupWindow的位置(居左,居中,居右等);参数x为PopupWindow的x坐标偏移量;参数y为PopupWindow的y坐标偏移量。
在上面图中,PopupWindow显示在Button的左边位置,并且与Button对齐,具体代码为:
int[] location = new int[2];
button.getLocationInWindow(location);
popupWindow.showAtLocation(button, Gravity.NO_GRAVITY, location[0] - contentView.getWidth(), location[1] - contentView.getMeasuredHeight() / 2 + button.getHeight() / 2);
注意:当contentView的宽或高为wrap_content时,要先测量contentView的宽高。测量方法如下:
contentView.measure(View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED),
View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED));
实际上调用measure()方法时,会去调用onMeasure()方法,然后测量出View的大小。
public final void measure(int widthMeasureSpec, int heightMeasureSpec){}
参数widthMeasureSpec:表示父容器强加给的水平空间
参数heightMeasureSpec:表示父容器强加给的垂直空间
关于View.MeasureSpec.makeMeasureSpec(int, int)方法:
public static int makeMeasureSpec(@IntRange(from = 0, to = (1 << MeasureSpec.MODE_SHIFT) - 1) int size,
@MeasureSpecMode int mode) {}
参数size:是指在某种测量模式的规格大小
参数mode:是指在测量模式
另外,模式只有三种值:
- UNSPECIFIED:父容器不对View有任何限制,要多大给多大。
- EXACTLY:父容器检测出View所需要的精确大小,这个时候View的最终大小就是SpecSize(参数size)所指定的值。它对应于LayoutParams中的match_parent和具体的数值这两种模式。
- AT_MOST:父容器指定了一个可用大小即SpecSize(参数size),View的大小不能大于这个值,具体是什么值要看不同View的具体实现。它对应于LayoutParams中的wrap_content。
3.动画
在使用动画时,如果PopupWindow从底部弹出:
popupWindow.showAtLocation(v.getRootView(), Gravity.BOTTOM, 0, 0);
那么在系统5.0以上,会出现在NavigationBar下面弹出或者被NavigationBar遮挡问题。如下图所示:
针对这个问题有如下解决方案:
在values-21/style.xml中的主题中添加:
<item name="android:windowDrawsSystemBarBackgrounds">false</item>
这个属性指示这个窗口是否负责绘制系统bar的背景。