28

I am using the default pop menu and expecting the behavior of the same. Everything is working fine. What my concern is regarding the rendering of pop up menu. My pop up menu sticks to the right of the screen.

I want the behavior as used by Youtube app for android.enter image description here

I am mainly not able to provide right margin to my pop up menu. Please help. I have tried providing Gravity to PopUp Menu. But Pop Up Menu sticks to the Right of screen.

PopupMenu popupMenu = new PopupMenu(mContext, anchor, Gravity.LEFT);
popupMenu.getMenuInflater().inflate(R.menu.menu_edit_accessory, popupMenu.getMenu());
Vadim Kotov
  • 8,084
  • 8
  • 48
  • 62
Anchit Mittal
  • 3,412
  • 4
  • 28
  • 48
  • Basically, it's not sticking to the right to the screen, but it sticks to the anchor View you set in the Constructor as anchor. I don't know how Youtube presents PopupMenus, but you could try using a different anchor, i.E. setting an invisible view just for the purpose of attaching your PopupMenu to it. – Benjamin Scharbau Dec 24 '15 at 08:01
  • I tried the same. but still it sticks to the right. I have tried creating the fake anchor view but still the behavior is same. – Anchit Mittal Dec 24 '15 at 08:03
  • Oh, you're right, I just confirmed by myself. Not sure if that's the way YouTube does it, but I would suggest trying to use a `PopupWindow` instead of the `PopupMenu`. The `PopupWindow` is anchored more nicely to the view, but you have to lay it out by yourself – Benjamin Scharbau Dec 24 '15 at 08:10

5 Answers5

55

You can change your PopupMenu's position by using the following attributes: gravity, dropDownHorizontalOffset and dropDownVerticalOffset

First set gravity to Gravity.END

popup.setGravity(Gravity.END);

Then change your dropdown-offsets by creating a style

<style name="MyPopupMenu" parent="@style/Widget.AppCompat.PopupMenu">
    <item name="android:dropDownHorizontalOffset">-4dp</item>
    <item name="android:dropDownVerticalOffset">4dp</item>
</style>

If you want to overlap the anchor view use

parent="@style/Widget.AppCompat.PopupMenu.Overflow"

Lastly apply MyPopupMenu to your theme

<item name="popupMenuStyle">@style/MyPopupMenu</item>
Markus Rubey
  • 5,153
  • 2
  • 21
  • 17
  • 3
    Thanks, setting gravity to Gravity.END did the trick for me. The default NO_GRAVITY value seems to be for ignoring alignment with its anchor. – somedev Sep 20 '17 at 12:07
  • works for partially. 1. in my theme I had to add `...`, without the `android:` namespace it didn't apply the menu style. 2. It applies the parent style, but the offset corrections don't have any effect. – quezak Dec 13 '17 at 20:19
  • 4
    update for the comment above: the offsets work after all after I corrected one stupid mistake :) And if you don't want to enable popup style globally, you can instantiate it with a specified style: `new PopupMenu(context, anchor, Gravity.END, 0, R.style.PopupMenuStyle)`. – quezak Dec 13 '17 at 20:58
  • @quezak setting style like this `new PopupMenu(context, anchor, Gravity.END, 0, R.style.PopupMenuStyle)` does not work – Syed Arsalan Kazmi Feb 23 '22 at 21:58
  • 1
    @syed-arsalan-kazmi I commented that 5 years ago, I'm pretty sure it's outdated by now :) I'm not working in Android since then so I can't help again. – quezak Mar 10 '22 at 18:35
8

This is a little late but I hope this helps someone.

I was trying to do what you were doing with a PopupMenu but nothing was working for me until I learned about ListPopupWindow. It's a way better alternative. Much more flexible in my opinion and you can achieve the margin-spacing you were asking about.

Here's the code:

public class MainActivity extends AppCompatActivity
{
    private ImageButton mMoreOptionsButton;
    private ArrayAdapter<String> mPopupAdapter;
    private ArrayList<String> mOptionsArray = 
            new ArrayList<>(Arrays.asList("Option1", "Option2", "Option3"));
    private ListPopupWindow mPopupWindow;

    @Override
    protected void onCreate(Bundle savedInstanceState)
    {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        mMoreOptionsButton = (ImageButton) view.findViewById(R.id.more_options_button);
        setupPopupWindow();
    }

    private void setupPopupWindow()
    {
        mPopupAdapter = new ArrayAdapter<>(MainActivity.this, android.R.layout.simple_spinner_dropdown_item, mOptionsArray);
        mPopupWindow = new ListPopupWindow(MainActivity.this);
        mPopupWindow.setAdapter(mPopupAdapter);
        mPopupWindow.setAnchorView(mMoreOptionsButton);
        mPopupWindow.setWidth(500);
        mPopupWindow.setHorizontalOffset(-380); //<--this provides the margin you need
        //if you need a custom background color for the popup window, use this line:
        mPopupWindow.setBackgroundDrawable(new ColorDrawable(ContextCompat.getColor(MainActivity.this, R.color.gray)));

        mPopupWindow.setOnItemClickListener(new AdapterView.OnItemClickListener() {
            @Override
            public void onItemClick(AdapterView<?> parent, View view, int position, long id)
            {
                //do something with item by referring to it using the "position" parameter
            }
        });

        mMoreOptionsButton.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v)
            {
                mPopupWindow.show();
            }
        });
    }
}

The key part is calling mPopupWindow.setHorizontalOffset(). Be aware that this method is tricky. Depending on the value you set in mPopupWindow.setWidth() you will have to adjust the value in setHorizontalOffset() accordingly. It just so happened that for my app, -380 was the perfect amount of margin I needed from the end. So you may have to play with this value a bit.

I believe the same can be said for using setHeight() and setVerticalOffset() if you want some margin at the top of your popup window.

Hope this helps :]

David Velasquez
  • 2,346
  • 1
  • 26
  • 46
2
  PopupMenu popup = null;
        if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.LOLLIPOP_MR1) {
            popup = new PopupMenu(context, anchorView, Gravity.END, 0, R.style.MyPopupMenu);
        }else{
            popup = new PopupMenu(context, anchorView);
        }

style

<style name="MyPopupMenu" parent="@style/Widget.AppCompat.PopupMenu">
    <item name="android:dropDownHorizontalOffset">-4dp</item>
    <item name="android:dropDownVerticalOffset">4dp</item>
</style>
Ankit Aman
  • 999
  • 6
  • 15
1

You can set popUpWindow at particular location

popupWindow .showAtLocation(popupView, Gravity.CENTER, 0, 0);

public void showAtLocation(View parent, int gravity, int x, int y) {
        showAtLocation(parent.getWindowToken(), gravity, x, y);
    }

If you want to show it as DropDown then you can try

public void showAsDropDown(View anchor, int xoff, int yoff) {
        showAsDropDown(anchor, xoff, yoff, DEFAULT_ANCHORED_GRAVITY);
    }

Take a look on Documentation of PopupWindow http://developer.android.com/intl/es/reference/android/widget/PopupWindow.html

Anuj Sharma
  • 4,294
  • 2
  • 37
  • 53
-1

Just declare your popup menu like this var popup = PopupMenu(this.requireContext(), isw_settings_icon, Gravity.END, 0, R.style.yourmenustyle)