今天我遇到了和你一样的问题。在我的模拟器上,由于PopupWindow的
Gravity.NO_GRAVITY
,PopupWindow在窗口范围内正确绘制。但是在我的Nexus 7平板电脑上,PopupWindow显示在设备底部显示的状态栏下方。
当我在屏幕上点击ImageButton时,我的PopupWindow会显示出来,此时它的y-position与ImageButton相同(而且宽度为
match_parent
)。ImageButton的位置可能在窗口范围内,也可能完全位于平板电脑底部的状态栏下方。
这是我想出来的方法:
我们有:
- 我们在PopupWindow的showAtLocation方法中指定的[x,y]位置(在这里我们只需要y-position,我将其命名为
oldY
)
我们计算:
- Popup高度
- 状态栏高度
- 可能的最大高度以保持在窗口范围内(
screenHeight - statusBarHeight - popupHeight
)
然后我们检查:
- 我们检查
oldY
是否大于maxY
- 如果是这样,
newY
将是maxY
,然后我们重新绘制 PopupWindow。 如果不是这种情况,这意味着我们什么都不做,只使用oldY
作为正确的Y位置。
注意1:我编写了此代码,但在调试期间发现我的模拟器和Nexus平板电脑上的状态栏高度均为0,因此仅使用screenHeight - popupHeight
就足够了。 仍然,在我的配置文件中包含了计算底部状态栏高度的代码,并使用布尔值来启用/禁用此功能,以防将来在其他平板电脑上安装应用程序。
以下是代码,我只是添加了上面的描述,以便清楚地说明我用哪种方法解决了这个问题:
int[] loc = new int[2];
myImageButton.getLocationOnScreen(loc);
LinearLayout viewGroup = (LinearLayout)findViewById(R.id.popup_layout);
LayoutInflater layoutInflater = (LayoutInflater)getSystemService(Context.LAYOUT_INFLATER_SERVICE);
final View layout = layoutInflater.inflate(R.layout.popup, viewGroup);
myPopupWindow = new PopupWindow(ChecklistActivity.this);
myPopupWindow.setContentView(layout);
myPopupWindow.setWindowLayoutMode(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT);
...
myPopupWindow.setBackgroundDrawable(new ColorDrawable(android.graphics.Color.WHITE));
myPopupWindow.showAtLocation(layout, Gravity.NO_GRAVITY, 0, loc[1]);
final int[] finalLoc = loc;
if(layout.getViewTreeObserver().isAlive()){
layout.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
@Override
public void onGlobalLayout() {
int popupHeight = layout.getHeight();
int statusBarHeight = 0;
if(D.WITH_STATUS_BAR_CHECK){
Rect r = new Rect();
Window w = ChecklistActivity.this.getWindow();
w.getDecorView().getWindowVisibleDisplayFrame(r);
int barHeightCheck = r.top;
if(barHeightCheck == 0){
int resourceId = getResources().getIdentifier("status_bar_height", "dimen", "android");
if (resourceId > 0)
statusBarHeight = getResources().getDimensionPixelSize(resourceId);
}
}
DisplayMetrics dm = new DisplayMetrics();
getWindowManager().getDefaultDisplay().getMetrics(dm);
int screenHeight = dm.heightPixels;
int oldY = finalLoc[1];
int maxY = screenHeight - statusBarHeight - popupHeight;
if(oldY > maxY){
myPopupWindow.dismiss();
myPopupWindow.showAtLocation(layout, Gravity.NO_GRAVITY, 0, maxY);
}
layout.getViewTreeObserver().removeOnGlobalLayoutListener(this);
}
});
}
注意2:我已经在这一行中将tag_popup
本身设置为width = match_parent; height = wrap_content
myPopupWindow.setWindowLayoutMode(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT)
将此弹出窗口的主要布局设置为width = match_parent; height = match_parent
:
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE xml>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/popup_layout"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@layout/tag_shape"
android:padding="@dimen/default_margin">
...
</RelativeLayout>
注意3:我的应用程序被强制保持为竖屏模式。我还没有在横屏模式下测试过这个问题,但我认为应该进行一些修改(不确定)。编辑:在我的两个设备上测试过了,在横屏模式下也可以工作。我不知道启用底部栏高度的情况下是否也适用于横屏模式。
希望这能帮助您和其他遇到类似问题的人。希望他们将来会修复PopupWindow的Gravity
问题,让它永远不会出现在状态栏下面,除非程序员自己想要并更改PopupWindow的设置。
PopupWindow
中的内容视图具有边距(即平板电脑上的Y偏移量)到窗口顶部边缘。我使用View.getLocationOnScreen
在绘制之前获取偏移量,然后一切都正常了。 - suitianshi