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

我想让所有不适合进入ActionBar的菜单项进入到溢出菜单(即从操作栏而不是菜单按钮到达的菜单项), 即使在具有菜单按钮的设备上也是如此 。 对于用户来说这似乎更直观,而不是把它们放在一个单独的菜单列表中,这需要用户从触摸(屏幕)交互跳转到基于按钮的交互,因为ActionBar的布局不能适应它们。

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

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

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

“…操作溢出可以从菜单硬件键获得,弹出的结果显示在屏幕的底部。

你会在屏幕截图中注意到,带有物理菜单按钮的手机在ActionBar中没有溢出菜单。 这避免了用户的不明确性,基本上有两个按钮可用于打开完全相同的菜单。

要解决设备之间的一致性问题:最终,对于用户体验而言,您的应用与同一设备上的所有其他应用的行为保持一致,而不是在所有设备上与其自身的行为保持一致。

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

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中的菜单,但显然它会在未来版本中由于复杂而被删除 。

我通过定义我的菜单来解决这个问题(同样在我的例子中使用了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手动“溢出管理”,但我发现这个解决方案有用。

您也可以强制设备使用硬件按钮打开溢出菜单,在您的活动中:

 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> 

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

那么我认为亚历山大·卢卡斯(Alexander Lucas)提供了(不幸的)正确的答案,所以我将其标记为“正确的”答案。 我在这里添加的替代答案只是指出任何新读者在Android开发者博客中的这篇文章作为一个相当完整的讨论的主题与一些具体的建议,如何处理您的代码从11级转换时到新的行动酒吧。

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

我不知道这是你要找的,但我在ActionBar的菜单中建立了一个子菜单,并设置它的图标以匹配溢出菜单的图标。 虽然它不会有物品自动发送给它(IE浏览器,你必须选择总是可见的东西,总是溢出),在我看来,这种方法可能会帮助你。

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

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

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

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

然后我在我的活动中充气工具栏。 我检查了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); }