PopupWindow Nexus 7的状态栏上方(以及其他设备的状态栏)

时间:2014-08-04 13:01:38

标签: android popup location popupwindow nexus-7

我有一个PopupWindow,在我点击ImageButton后会打开:

// Get the [x, y]-location of the ImageButton
int[] loc = new int[2];
myImageButton.getLocationOnScreen(loc);

// Inflate the tag_popup.xml
LinearLayout viewGroup = (LinearLayout)findViewById(R.id.tagPopupLayout);
LayoutInflater layoutInflater = (LayoutInflater)getSystemService(Context.LAYOUT_INFLATER_SERVICE);
final View layout = layoutInflater.inflate(R.layout.tag_popup, viewGroup);

// Create the PopupWindow
myPopupWindow = new PopupWindow(ChecklistActivity.this);
myPopupWindow.setContentView(layout);
myPopupWindow.setWindowLayoutMode(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT);
myPopupWindow.setFocusable(true);
myPopupWindow.setOutsideTouchable(false);

// Clear the default translucent background and use a white background instead
myPopupWindow.setBackgroundDrawable(new ColorDrawable(android.graphics.Color.WHITE));

// Set the content of the TextViews, EditTexts and Buttons of the PopupWindow
setPopupContent(...);

// Displaying the Pop-up at the specified location
myPopupWindow.showAtLocation(layout, Gravity.NO_GRAVITY, 0, loc[1]);

因为Gravity.NO_GRAVITY,PopupWindow将显示在Window的边框内。一切都在我的模拟器上按预期工作,但当我在我的Nexus 7平板电脑上运行时,它部分由设备的底部状态栏覆盖。

我该如何解决这个问题?我应该在Gravity.NO_GRAVITY发生后以某种方式获取当前PopupWindow的位置,然后更改y位置以添加设备的状态栏的高度,然后重新绘制它? (会尝试这个,但我认为拥有正确的位置而不是重新绘制它是一个更好的解决方案..)

1 个答案:

答案 0 :(得分:0)

这就是我想出的:

我们拥有什么:

  • 我们给PopupWindow的showAtLocation方法的[x,y]位置(我们只需要这个位置的y位置,我将其命名为oldY

我们的计算方法:

  • 弹出高度
  • 状态栏高度
  • 窗口边界(screenHeight - statusBarHeight - popupHeight
  • 内的最大可能高度

然后我们检查:

  • 我们会检查oldY是否大于maxY
  • 如果是这种情况,newY将是maxY,我们会重新绘制PopupWindow。如果不是这种情况,则意味着我们什么也不做,只需使用oldY作为正确的Y-postition。

注意1:我为此制作了代码,但在调试过程中,我的模拟器和Nexus平板电脑上的状态栏的高度为0,所以只需使用screenHeight - popupHeight对我来说足够了。尽管如此,如果应用程序将来安装在另一台平板电脑上,我还是会在我的Config文件中包含用于计算Bottom Status Bar Height底部状态栏高度的代码来启用/禁用此功能。

这是在代码中,我刚刚添加了上面的描述,以明确我用来解决这个问题的方法:

// Get the [x, y]-location of the ImageButton
int[] loc = new int[2];
myImageButton.getLocationOnScreen(loc);

// Inflate the popup.xml
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);

// Create the PopupWindow
myPopupWindow = new PopupWindow(ChecklistActivity.this);
myPopupWindow.setContentView(layout);
myPopupWindow.setWindowLayoutMode(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT);

... // Some more stuff with the PopupWindow's content

// Clear the default translucent background and use a white background instead
myPopupWindow.setBackgroundDrawable(new ColorDrawable(android.graphics.Color.WHITE));

// Displaying the Pop-up at the specified location
myPopupWindow.showAtLocation(layout, Gravity.NO_GRAVITY, 0, loc[1]);

// Because the PopupWindow is displayed below the Status Bar on some Device's,
// we recalculate it's height:
// Wait until the PopupWindow is done loading by using an OnGlobalLayoutListener:
final int[] finalLoc = loc;
if(layout.getViewTreeObserver().isAlive()){
    layout.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
        // This will be called once the layout is finished, prior to displaying it
        // So we can change the y-position of the PopupWindow just before that
        @Override
        public void onGlobalLayout() {
            // Get the PopupWindow's height
            int popupHeight = layout.getHeight();
            // Get the Status Bar's height
            int statusBarHeight = 0;
            // Enable/Disable this in the Config-file
            // This isn't needed for the Emulator, nor the Nexus 7 tablet
            // Since the calculated Status Bar Height is 0 with both of them
            // and the PopupWindow is displayed at its correct position
            if(D.WITH_STATUS_BAR_CHECK){
                // Check whether the Status bar is at the top or bottom
                Rect r = new Rect();
                Window w = ChecklistActivity.this.getWindow();
                w.getDecorView().getWindowVisibleDisplayFrame(r);
                int barHeightCheck = r.top;
                // If the barHeightCheck is 0, it means our Status Bar is
                // displayed at the bottom and we need to get it's height
                // (If the Status Bar is displayed at the top, we use 0 as Status Bar Height)
                if(barHeightCheck == 0){
                    int resourceId = getResources().getIdentifier("status_bar_height", "dimen", "android");
                    if (resourceId > 0)
                        statusBarHeight = getResources().getDimensionPixelSize(resourceId);
                }
            }
            // Get the Screen's height:
            DisplayMetrics dm = new DisplayMetrics();
            getWindowManager().getDefaultDisplay().getMetrics(dm);
            int screenHeight = dm.heightPixels;
            // Get the old Y-position
            int oldY = finalLoc[1];
            // Get the max Y-position to be within Window boundaries
            int maxY = screenHeight - statusBarHeight - popupHeight;
            // Check if the old Y-position is outside the Window boundary
            if(oldY > maxY){
                // If it is, use the max Y-position as new Y-position,
                // and re-draw the PopupWindow
                myPopupWindow.dismiss();
                myPopupWindow.showAtLocation(layout, Gravity.NO_GRAVITY, 0, maxY);
            }

            // Since we don't want onGlobalLayout to continue forever, we remove the Listener here again
            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>
 <!-- The DOCTYPE above is added to get rid of the following warning:
     "No grammar constraints (DTD or XML schema) detected for the document." -->

 <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">

     ... <!-- Popup's Content (EditTexts, Spinner, TextViews, Button, etc.) -->

 </RelativeLayout>

注意3: 我的应用程序被强制保持在纵向模式。我没有在横向模式下测试它,但我假设应该进行一些修改(但不确定)。编辑:经过测试,它也可以在我的两个设备上以横向模式工作。我不知道这是否也适用于横向模式并且启用了底栏高度。

花了我一些时间,但它现在有效。希望他们将来修复PopupWindow的Gravity,所以它永远不会低于状态栏,除非程序员自己想要并更改PopupWindow的设置。使事情变得更容易..