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

我想让所有不适合 ActionBar 的菜单项进入溢出菜单(从 Action Bar 而不是菜单按钮到达的那个) 即使在 < strong > do 的设备上也有一个菜单按钮。对于用户来说,这似乎比将它们放入单独的菜单列表要直观得多,单独的菜单列表要求用户从触摸(屏幕)交互跳到基于按钮的交互,仅仅因为 ActionBar 的布局无法将它们放在工具条上。

在模拟器上,我可以设置“硬件返回/主键”的值为“否”,并得到这种效果。 我已经找到了一种方法来做到这一点的实际设备,有一个菜单按钮,但不能罚款一个代码。有人能帮我吗?

78925 次浏览

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

这实际上是设计好的。根据 Android 设计指南的兼容性部分,

”... 操作溢出可从菜单硬件键获得。结果弹出的动作... ... 显示在屏幕底部。”

你会在截图中注意到,带有物理菜单按钮的手机在 ActionBar 中没有溢出菜单。这样就避免了用户的不确定性,实际上有两个按钮可用来打开完全相同的菜单。

为了解决跨设备一致性的问题: 最终,对于用户体验来说,你的应用程序与同一设备上的其他应用程序的行为一致,比它在所有设备上的行为一致更为重要。

我认为亚历山大 · 卢卡斯提供了(不幸的)正确答案,所以我把它标记为“正确”答案。我在这里添加的另一个答案是简单地指出任何新的读者到 这篇文章发表在 Android 开发者的博客上作为一个相当完整的主题讨论和一些具体的建议,如何处理您的代码时,从前级11过渡到新的动作栏。

我仍然相信这是一个设计上的错误,没有让菜单按钮表现得像菜单按钮中的一个冗余的“ Action Overflow”按钮,作为一个更好的方式来转换用户体验,但它已经过时了。

在预安装 ICS 的 gmail 应用程序中,当您选择了多个项目时,菜单按钮将被禁用。溢出菜单在这里被“强制”使用溢出按钮而不是物理菜单按钮来触发。有一个名为 ActionBarSherlock 的第三方库,可以让你“强制”使用溢出菜单。但是这只能在 API 级别14或更低(pre-ICS)上工作

我不确定这是否是你要找的,但我在 ActionBar 的菜单中建立了一个子菜单,并将其图标设置为与溢出菜单的图标相匹配。虽然它不会自动发送项目到它,(IE 你必须选择什么是总是可见的,什么是总是溢出)对我来说,这种方法可能会帮助你。

你也可以在这里使用这个小窍门:

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

它将强制应用程序显示溢出菜单。菜单按钮将仍然工作,但它将打开右上角的菜单。

[编辑]因为它已经出现了好几次了: 这次黑客攻击只适用于 Android 3.0中引入的本地 ActionBar,而不适用于 ActionBarSherlock。后者使用自己的内部逻辑来决定是否显示溢出菜单。如果使用 ABS,则所有 < 4.0的平台都由 ABS 处理,因此受其逻辑支配。黑客技术仍然适用于所有 Android 4.0或更高版本的设备(你可以安全地忽略 Android 3.x,因为实际上没有任何带菜单按钮的平板电脑)。

存在一个特殊的 ForceOverflow-Theme,它将强制 ABS 中的菜单,但显然它是 将被删除在未来的版本,由于并发症

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

我通常像这样定义我的菜单来解决这个问题(在我的例子中也使用了 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);
}

:-)

如果您正在使用支持库(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>

如果你使用 工具栏,你可以显示所有版本和所有设备上的溢出,我已经在一些2.x 设备上试过了,它工作。

对不起,如果这个问题是死的。

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

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

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