2011-10-08 141 views
10

大多数示例都指定了弹出窗口的宽度和高度。我想他们是WRAP_CONTENT - 由于内容dinamically决定的,所以在构造函数中我设置-2宽度和高度,并通过showAsDropDown(查看锚)未指定大小时弹出窗口弹出窗口

这样做表明它,在弹出总是画在锚点视图下方,这意味着它可以在屏幕外画出。以下片段演示了这个问题。尝试点击最后一个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; 
    } 
} 

回答

16

我开始怀疑,在PopupWindow是-2的情况下,-2实际上意味着WRAP_CONTENT,而我认为它只是将其解释为宽度= -2高度= -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 = new PopupWindow(getPopupContent(), 1, 1); 

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

enter image description here

但是等等!如果在我当前的示例中,每次都会增加更多内容,那该怎么办呢?那么,这是事情变得有趣的地方。你可以看到,在我的下一张截图中,弹出窗口尽管现在应该显示为6行,但显示在底部!哦,废话,对!那是因为它是用我在构造函数中使用的1 1来衡量的。那么有什么解决方案呢?

enter image description here

解决方法一:我的首选方法是采取什么的TextView的平均最大高度会,然后简单地抛在一个一般大的数字猜测。

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

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

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); 
+0

我读得源,它似乎更多的A ndroid的bug,因为大小是正确的,但放置是错误的。自从我提供演示以来,您可以亲自测试它。现在我正在试验PopupWindow.showAtLocation() – Raffaele

+0

正如我怀疑你需要在'setWindowLayoutMode'中添加我编辑我的答案并添加到您需要的确切工作代码。我在我的android设备上测试了它,所有东西! :) – Bob

+0

如果下一次调用弹出内容视图更改会发生什么?这就是为什么我需要WRAP_CONTENT – Raffaele

1

我通过调用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);