How to force use of overflow menu on devices with menu button
Asked Answered
P

11

161

I'd like to have all of the menu items that don't fit into the ActionBar go into the overflow menu (the one that is reached from the Action Bar not the menu button) even on devices that do have a Menu button. This seems much more intuitive for users than throwing them into a separate menu list that requires the user to jump from a touch(screen) interaction to a button based interaction simply because the layout of the ActionBar can't fit them on the bar.

On the emulator I can set the "Hardware Back/Home Keys" value to "no" and get this effect. I've searched for a way to do this in code for an actual device that has a menu button but can't fine one. Can anyone help me?

Predetermine answered 15/2, 2012 at 1:43 Comment(0)
T
54

EDIT: Modified to answer for the situation of physical menu button.

This is actually prevented by design. According to the Compatibility Section of the Android Design Guide,

"...the action overflow is available from the menu hardware key. The resulting actions popup... is displayed at the bottom of the screen."

You'll note in the screenshots, phones with a physical menu button don't have an overflow menu in the ActionBar. This avoids ambiguity for the user, essentially having two buttons available to open the exact same menu.

To address the issue of consistency across devices: Ultimately it's more important to the user experience that your app behave consistently with every other app on the same device, than that it behave consistently with itself across all devices.

Tosha answered 15/2, 2012 at 2:12 Comment(13)
Alexander - No, I've tried all of the showAsAction values and several combinations and none of them does the trick (at least on the emulator). The overflow menu on the action bar only shows up if I emulate a device without a menu button. I want to see that vertical ellipsis and have overflowing items show up there on devices with a menu button. I've edited my question to make that a bit clearer.Predetermine
Let's step into this conversation and discuss: I know it's prevented by design (i read the design guidelines). But thats kind of %$/%#+, i think. For example: the user is switching from a Galaxy Nexus (-> w Overflow) to a Nexus One (w 4.0/ -> no Overflow). I bet the user won't find the menu items anymore. For that reason I want the same usage for all devices. So, I'm ending up with the same problem as paulp. Isn't there any clean workaround available?Pender
I assume you mean Nexus S (Nexus One only goes as high as Gingerbread (2.3.x)). Your users will find the menu key on a Nexus S, because that's what all Nexus S apps use to show a menu. Ultimately it's more important to the user experience that your app behave consistently with every other app on the same device, than that it behave consistently with itself across all devices.Tosha
I too read the Design Guide first. To me this was a bad choice of design in the support package. A better strategy to transition users AWAY from the button (the objective, right?) would be to make it redundant, put the functionality on screen as well as in the button. As things are now, the button does not list all menu choices, only those not on the actionbar, so this design neither supports a smooth transition to the actionbar nor does it do what it used to do before adding an actionbar (display all the menu choices). I suspect you are right and that there is no simple workaround.Predetermine
Google goes against this in their new Google + apps. It has overflow item regardless of device.. yet they still prevent developers from doing the same and advice against it, to my knowledge.Np
Honestly, I've seen way too many users not try out the menu hard key to ever expect them to. If the design says any user on any phone shouldn't have an on screen indicator that menu options exist, that design is a poorly informed one.Chapell
Google goes against this in multiple apps, including the Play store. They realized it was a bad design. So now we just have to figure out how to work around it the same way they worked around it.Hardback
@dpk or just wait until all of the phones with hard menu buttons die out... cross your fingersDemarche
@AlexLockwood actually hard buttons have their own advantages. soft buttons are easily being touched by accident, especially in horizontal -orientation games. it's too bad that for such devices google doesn't allow to show the overflow button instead of letting the user try to press the menu button each time. there is no clue whatsover to the user that there are more actions in the action bar that will only be shown when pressing the menu button.Zetana
@androiddeveloper I think Alex is referring to a system menu button, regardless of whether it's software or hardware.Speculator
@Speculator i know what he meant, and i meant what i wrote too. buttons of the device (menu,home,back,...) have their own advantages. many times i let others use my phone and they accidentally press the soft buttons, but never press the hard buttons by accident. same thing occurs to me even on my device when i play horizontal games, especially if the buttons of the game (on the screen) are near the soft buttons of the device.Zetana
Well, as of KitKat (4.4) the overflow button is present regardless of whether a hardware menu button is available. So, at least at some point in the future when everyone is 4.4 or higher this should not be an issue.Eydie
Pretty late to the party but I still have an opinion: although I agree with Google's design guidelines, but the practicality asks me to give user an option they're familiar with. If a user does not see an overflow icon, they may not know the options a developer has put in that menu unless out of desperation, they press the hardware menu key. Therefore, I'd have no choice but to override this functionality and show the overflow icon, any way.Acculturate
R
325

