PopupWindow out of screen when size is unspecified

前端 未结 3 1714
孤城傲影
孤城傲影 2020-12-20 13:01

Most examples out there specify exactly the width and height of the popup window. I want them to be WRAP_CONTENT - since the content is dinamically determined, so in the con

相关标签:
3条回答
  • 2020-12-20 13:13
    final PopupWindow popupWindow = new PopupWindow();
    // inflate your layout or dynamically add view
    LayoutInflater inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
    View view = inflater.inflate(R.layout.alert_reply_chat,null);
    
    popupWindow.setFocusable(true);
    popupWindow.setWidth(WindowManager.LayoutParams.WRAP_CONTENT);
    popupWindow.setHeight(180);
    popupWindow.setBackgroundDrawable(null);
    
    popupWindow.setClippingEnabled(false);
    
    popupWindow.setTouchable(true);
    popupWindow.setContentView(view);
    
    return popupWindow;
    

    //above is working code i checked it

    0 讨论(0)
  • 2020-12-20 13:26

    I'm starting to doubt that in the context of a PopupWindow that -2, -2 actually means WRAP_CONTENT rather I think that its just interpreting it as width = -2 height = -2

    This is from the 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);
    }
    

    where setWidth(int width) is just a simple mWidth = width; I think what you are looking for instead is the setWindowLayoutMode (int widthSpec, int heightSpec) method. That is where you should pass in the WRAP_CONTENT

    If all else fails, measure the width and height of the TextView and then use setWidth and setHeight as expected.

    Edit:

    Just tried it out for myself and added this line of code to make it work

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

    I left the original comments in there so you can see for yourself where everything should go.

    Edit 2: Okay, so I took your code you posted and verbatim tried it on my device, and you were right, it didn't work because when Android is determining which views to layout to put it in, it relies on the width and height you provided. What that means is since you are using 0 and 0 as your width and height, Android will come along and say, "Oh look, the box is only a 0 by 0 box so I can display it as a popup below the content." This isn't what is desired though! The thing is, you know that the box is going to be bigger than that, so lets start putting in some different numbers and seeing the results that come from it.

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

    Now when I go and click the bottom box, notice that it jumps above. (See screenshot) That's because Android KNOWS that the width and height are 1 (as I set in the constructor) and that the available screen space below the list item is 0. Well, if there's not enough room to display it there, then it must above then!

    enter image description here

    But wait! What if like in my current example the string adds on more content each time? Well, this is where things get interesting. You see, in my next screenshot that the popup, even though it should be displayed up since it is 6 lines long now, is rather displayed at the bottom! Oh crap, right! That's because it is measuring against the 1 1 I used in the constructor. Well what are some solutions to this then?

    enter image description here

    Solution One: My preferred way would be to take a guess at what the average max height of the TextView would be and then simply toss in one generically big number.

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

    Solution Two: This is more proper, but you are sacrificing a little speed to do it. Using the Paint class to measure what the text content size is going to be and passing that into the the setWidth() and setHeight() before you display the popup. I went ahead and built an almost complete solution, but I didn't measure in padding and stuff (see the comment)

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

    And then in the onClick() I added these two lines

        popup.setHeight(maxHeight);
        popup.setWidth(maxWidth);
    
    0 讨论(0)
  • 2020-12-20 13:27

    I solved this problem by calling measure() method in a popup content view:

    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);
    
    0 讨论(0)
提交回复
热议问题