Reputation: 9212
Here's the default position of the contextual menu in Android:
However, the app Inbox has it farther from the top and the right edges of the screen:
Is there a relatively straight-forward way to achieve this?
Upvotes: 5
Views: 7269
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:
Styled:
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
Reputation: 16000
What you see on the screenshot, is not exactly a Menu
, but a FrameLayout
with background with shadows. It's just a custom View.
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.
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:
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):
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:
(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
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 thisMenuItem
. OnClick of the overflow icon, you show aListPopupWindow
that's anchored to theMenuItem
view. If theListPopupWindow
doesn't show up where you want it to, you can callListPopupWindow.setHorizontalOffset()
andListPopupWindow.setVerticalOffset()
Upvotes: 1
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
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
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