当尺寸未指定时PopupWindow出现在屏幕之外

那里的大多数例子都指定了popup窗口的宽度和高度。 我希望它们是WRAP_CONTENT – 因为内容是dinamically确定的,所以在构造函数中,我设置了-2的宽度和高度,并通过showAsDropDown(View anchor)

这样做,popup窗口总是在锚点视图下面绘制,这意味着它可以在屏幕外绘制。 以下片段演示了这个问题。 尝试点击最后一个TextView,你将看不到任何PopupWindow,因为它显示在窗口范围之外。 为什么不起作用? 我指出明确指定维度(例如200,100)不会触发问题。 亲自尝试一下

package com.zybnet.example.popupdemo; import android.app.Activity; import android.graphics.Color; import android.os.Bundle; import android.view.View; import android.view.View.OnClickListener; import android.widget.LinearLayout; import android.widget.PopupWindow; import android.widget.TextView; public class PopupDemoActivity extends Activity implements OnClickListener { private PopupWindow popup; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); // -2 means WRAP_CONTENT THIS TRIGGERS THE PROBLEM popup = new PopupWindow(getPopupContent(), -2, -2); // When you specify the dimensions everything goes fine //popup = new PopupWindow(getPopupContent(), 200, 100); LinearLayout layout = new LinearLayout(this); layout.setOrientation(LinearLayout.VERTICAL); // FILL_PARENT and same layout weight for all children LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(-1, -1, 1); for (int i = 0; i < 10; i++) { TextView tv = new TextView(this); tv.setText("Click to show popup"); tv.setOnClickListener(this); layout.addView(tv, params); } setContentView(layout); } @Override public void onClick(View view) { popup.dismiss(); popup.showAsDropDown(view); } private View getPopupContent() { TextView popupContent = new TextView(this); popupContent.setText("Some text here"); popupContent.setTextColor(Color.parseColor("#5000ae")); popupContent.setBackgroundColor(Color.parseColor("#ff00ff")); popupContent.setPadding(10, 20, 20, 10); return popupContent; } } 

Solutions Collecting From Web of "当尺寸未指定时PopupWindow出现在屏幕之外"

我开始怀疑,在一个PopupWindow的上下文中,-2,-2实际上意味着WRAP_CONTENT而我认为它只是将其解释为width = -2 height = -2

这是来自Android的源

 public PopupWindow(View contentView, int width, int height, boolean focusable) { if (contentView != null) { mContext = contentView.getContext(); mWindowManager = (WindowManager) mContext.getSystemService(Context.WINDOW_SERVICE); } setContentView(contentView); setWidth(width); setHeight(height); setFocusable(focusable); } 

其中setWidth(int width)只是一个简单的mWidth = width; 我认为你正在寻找的是setWindowLayoutMode(int widthSpec,int heightSpec)方法。 那就是你应该通过WRAP_CONTENT

如果一切都失败了,测量TextView的宽度和高度,然后按照预期使用setWidthsetHeight

编辑

只是试了一下自己,并添加了这一行代码,使其工作

  // -2 means WRAP_CONTENT THIS TRIGGERS THE PROBLEM popup = new PopupWindow(getPopupContent(), 200, 100); popup.setWindowLayoutMode(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT); // When you specify the dimensions everything goes fine //popup = new PopupWindow(getPopupContent(), 200, 100); LinearLayout layout = new LinearLayout(this); layout.setOrientation(LinearLayout.VERTICAL); 

我留下了原来的评论,所以你可以看到自己的一切应该去的地方。

编辑2:好的,所以我把你的代码发布,并逐字尝试在我的设备上,你是对的,这是行不通的,因为当Android确定哪些视图来布置放置它,它依赖于宽度和你提供的高度。 这是什么意思,因为你使用0和0作为你的宽度和高度,Android会来,并说:“哦,看,这个盒子只是一个0×0框,所以我可以显示它作为一个popup下面的内容。 这不是所期望的! 事情是,你知道这个盒子会比那个更大,所以我们开始input一些不同的数字,看看结果。

 popup = new PopupWindow(getPopupContent(), 1, 1); 

现在,当我去点击底部的框,注意它跳到上面。 (见截图)这是因为Android知道宽度和高度是1(正如我在构造函数中设置的那样),并且列表项下面的可用屏幕空间是0.那么,如果没有足够的空间来显示它,那么它一定要在上面!

在这里输入图像说明

可是等等! 如果在我现在的例子中,每次都会添加更多的内容呢? 那么,这是事情变得有趣的地方。 你可以看到,在我的下一个截图中,popup窗口,即使它现在显示为6行,显示在底部! 哦,废话,对! 那是因为它是用我在构造函数中使用的1 1来度量的。 那么有什么解决scheme呢?

在这里输入图像说明

解决scheme一:我的首选方法是猜测TextView的平均最大高度是多less,然后简单地扔在一个大的数字。

 popup = new PopupWindow(getPopupContent(), 300, 300); //just guessing it won't get bigger than that 

解决scheme二:这是更合适的,但你牺牲了一点速度去做。 使用Paint类来测量文本内容大小,并在显示popup窗口之前将其传递到setWidth()setHeight() 。 我继续build立一个几乎完整的解决scheme,但我没有测量填充和东西(见评论)

 private int maxWidth; private int maxHeight; private Paint p = new Paint(); private Rect bounds = new Rect(); private View getPopupContent() { maxWidth = 0; maxHeight = 0; TextView popupContent = new TextView(this); popupContent.setText(popupText += "\n" + DEMO); popupContent.setTextColor(Color.parseColor("#5000ae")); popupContent.setBackgroundColor(Color.parseColor("#ff00ff")); popupContent.setPadding(10, 20, 20, 10); //the measure can only work line by line so I split it up by line String[] temp = popupText.split("\n"); for (String s : temp){ //measure each line of string and get its width and height p.getTextBounds(s, 0, s.length(), bounds); //keep a running total of the longest width maxWidth = (bounds.width() > maxWidth) ? bounds.width() : maxWidth; //add up each of the heights maxHeight += bounds.height(); } //also take in account the padding too... if you REALLY want it to be completely robust //probably adding another 20 or 30 to the maxHeight should be good return popupContent; } 

然后在onClick()我加了这两行

  popup.setHeight(maxHeight); popup.setWidth(maxWidth); 

我通过在popup式内容视图中调用measure()方法解决了这个问题:

 View content = getPopupContent(); content.measure(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT); int measuredHeight = content.getMeasuredHeight(); popup = new PopupWindow(content, ViewGroup.LayoutParams.WRAP_CONTENT, measuredHeight);