Android - 在特定视图上方显示弹出窗口

33

我正在开发一款Android应用,当用户点击屏幕底部特定菜单栏对象(由水平排列的小图像组成)时,我使用一个弹出窗口。

在单击操作后,我希望弹出窗口锚定在所点击的视图的左上角,并显示在其上方。

唯一看起来相关的方法是showAsDropDown(View anchor,int xoff,int yoff)showAtLocation(View parent,int gravity,int x,int y)。 showAsDropDown的问题在于它锚定在视图的底部左侧角落。

是否有其他实现方式?

11个回答

51

popupWindow.showAsDropDown(...)方法会在锚点视图下方显示弹出窗口,而popupWindow.showAtLocation(...)方法则是绝对定位在屏幕上(甚至不是应用程序内)。该调用中的锚点仅用于其窗口令牌。而坐标则是相对于给定重力的偏移量。

你实际想要使用的是:

popupWindow.showAsDropDown(anchor, offsetX, offsetY, gravity);

这个调用只适用于 API 19+,所以在早期版本中,您需要使用:

popupWindow.showAsDropdown(anchor, offsetX, offsetY);

这些调用将显示弹出窗口相对于指定的锚定视图。请注意,默认重力(在没有指定重力时调用)为Gravity.TOP|Gravity.START,因此如果您在应用程序中明确使用Gravity.LEFT,那么您可能会遇到困难 :)


1
这就是我在寻找的那个。你所需要计算的只是根据你使用的UI元素来计算偏移量。 - Alpaslan

20

我编写了一段Kotlin示例代码,它将在锚定视图上方显示一个PopupWindow

private fun showPopupWindow(anchor: View) {
    PopupWindow(anchor.context).apply {
        isOutsideTouchable = true
        val inflater = LayoutInflater.from(anchor.context)
        contentView = inflater.inflate(R.layout.popup_layout, null).apply {
            measure(
                View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED),
                View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED)
            )
        }
    }.also { popupWindow ->
        // Absolute location of the anchor view
        val location = IntArray(2).apply {
            anchor.getLocationOnScreen(this)
        }
        val size = Size(
            popupWindow.contentView.measuredWidth,
            popupWindow.contentView.measuredHeight
        )
        popupWindow.showAtLocation(
            anchor,
            Gravity.TOP or Gravity.START,
            location[0] - (size.width - anchor.width) / 2,
            location[1] - size.height
        )
    }
}

3
这是一个非常好的答案,而且它运行良好。 - Faldu Jaldeep
100%的工作解决方案,但它显示了一些背景颜色,如何去除? - Gulab Sagevadiya
2
@GulabSagevadiya您需要设置/清除弹出窗口的背景颜色:popupWindow.setBackgroundDrawable(ColorDrawable(Color.TRANSPARENT)) - Vikas Patidar
很棒的回答。对我也很有帮助。 - filipst

10

您只需要在showAsDropDown(View anchor, int xoff, int yoff)语法中使用yoff参数,将弹出窗口沿其锚点的高度移动即可。

popupWindow.showAsDropDown(anchor, 0, -anchor.getHeight()+popupView.getHeight);

另外,请注意,如果允许的最大高度不足以容纳变换,则可能无法正确显示弹出窗口。


请详细说明这段代码如何回答问题(此答案在“低质量帖子”审核队列中)。 - JAL

7
popupWindow.showAtLocation(anchor, Gravity.BOTTOM, 0, anchor.getHeight());

你需要添加父视图而不是锚点,并且需要传递弹出窗口的确切位置,以便将其放置在指定位置。 - Er.Rohit Sharma

6
我有这段代码:PopupWindow在所有sdk版本下都可以显示在特定视图下方(重心为End)。
        // display the popup[![enter image description here][1]][1]
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
            mPopupWindow.showAsDropDown(v, 0, 0, Gravity.END);
        } else {
            mPopupWindow.showAsDropDown(v, v.getWidth() - mPopupWindow.getWidth(), 0);
        }

这里的 View v 是一个图片按钮日历。


这对我非常有效。我在SDK >= 24上使用showAtLocation,但并不适用于所有设备。到目前为止,这对我测试的每个设备都有效。 - FerDensetsu

5
你想要使用的是showAtLocation(...)。你需要指定锚点视图(用户单击的那个视图),并通过gravity参数和偏移量将其相对于该视图定位。可以将gravity参数视为PopupWindow几乎就像是一个子视图,而父视图就像是一个容器布局。
你应该能够将Gravity.LEFT | Gravity.TOP作为参数。

12
很不幸,弹出窗口将在窗口的左上角显示该行内容(popupWindow.showAsLocation(anchor, Gravity.TOP|Gravity.LEFT, 0, 0))。 - user153275

4
您可以通过以下方式始终将弹出窗口显示在锚点上方:
popupWindow.showAsDropDown(anchor, 0, -anchor.getHeight()-popupView.getHeight);

1
无法工作。弹出窗口从屏幕底部显示。 - Mohit Rajput

3

示例:

ScrollView scrollView = new ScrollView(context);
popupWindow.setContentView(scrollView);
scrollView.measure(View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED),                 
View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED));
int he=scrollView.getMeasuredHeight();
popupWindow.showAsDropDown(items,0, -items.getHeight()-he);

0

这里使用android-x解决方案,即使您使用SAW权限(系统警报窗口)具有浮动UI也应该可以工作:

@SuppressLint("InflateParams")
private fun showPopupWindow(anchor: View) {
    val popupWindow = PopupWindow(anchor.context)
    popupWindow.isFocusable = true
    popupWindow.inputMethodMode = PopupWindow.INPUT_METHOD_NOT_NEEDED
    popupWindow.contentView = LayoutInflater.from(anchor.context).inflate(R.layout.popup_layout, null)
    PopupWindowCompat.showAsDropDown(popupWindow, anchor, 0, 0, Gravity.BOTTOM)
}

这是用于底部左对齐的。

如果您需要底部居中,您可以使用以下示例:

@SuppressLint("InflateParams")
private fun showPopupWindow(anchor: View) {
    val popupWindow = PopupWindow(anchor.context)
    popupWindow.isFocusable = true
    popupWindow.inputMethodMode = PopupWindow.INPUT_METHOD_NOT_NEEDED
    val inflater = LayoutInflater.from(anchor.context)
    val contentView = inflater.inflate(R.layout.popup_layout, null)
    contentView.measure(View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED), View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED))
    popupWindow.contentView = contentView
    PopupWindowCompat.showAsDropDown(popupWindow, anchor, (anchor.measuredWidth - contentView.measuredWidth) / 2, 0, Gravity.BOTTOM)
}

0

在尝试了许多解决方案后,我找到了一种在Kotlin中显示PopupWindow在任何View上方的方法。

要在视图上方显示弹出窗口,您可以使用showAsDropDown()函数。

popUp.showAsDropDown(v, 0, (-0.2 * v.height).roundToInt(), Gravity.CENTER)

使用:

  • v:视图(锚点)
  • 0:偏移X
  • (-0.2 * v.height).roundToInt():偏移Y
  • Gravity.CENTER:重力

例如:https://medium.com/@bhattmeet887/popupwindow-above-the-specific-view-kotlin-ab1a199581eb


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接