android - 未指定大小时 PopupWindow 超出屏幕

标签 android

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

显示它

这样做,弹出窗口总是绘制在 anchor View 下方,这意味着它可以绘制在屏幕外。以下代码段演示了该问题。尝试单击最后一个 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;
    }
}

最佳答案

我开始怀疑在 PopupWindow 的上下文中 -2,-2 实际上意味着 WRAP_CONTENT 而我认为它只是将它解释为 width = -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 确定将其放置在哪个 View 中时,它取决于您提供的宽度和高度.这意味着因为你使用 0 和 0 作为你的宽度和高度,Android 会出现并说,“哦看,这个框只是一个 0 x 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);

关于android - 未指定大小时 PopupWindow 超出屏幕,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/7696246/

相关文章:

c# - 是否可以使用 Visual Studio 从 Android Firebase 接收数据并向 mysql 发送数据

android - ?安卓 :attr/selectableItemBackground not working on white windowBackground

android - 错误:Execution failed for task app:processDebugResources

java - 将项目添加到包含图像的列表的 Activity

android - 具有 9-patch 项背景问题的 ListView

java - 在 Android XML 中对齐 TextView 和进度条

java - 更改应用程序语言

android - android studio字体问题

android - Fabric Crashlytics - 聚合来自不同项目的数据

c++ - 在 Android 发送的图像上计算服务器端的 OpenCV 函数