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

Raf*_*ele 12 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;
    }
}
Run Code Online (Sandbox Code Playgroud)

Bob*_*Bob 17

我开始怀疑在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);
}
Run Code Online (Sandbox Code Playgroud)

在哪里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);
Run Code Online (Sandbox Code Playgroud)

我把原来的评论留在那里,这样你就可以看到一切应该去的地方.

编辑2: 好的,所以我把你发布的代码和逐字试验放在我的设备上,你是对的,它没有用,因为当Android确定要布局的布局时,它依赖于宽度和你提供的高度.这意味着,因为你使用0和0作为你的宽度和高度,Android会出现并说:"哦,看起来,这个盒子只是一个0×0的盒子,所以我可以把它显示为内容下方的弹出窗口." 这不是我们想要的!问题是,你知道盒子会比那个大,所以让我们开始输入一些不同的数字并看到它的结果.

popup = new PopupWindow(getPopupContent(), 1, 1);
Run Code Online (Sandbox Code Playgroud)

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

在此输入图像描述

可是等等!如果在我当前的示例中,字符串每次都会添加更多内容,该怎么办?好吧,这就是事情变得有趣的地方.你会看到,在我的下一个屏幕截图中,弹出窗口,即使它现在应该显示为6行,现在显示在底部!哦,废话,对!那是因为它是1 1在构造函数中使用的.那么有什么解决方案呢?

在此输入图像描述

解决方案一:我首选的方法是猜测平均最大高度是多少TextView,然后简单地抛出一个通常大的数字.

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

解决方案二:这更合适,但你要牺牲一点速度来做到这一点.使用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;
}
Run Code Online (Sandbox Code Playgroud)

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

    popup.setHeight(maxHeight);
    popup.setWidth(maxWidth);
Run Code Online (Sandbox Code Playgroud)


小智 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);
Run Code Online (Sandbox Code Playgroud)