当未指定大小时,PopupWindow超出屏幕

时间:2011-10-08 10:38:39

标签: android

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

执行此操作时,弹出窗口始终绘制在锚点视图下方,这意味着它可以在屏幕外绘制。以下代码段演示了此问题。尝试单击最后一个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;
    }
}

3 个答案:

答案 0 :(得分:16)

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

这是来自Android Source

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

答案 1 :(得分:7)

我通过在弹出式内容视图中调用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);

答案 2 :(得分:0)

var selectedDays = modifyRecordData.selectedDays;
var splitSelectedDays = selectedDays.split(',');

splitSelectedDays.forEach(day => {
    let val = day.trim();

    if(val == 'Mon') {
        $('#mon').removeClass('btn-default');
        $('#mon').addClass('btn-primary');
    }

    if (val == 'Tue') {
        $('#tue').removeClass('btn-default');
        $('#tue').addClass('btn-primary');
    }

    if (val == 'Wed') {
        $('#wed').removeClass('btn-default');
        $('#wed').addClass('btn-primary');
    }

    if (val == 'Thur') {
        $('#thur').removeClass('btn-default');
        $('#thur').addClass('btn-primary');
    }

    if (val == 'Fri') {
        $('#fri').removeClass('btn-default');
        $('#fri').addClass('btn-primary');
    }

    if (val == 'Sat') {
        $('#sat').removeClass('btn-default');
        $('#sat').addClass('btn-primary');
    }

    if (val == 'Sun') {
        $('#sun').removeClass('btn-default');
        $('#sun').addClass('btn-primary');
    }
})

//以上是我检查过的有效代码