espinchi
espinchi

Reputation: 9212

Change the margin of the overflow menu in Android

Here's the default position of the contextual menu in Android:

default position

However, the app Inbox has it farther from the top and the right edges of the screen:

inbox

Is there a relatively straight-forward way to achieve this?

Upvotes: 5

Views: 7269

Answers (6)

Vikram
Vikram

Reputation: 51571

Is there a relatively straight-forward way to achieve this?

Yes, of course. And, it only requires 5 lines of code.

Konstantin Loginov takes a bottom-up approach where you literally handle everything in code/design. As much as I appreciate the said approach, it adds complexity to your source. Its always better to check whether a top-down approach is available before resorting to a custom solution.

Here's the top-down version:

Following line will go inside your activity's base theme definition:

<item name="actionOverflowMenuStyle">@style/OverflowMenuStyle</item>

The style OverflowMenuStyle will be defined as:

<style name="OverflowMenuStyle" parent="Widget.AppCompat.PopupMenu.Overflow">
    <item name="android:dropDownHorizontalOffset">-16dp</item>
    <item name="android:dropDownVerticalOffset">16dp</item>
</style>

Results:

Unstyled:

enter image description here

Styled:

enter image description here

Additional notes (possibly trivial to you, but they may help others):

A typical app-theme setup is:

/res/values/styles.xml:

<!-- Values defined here apply to all supported API versions unless overridden in children -->
<BaseTheme />

<!-- Defined values apply to all supported API versions unless overridden in res/values-vXX/styles.xml -->
<AppTheme extends BaseTheme />

/res/values-vXX/styles.xml:

<!-- Values defined here apply to all API versions >= XX unless overridden in res/values-vYY/styles.xml where YY > XX -->
<AppTheme extends BaseTheme />

In this kind of setup, actionOverflowMenuStyle will be defined under BaseTheme. Note the absence of android: prefix - we are overriding actionOverflowMenuStyle provided by appcompat library, not the android system.

Upvotes: 6

Konstantin Loginov
Konstantin Loginov

Reputation: 16000

About Inbox app

What you see on the screenshot, is not exactly a Menu, but a FrameLayout with background with shadows. It's just a custom View.

enter image description here
You can check it with UI Automator Viewer

So you can do same trick and instead of inflating PopupMenu, create a custom View and place it wherever you want.

How to archive same behaviour as a Menu

First, generate background for the popup menu by using Android Action Bar Style Generator(or create a 9patch background by your own).

Then, take menu_dropdown_panel.9 file:

enter image description here

and add paddings there (I used Paint.NET to do it: resize the canvas, insert old image back and move black lines to the sides of the canvas):

enter image description here

Set new background as android:popupBackground in styles:

<style name="AppTheme" parent="Theme.AppCompat.Light.DarkActionBar">
    <item name="popupMenuStyle">@style/PopupMenu.Example</item>
</style>

<style name="PopupMenu.Example" parent="@style/Widget.AppCompat.Light.PopupMenu">
    <item name="android:popupBackground">@drawable/menu_dropdown_panel_background</item>
</style>

Result looks like this:

enter image description hereenter image description here
(vertical position depends on the anchor you passes to PopupMenu's constructor)

To show this PopupMenu, I use this code:

PopupMenu popup = new PopupMenu(MainActivity.this, fab);
popup.getMenuInflater().inflate(R.menu.popup_menu, popup.getMenu());
popup.show();

I hope, it helps

Upvotes: 2

Viral Patel
Viral Patel

Reputation: 33408

There is no straight-forward way. But there is a way to mimic the behavior or create an illusion of it happening.

Something similar is already answered in this post. It was a slightly different question but the answer may serve your purpose too.

Instead of having an actual overflow menu you could "cheat" a little bit. Have an icon in your actionbar that looks like the overflow icon. You should set showAsAction to always on this MenuItem. OnClick of the overflow icon, you show a ListPopupWindow that's anchored to the MenuItem view. If the ListPopupWindow doesn't show up where you want it to, you can call ListPopupWindow.setHorizontalOffset() and ListPopupWindow.setVerticalOffset()

Upvotes: 1

Aditya Vyas-Lakhan
Aditya Vyas-Lakhan

Reputation: 13555

i think this is what exactly you looking for,you need to customize the view

public void onClick(View v) {
    // code from above
    // ...

    popupMenu.show();

    // Try to force some horizontal offset
    try {
        Field fListPopup = menuHelper.getClass().getDeclaredField("mPopup");
        fListPopup.setAccessible(true);
        Object listPopup = fListPopup.get(menuHelper);
        argTypes = new Class[] { int.class };
        Class listPopupClass = listPopup.getClass();

        // Get the width of the popup window
        int width = (Integer) listPopupClass.getDeclaredMethod("getWidth").invoke(listPopup);

        // Invoke setHorizontalOffset() with the negative width to move left by that distance
        listPopupClass.getDeclaredMethod("setHorizontalOffset", argTypes).invoke(listPopup, -width);

        // Invoke show() to update the window's position
        listPopupClass.getDeclaredMethod("show").invoke(listPopup);
    } catch (Exception e) {
        // Again, an exception here indicates a programming error rather than an exceptional condition
        // at runtime
        Log.w(TAG, "Unable to force offset", e);
    }
}

For more Check this

Upvotes: 0

Brendon
Brendon

Reputation: 1368

you can get rid of these issue with this solution, but it wouln't overlay the menu, instead it will act like below the menu button, if you want then try it,

create a style

 <style name="OverflowMenu" parent="Widget.AppCompat.PopupMenu.Overflow" tools:targetApi="21">
    <item name="overlapAnchor">false</item>
    <!--<item name="dropDownVerticalOffset">?attr/actionBarSize</item>-->
    <item name="android:overlapAnchor">false</item>
</style>

then add it to your base style

<item name="actionOverflowMenuStyle">@style/OverflowMenu</item>

Upvotes: 1

C0D3LIC1OU5
C0D3LIC1OU5

Reputation: 8680

This isn't really possible to do with default Overflow Menu. My guess is that they added a custom overflow button to open a custom Activity (to overlay the ActionBar) that has a transparent root view, and, say, a properly sized and positioned CardView for the visible part. CardView is taking care of the border and elevation effects, but there's probably a custom opening animation too. This is custom work.

Upvotes: 0

Related Questions