You can also use this little hack here:

try {
    ViewConfiguration config = ViewConfiguration.get(this);
    Field menuKeyField = ViewConfiguration.class.getDeclaredField("sHasPermanentMenuKey");
    if (menuKeyField != null) {
        menuKeyField.setAccessible(true);
        menuKeyField.setBoolean(config, false);
    }
} catch (Exception ignored) {
}

Good place to put it would be the onCreate-Method of your Application class.

It will force the App to show the overflow menu. The menu button will still work, but it will open the menu in the top right corner.

[Edit] Since it has come up several times now: This hack only works for the native ActionBar introduced in Android 3.0, not ActionBarSherlock. The latter uses its own internal logic to decide whether to show the overflow menu. If you use ABS, all platforms < 4.0 are handled by ABS and are thus subjected to its logic. The hack will still work for all devices with Android 4.0 or greater (you can safely ignore Android 3.x, since there aren't really any tablets out there with a menu button).

There exists a special ForceOverflow-Theme that will force the menu in ABS, but apperently it is going to be removed in future versions due to complications.

Rouen answered 11/7, 2012 at 17:34 Comment(19)
I am not sure whether I want to implement this but your code seems to work as expected. Thank you! It is good to have options. Curious to know, how you figured this out.Solfatara
I looked through the source code. Treasure grove of undocumented features :) Just make sure you have a workable fallback for things like that.Rouen
It works on Gingerbread, ICS and Jelly bean. I know it may break in the future, but it just work right now :)Nebula
@YanChengCHEOK I doubt it works on Gingerbread. There is no field called "sHasPermanentMenuKey" in Gingerbread.Tacklind
Awesome find. Just dropped it in and it works perfectly on all my devices. @Singularity, since the ActionBar was added in Honeycomb, this hack is really only for Honeycomb and newer. For that matter, I believe all Honeycomb devices had no hardware menu button, so I think this hack is really only needed for Ice Cream Sandwich and newer devices. I use ActionBarSherlock on older devices, so just a little hack there and I will be able to show the overflow button on older devices as well. This hack is mainly to override behavior in the OS based ActionBar, which is less in our control.Frizzle
This hack doesn't work with recent ActionBarSherlock. On 2.3 devices it won't show overflow button.Wilcher
Thanks a lot! This is really great. I wanted to put review, bugreport and share actions into the overflow, but it was not showing on Nexus S. Users won't even click the Menu button. With the overflow users sees that extra actions are available.Fajardo
@TimoOhr I understood this will not work with ActionBarScherlock but what about new ActionBarComp? I would need to suport 2.3.x .. Thanks..Ento
@Ento I'm pretty late on the comment here, but I just tried this with the most recent version of ActionBarCompat, and it DID work.Braud
This works great! However I noticed that when you press the hardware menu key you will hear the menu sound effect twice. Not a big deal but is there a way to work around that?Plafond
This works on the Samsung Galaxy S3 and S4, but not on the LG G2 (suspect they are hard coding the check to show overflow menu button)Trellas
Beautiful! If Eclipse gives you like 6 different imports to choose from for Field choose this one java.lang.reflect.Field ;)Hilly
@ewoks Sadly it won't work with device under 3.0. As the source code of AppCompat public boolean showsOverflowMenuButton() { // Only show overflow on HC+ devices return Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB; }Boatwright
Just ran into the same problem with the LG G2. I wonder if it's because the menu key is soft, so it technically doesn't have a 'permanent' menu key.Hornback
What do people mean it doesn't work on LG G2 (I don't have one to test on) Is it that the menu button shows the options rather than action bar, or the options are not accessible at all or something else?Zurheide
This doesn't work on a 3.0 Honeycomb emulator. The overflow menu never appears. Only the hardware menu button works.Charissecharita
On a Galaxy S2, this displays the overflow menu as intended. But pressing the menu button open the "normal" menu (not the overflow menu).Albania
It may sound weird but I am experiencing different behaviour of this code in eclipse and android studio. In eclipse, on clicking the physical button the menu appears next to action bar but in Android Studio the menu is appearing at the bottom of the screen.Emelun
This is also what the com.android.fmradio app is using: found it in the official Android source code: FmMainActivity.javaOutface
T
54

