33

I am developing an application for Android and I am using a popup window when the user clicks a specific menu bar object(consisting of small images lined up horizontally) on the bottom of the screen.

On the click I want the popup window to be anchored to the top-left corner of the view that was clicked and be shown on top.

The only methods that seem to be relevant are showAsDropDown(View anchor, int xoff, int yoff) and showAtLocation(View parent, int gravity, int x, int y). The problem with showAsDropDown is that it is anchored to the bottom-left corner of the view.

Is there another way to implement this?

Matt
  • 1,017
  • 2
  • 11
  • 27

11 Answers11

48

popupWindow.showAtLocation(...) actually shows the window absolutely positioned on the screen (not even the application). The anchor in that call is only used for its window token. The coordinates are offsets from the given gravity.

What you actually want to use is:

popupWindow.showAsDropDown(anchor, offsetX, offsetY, gravity);

This call is only available in API 19+, so in earlier versions you need to use:

popupWindow.showAsDropdown(anchor, offsetX, offsetY);

These calls show the popup window relative to the specified anchor view. Note that the default gravity (when calling without specified gravity) is Gravity.TOP|Gravity.START so if you are explicitly using Gravity.LEFT in various spots in your app you will have a bad time :)

William
  • 2,917
  • 5
  • 30
  • 47
  • 1
    That's the one I was looking for. All you need to calculate is the offset according to the ui element you use.. – Alpaslan Jun 22 '15 at 08:50
17

I wrote a sample Kotlin code which will show a PopupWindow above the anchor view.

private fun showPopupWindow(anchor: View) {
    PopupWindow(anchor.context).apply {
        isOutsideTouchable = true
        val inflater = LayoutInflater.from(anchor.context)
        contentView = inflater.inflate(R.layout.popup_layout, null).apply {
            measure(
                View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED),
                View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED)
            )
        }
    }.also { popupWindow ->
        // Absolute location of the anchor view
        val location = IntArray(2).apply {
            anchor.getLocationOnScreen(this)
        }
        val size = Size(
            popupWindow.contentView.measuredWidth,
            popupWindow.contentView.measuredHeight
        )
        popupWindow.showAtLocation(
            anchor,
            Gravity.TOP or Gravity.START,
            location[0] - (size.width - anchor.width) / 2,
            location[1] - size.height
        )
    }
}
Vikas Patidar
  • 42,865
  • 22
  • 93
  • 106
10

You just needed to move the popupWindow by the height of its anchor using the yoff parameter in the showAsDropDown(View anchor, int xoff, int yoff) syntax.

popupWindow.showAsDropDown(anchor, 0, -anchor.getHeight()+popupView.getHeight);

Also, be aware that if the max height allowed to anchor does not allow for the transformation, the popup might not show up properly.

theSlyest
  • 429
  • 1
  • 6
  • 16
  • Please elaborate on how this code answers the question (this answer was in the Low Quality Posts review queue). – JAL Apr 06 '16 at 21:10
7
popupWindow.showAtLocation(anchor, Gravity.BOTTOM, 0, anchor.getHeight());
David
  • 15,894
  • 22
  • 55
  • 66
Farhan C K
  • 1,159
  • 18
  • 35
  • You need to add parent view instead of anchor and also need to pass the exact location of the popup where you want to place it. – Er.Rohit Sharma Nov 22 '19 at 10:47
6

I have this code: PopupWindow below a specific view (Gravity End) for all sdk version.

        // display the popup[![enter image description here][1]][1]
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
            mPopupWindow.showAsDropDown(v, 0, 0, Gravity.END);
        } else {
            mPopupWindow.showAsDropDown(v, v.getWidth() - mPopupWindow.getWidth(), 0);
        }

Here View v is ImageButton Calendar.

Ho Luong
  • 726
  • 8
  • 12
  • This worked great for me. I was using showAtLocation for SDK >= 24, but it didn't work for all devices. This worked for every device I tested so far. – FerDensetsu Sep 13 '18 at 16:38
5

The one you want to use is showAtLocation(...). You specify the anchor view (the one the user clicks), and position it relative to that via the gravity parameter and offsets. Think of the gravity parameter like the PopupWindow is almost like a child view and the parent view is like a container layout.

You should be able to put Gravity.LEFT | Gravity.TOP as the parameter.

Wenger
  • 989
  • 2
  • 12
  • 35
  • 12
    No such luck, the PopupWindow will show top-left corner of the window with that line (popupWindow.showAsLocation(anchor, Gravity.TOP|Gravity.LEFT, 0, 0)). –  Apr 18 '14 at 18:50
4

you can display the popup always above the anchor by following

popupWindow.showAsDropDown(anchor, 0, -anchor.getHeight()-popupView.getHeight);
rollstuhlfahrer
  • 3,988
  • 9
  • 25
  • 38
3

Sample example:

ScrollView scrollView = new ScrollView(context);
popupWindow.setContentView(scrollView);
scrollView.measure(View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED),                 
View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED));
int he=scrollView.getMeasuredHeight();
popupWindow.showAsDropDown(items,0, -items.getHeight()-he);
Sumit Garai
  • 1,205
  • 8
  • 6
0

After using so many solutions, I got one solution to display the PopupWindow above any View in Kotlin.

To display the popup window above the view, you can use the showAsDropDown() function.

popUp.showAsDropDown(v, 0, (-0.2 * v.height).roundToInt(), Gravity.CENTER)

With:

  • v: View(Anchor)
  • 0: offSetX
  • (-0.2 * v.height).roundToInt(): offSetY
  • Gravity.CENTER: Gravity

For example: https://medium.com/@bhattmeet887/popupwindow-above-the-specific-view-kotlin-ab1a199581eb

Meet Bhatt
  • 11
  • 4
0

Here's using the android-x solution, which should even work in case you have a floating UI using SAW permission (System Alert Window) :

@SuppressLint("InflateParams")
private fun showPopupWindow(anchor: View) {
    val popupWindow = PopupWindow(anchor.context)
    popupWindow.isFocusable = true
    popupWindow.inputMethodMode = PopupWindow.INPUT_METHOD_NOT_NEEDED
    popupWindow.contentView = LayoutInflater.from(anchor.context).inflate(R.layout.popup_layout, null)
    PopupWindowCompat.showAsDropDown(popupWindow, anchor, 0, 0, Gravity.BOTTOM)
}

This is for alignment of bottom-left.

If you need bottom-center, you could use this, for example:

@SuppressLint("InflateParams")
private fun showPopupWindow(anchor: View) {
    val popupWindow = PopupWindow(anchor.context)
    popupWindow.isFocusable = true
    popupWindow.inputMethodMode = PopupWindow.INPUT_METHOD_NOT_NEEDED
    val inflater = LayoutInflater.from(anchor.context)
    val contentView = inflater.inflate(R.layout.popup_layout, null)
    contentView.measure(View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED), View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED))
    popupWindow.contentView = contentView
    PopupWindowCompat.showAsDropDown(popupWindow, anchor, (anchor.measuredWidth - contentView.measuredWidth) / 2, 0, Gravity.BOTTOM)
}
android developer
  • 114,585
  • 152
  • 739
  • 1,270
-5

popupwindow.showAsDropDown(anchor,0, -125); this thing work for me

Vishal Mokal
  • 792
  • 1
  • 5
  • 22