目录
PopWindow位置问题
有时候我们通过PopWindow来从底部往上展示界面,可能会发现在部分机型上有问题,想要在bottom显示窗口,结果在top显示了,如下图:
Gravity.BOTTOM无效的原因
可能我们用的是下面这句代码:
popupWindow.showAtLocation(mRootLayout, Gravity.BOTTOM, 0, 0);在部分机型上有问题BOTTOM根本不管用
从源码中找答案,下面是部分源码
//mGravity默认Gravity.NO_GRAVITY
private int mGravity = Gravity.NO_GRAVITY;
/**
* <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) {
mParentRootView = new WeakReference<>(parent.getRootView());
showAtLocation(parent.getWindowToken(), gravity, x, y);
}
/**
* Display the content view in a popup window at the specified location.
*
* @param token Window token to use for creating the new window
* @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
*
* @hide Internal use only. Applications should use
* {@link #showAtLocation(View, int, int, int)} instead.
*/
public void showAtLocation(IBinder token, int gravity, int x, int y) {
if (isShowing() || mContentView == null) {
return;
}
TransitionManager.endTransitions(mDecorView);
detachFromAnchor();
mIsShowing = true;
mIsDropdown = false;
mGravity = gravity;
final WindowManager.LayoutParams p = createPopupLayoutParams(token);
preparePopup(p);
p.x = x;
p.y = y;
invokePopup(p);
}
private int computeGravity() {
int gravity = mGravity == Gravity.NO_GRAVITY ? Gravity.START | Gravity.TOP : mGravity;
if (mIsDropdown && (mClipToScreen || mClippingEnabled)) {
gravity |= Gravity.DISPLAY_CLIP_VERTICAL;
}
return gravity;
}
其实我们通过showAtLocation(mRootLayout, Gravity.BOTTOM, 0, 0)是想在bottom显示,但是部分机型有问题,这时候我们不要相信Gravity.BOTTOM的效果了,索性使用Gravity.NO_GRAVITY,后面传入自己计算好的坐标,一般x=0就好了,主要是计算y的值。
解决方案
popupWindow.showAtLocation(mRootLayout, Gravity.NO_GRAVITY, 0, DimenUtils.getWindowHeight() - contentView.getMeasuredHeight());
DimenUtils.getWindowHeight():屏幕的高度
contentView.getMeasuredHeight():内容view的高度(注意因为没有显示出来,所以view高度拿不到需要通过)
在使用getMeasuredHeight之前需要先测量一下
contentView.measure(View.MeasureSpec.UNSPECIFIED, View.MeasureSpec.UNSPECIFIED);
private PopupWindow createPopupWindow(View contentView) {
contentView.measure(View.MeasureSpec.UNSPECIFIED, View.MeasureSpec.UNSPECIFIED);
PopupWindow popupWindow = new PopupWindow(contentView, WindowManager.LayoutParams.MATCH_PARENT, WindowManager.LayoutParams.WRAP_CONTENT, true);
popupWindow.setTouchable(true);
popupWindow.setBackgroundDrawable(new BitmapDrawable());
popupWindow.setFocusable(true);
popupWindow.setAnimationStyle(R.style.PopupAnimation);
popupWindow.setClippingEnabled(true);
popupWindow.setSoftInputMode(PopupWindow.INPUT_METHOD_NEEDED);
popupWindow.setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE);
popupWindow.showAtLocation(mRootLayout, Gravity.NO_GRAVITY, 0, DimenUtils.getWindowHeight() - contentView.getMeasuredHeight());
popupWindow.update();
return popupWindow;
}