EDIT: Modified to answer for the situation of physical menu button.

This is actually prevented by design. According to the Compatibility Section of the Android Design Guide,

"...the action overflow is available from the menu hardware key. The resulting actions popup... is displayed at the bottom of the screen."

You'll note in the screenshots, phones with a physical menu button don't have an overflow menu in the ActionBar. This avoids ambiguity for the user, essentially having two buttons available to open the exact same menu.

To address the issue of consistency across devices: Ultimately it's more important to the user experience that your app behave consistently with every other app on the same device, than that it behave consistently with itself across all devices.

Tosha answered 15/2, 2012 at 2:12 Comment(13)
Alexander - No, I've tried all of the showAsAction values and several combinations and none of them does the trick (at least on the emulator). The overflow menu on the action bar only shows up if I emulate a device without a menu button. I want to see that vertical ellipsis and have overflowing items show up there on devices with a menu button. I've edited my question to make that a bit clearer.Predetermine
Let's step into this conversation and discuss: I know it's prevented by design (i read the design guidelines). But thats kind of %$/%#+, i think. For example: the user is switching from a Galaxy Nexus (-> w Overflow) to a Nexus One (w 4.0/ -> no Overflow). I bet the user won't find the menu items anymore. For that reason I want the same usage for all devices. So, I'm ending up with the same problem as paulp. Isn't there any clean workaround available?Pender
I assume you mean Nexus S (Nexus One only goes as high as Gingerbread (2.3.x)). Your users will find the menu key on a Nexus S, because that's what all Nexus S apps use to show a menu. Ultimately it's more important to the user experience that your app behave consistently with every other app on the same device, than that it behave consistently with itself across all devices.Tosha
I too read the Design Guide first. To me this was a bad choice of design in the support package. A better strategy to transition users AWAY from the button (the objective, right?) would be to make it redundant, put the functionality on screen as well as in the button. As things are now, the button does not list all menu choices, only those not on the actionbar, so this design neither supports a smooth transition to the actionbar nor does it do what it used to do before adding an actionbar (display all the menu choices). I suspect you are right and that there is no simple workaround.Predetermine
Google goes against this in their new Google + apps. It has overflow item regardless of device.. yet they still prevent developers from doing the same and advice against it, to my knowledge.Np
Honestly, I've seen way too many users not try out the menu hard key to ever expect them to. If the design says any user on any phone shouldn't have an on screen indicator that menu options exist, that design is a poorly informed one.Chapell
Google goes against this in multiple apps, including the Play store. They realized it was a bad design. So now we just have to figure out how to work around it the same way they worked around it.Hardback
@dpk or just wait until all of the phones with hard menu buttons die out... cross your fingersDemarche
@AlexLockwood actually hard buttons have their own advantages. soft buttons are easily being touched by accident, especially in horizontal -orientation games. it's too bad that for such devices google doesn't allow to show the overflow button instead of letting the user try to press the menu button each time. there is no clue whatsover to the user that there are more actions in the action bar that will only be shown when pressing the menu button.Zetana
@androiddeveloper I think Alex is referring to a system menu button, regardless of whether it's software or hardware.Speculator
@Speculator i know what he meant, and i meant what i wrote too. buttons of the device (menu,home,back,...) have their own advantages. many times i let others use my phone and they accidentally press the soft buttons, but never press the hard buttons by accident. same thing occurs to me even on my device when i play horizontal games, especially if the buttons of the game (on the screen) are near the soft buttons of the device.Zetana
Well, as of KitKat (4.4) the overflow button is present regardless of whether a hardware menu button is available. So, at least at some point in the future when everyone is 4.4 or higher this should not be an issue.Eydie
Pretty late to the party but I still have an opinion: although I agree with Google's design guidelines, but the practicality asks me to give user an option they're familiar with. If a user does not see an overflow icon, they may not know the options a developer has put in that menu unless out of desperation, they press the hardware menu key. Therefore, I'd have no choice but to override this functionality and show the overflow icon, any way.Acculturate
I
35

