如何在菜单按钮的设备上强制使用溢出菜单

时间:2012-02-15 01:44:00

标签: android android-actionbar

我想让所有不适合ActionBar的菜单项进入溢出菜单(从操作栏到菜单按钮而不是菜单按钮)即使在< strong>执行有一个菜单按钮。对于用户而言,这似乎更直观,而不是将它们放入单独的菜单列表中,该列表要求用户从触摸(屏幕)交互跳转到基于按钮的交互,这仅仅是因为ActionBar的布局不适合他们在栏上。

在模拟器上,我可以将“硬件后退/主页键”值设置为“否”并获得此效果。 我已经在代码中搜索了一种方法来实现具有菜单按钮但不能很好的设备的实际设备。任何人都可以帮助我吗?

11 个答案:

答案 0 :(得分:323)

你也可以在这里使用这个小黑客:

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) {
}

放置它的好地方是onCreate - Application类的方法。

它将强制App显示溢出菜单。菜单按钮仍然有效,但它会打开右上角的菜单。

[编辑]因为它现在出现了好几次:这个hack只适用于Android 3.0中引入的原生ActionBar,而不适用于ActionBarSherlock。后者使用自己的内部逻辑来决定是否显示溢出菜单。如果你使用ABS,所有平台&lt; 4.0由ABS处理,因此受其逻辑的影响。黑客仍然适用于Android 4.0或更高版本的所有设备(您可以放心地忽略Android 3.x,因为没有任何平板电脑带有菜单按钮)。

存在一个特殊的ForceOverflow-Theme,它会强制显示ABS中的菜单,但显然是going to be removed in future versions due to complications

答案 1 :(得分:54)

编辑:修改为回答物理菜单按钮的情况。

这实际上是通过设计来防止的。根据{{​​3}},

“...操作溢出可从菜单硬件键获得。生成的操作弹出窗口...显示在屏幕底部。”

您将在屏幕截图中注意到,带有物理菜单按钮的手机在ActionBar中没有溢出菜单。这避免了用户的歧义,实际上有两个按钮可用于打开完全相同的菜单。

解决跨设备一致性的问题:最终,您的应用与同一设备上的所有其他应用一致的用户体验比在所有设备上与其自身表现一致更为重要。

答案 2 :(得分:35)

我通过像这样定义我的菜单(也使用我的示例中使用的ActionBarSherlock图标)来解决它:

<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>

我承认这可能需要在你的xml中手动“溢出管理”,但我发现这个解决方案很有用。

您还可以强制设备在您的活动中使用HW按钮打开溢出菜单:

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);
}

: - )

答案 3 :(得分:11)

如果您使用支持库(android.support.v7.app.ActionBar)中的操作栏,请使用以下命令:

<?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>

答案 4 :(得分:7)

Android开发者设计系统阻止了这种方法,但我找到了传递它的方法:

将其添加到XML菜单文件中:

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

接下来,创建一个名为“AppPickActionProvider”的类,并将以下代码复制到其中:

    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;
    }
}

答案 5 :(得分:5)

嗯,我认为Alexander Lucas提供了(不幸的)正确答案,因此我将其标记为“正确”答案。我在这里添加的替代答案只是将任何新读者指向this post in the Android Developers blog作为对该主题的相当完整的讨论,并提供一些具体的建议,以便在从11级前转换到新的行动吧。

我仍然认为这是一个设计错误,没有菜单按钮在启用菜单按钮的设备中表现为冗余的“动作溢出”按钮,作为转换用户体验的更好方式,但此时它在桥下的水。< / p>

答案 6 :(得分:4)

我不确定这是否是您正在寻找的,但我在ActionBar的菜单中构建了一个子菜单,并设置其图标以匹配溢出菜单的图标。虽然它没有自动发送给它的项目,(IE你必须选择总是可见的东西和总是溢出的东西),但在我看来,这种方法可能对你有所帮助。

答案 7 :(得分:2)

在预安装ICS的gmail应用程序中,如果选择了多个项目,则会禁用菜单按钮。溢出菜单在这里“强制”通过使用溢出按钮而不是物理菜单按钮来触发。这是一个名为ActionBarSherlock的第三方库,可以让你“强制”溢出菜单。但这只适用于API级别14或更低级别(pre-ICS)

答案 8 :(得分:2)

如果您使用Toolbar,则可以在所有版本和所有设备上显示溢出,我已尝试在某些2.x设备上运行。

答案 9 :(得分:1)

对不起,如果这个问题已经死了。

以下是我为解决错误所做的工作。我去了布局并创建了两个包含工具栏的布局。一个是sdk版本8的布局,另一个是sdk版本21.在版本8,我使用了android.support.v7.widget.Toolbar,而我在sdk 21布局上使用了android.widget.Toolbar。

然后我在我的活动中给工具栏充气。我检查sdk是否是21或更高。然后我膨胀相应的布局。这会强制硬件按钮映射到您实际设计的工具栏上。

答案 10 :(得分:0)

对于使用新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);
}