I use to workaround it by defining my menu like this (also with ActionBarSherlock icon used in my example):

<menu xmlns:android="http://schemas.android.com/apk/res/android" >

    <item
        android:id="@+id/menu_overflow"
        android:icon="@drawable/abs__ic_menu_moreoverflow_normal_holo_light"
        android:orderInCategory="11111"
        android:showAsAction="always">
        <menu>
            <item
                android:id="@+id/menu_overflow_item1"
                android:showAsAction="never"
                android:title="@string/overflow_item1_title"/>
            <item
                android:id="@+id/menu_overflow_item2"
                android:showAsAction="never"
                android:title="@string/overflow_item2_title"/>
        </menu>
    </item>

</menu>

I admit that this may require manual "overflow-management" in your xml, but I found this solution useful.

You can also force device to use HW button to open the overflow menu, in your activity:

private Menu mainMenu;

@Override
public boolean onCreateOptionsMenu(Menu menu) {
    // TODO: init menu here...
    // then:
    mainMenu=menu;
    return true;
}

@Override
public boolean onKeyUp(int keycode, KeyEvent e) {
    switch(keycode) {
        case KeyEvent.KEYCODE_MENU:
            if (mainMenu !=null) {
                mainMenu.performIdentifierAction(R.id.menu_overflow, 0);
            }
    }

    return super.onKeyUp(keycode, e);
}

:-)

Interracial answered 30/8, 2013 at 10:1 Comment(2)
how to use HW button to open the overflow menu?Nigelniger
See my updated answer for opening overflow menu with HW button. :)Greenness
S
11

If you are using the action bar from the support library (android.support.v7.app.ActionBar), use the following:

<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:yorapp="http://schemas.android.com/apk/res-auto" >

    <item
        android:id="@+id/menu_overflow"
        android:icon="@drawable/icon"
        yourapp:showAsAction="always"
        android:title="">
        <menu>
            <item
                android:id="@+id/item1"
                android:title="item1"/>
            <item
                android:id="@+id/item2"
                android:title="item2"/>
        </menu>
    </item>

</menu>
Suprasegmental answered 26/12, 2013 at 6:46 Comment(1)
When using the support library I implemented this too and it works ok on both pre and post 3.0 devicesPachyderm
R
7

This kind of method is prevented by the Android Developers Design System, but I found a way to pass it:

Add this to your XML menu file:

<item android:id="@+id/pick_action_provider"
    android:showAsAction="always"
    android:title="More"
    android:icon="@drawable/ic_action_overflow"
    android:actionProviderClass="com.example.AppPickActionProvider" />

Next, create a class named 'AppPickActionProvider', and copy the following code to it:

    package com.example;

import android.content.Context;
import android.util.Log;
import android.view.ActionProvider;
import android.view.MenuItem;
import android.view.MenuItem.OnMenuItemClickListener;
import android.view.SubMenu;
import android.view.View;

public class AppPickActionProvider extends ActionProvider implements
        OnMenuItemClickListener {

    static final int LIST_LENGTH = 3;

    Context mContext;

    public AppPickActionProvider(Context context) {
        super(context);
        mContext = context;
    }

    @Override
    public View onCreateActionView() {
        Log.d(this.getClass().getSimpleName(), "onCreateActionView");

        return null;
    }

    @Override
    public boolean onPerformDefaultAction() {
        Log.d(this.getClass().getSimpleName(), "onPerformDefaultAction");

        return super.onPerformDefaultAction();
    }

    @Override
    public boolean hasSubMenu() {
        Log.d(this.getClass().getSimpleName(), "hasSubMenu");

        return true;
    }

    @Override
    public void onPrepareSubMenu(SubMenu subMenu) {
        Log.d(this.getClass().getSimpleName(), "onPrepareSubMenu");

        subMenu.clear();

        subMenu.add(0, 1, 1, "Item1")
        .setIcon(R.drawable.ic_action_home).setOnMenuItemClickListener(this);

        subMenu.add(0, 2, 1, "Item2")
            .setIcon(R.drawable.ic_action_downloads).setOnMenuItemClickListener(this);
    }

    @Override
    public boolean onMenuItemClick(MenuItem item) {
        switch(item.getItemId())
        {
            case 1:

                // What will happen when the user presses the first menu item ( 'Item1' )

                break;
            case 2:

                // What will happen when the user presses the second menu item ( 'Item2' )

                break;

        }

        return true;
    }
}
Rettarettig answered 10/1, 2013 at 10:17 Comment(1)
what's the difference between using this method and just using a submenu , as shown here: https://mcmap.net/q/151944/-display-action-bar-menu-button ?Zetana
P
5

Well I think that Alexander Lucas has provided the (unfortunately) correct answer so I'm marking it as the "correct" one. The alternative answer I'm adding here is simply to point any new readers to this post in the Android Developers blog as a rather complete discussion of the topic with some specific suggestions as to how to deal with your code when transitioning from pre-level 11 to the new Action Bar.

I still believe it was a design mistake not have the menu button behave as a redundant "Action Overflow" button in menu button enabled devices as a better way to transition the user experience but its water under the bridge at this point.

Predetermine answered 9/3, 2012 at 19:33 Comment(2)
I agree completely with you about the design mistake - and am finding this frustrating!Darn
I would agree with you on this, if it wasn't for the fact that Google itself started to violate that rule in its recent G+ app. And rightfully so. The menu button isn't legacy, even new devices like the SGS3 have it. It's here to stay, unfortunately. And it seriously hampers usability.Rouen
B
4

I'm not sure if this is what you're looking for, but I built a Submenu within the ActionBar's Menu and set its icon to match the Overflow Menu's Icon. Although it wont have items automatically sent to it, (IE you have to choose what's always visible and what's always overflowed) it seems to me that this approach may help you.

Beatitude answered 9/7, 2012 at 18:11 Comment(0)
F
2

In the gmail app that comes with ICS pre-installed, the menu button is disabled when you have multiple items selected. The overflow menu is here "forced" to be triggered by the use of the overflow button instead of the physical menu button. Theres a 3rd-party lib called ActionBarSherlock which lets you "force" the overflow menu. But this will only work on API level 14 or lower(pre-ICS)

Freehand answered 26/5, 2012 at 2:46 Comment(0)
V
2

If you use Toolbar, you can show the overflow on all versions and all devices, I've tried on some 2.x devices, it works.

Vincents answered 12/11, 2014 at 15:50 Comment(0)
N
1

Sorry if this problem is dead.

Here is what I did to resolve the error. I went to layouts and created two ones containing toolbars. One was a layout for sdk version 8 and the other was for sdk version 21. On version 8, I used the android.support.v7.widget.Toolbar while I used android.widget.Toolbar on the sdk 21 layout.

Then I inflate the toolbar in my activity. I check the sdk to see if it was 21 or higher. I then inflate the corresponding layout. This forces the hardware button to map onto the toolbar you actually designed.

Neume answered 31/8, 2015 at 6:33 Comment(0)
T
0

For anyone using the new Toolbar:

private Toolbar mToolbar;

@Override
protected void onCreate(Bundle bundle) {
    super.onCreate(bundle);

    mToolbar = (Toolbar) findViewById(R.id.toolbar);
    setSupportActionBar(mToolbar);

    ...
}


@Override
public boolean onKeyUp(int keycode, KeyEvent e) {
    switch(keycode) {
        case KeyEvent.KEYCODE_MENU:
            mToolbar.showOverflowMenu();
            return true;
        }

    return super.onKeyUp(keycode, e);
}
Tusche answered 31/8, 2016 at 23:25 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.