我想让所有不适合操作栏的菜单项进入溢出菜单(从操作栏而不是菜单按钮到达的菜单项),即使在有菜单按钮的设备上也是如此。对于用户来说,这似乎比将它们放入单独的菜单列表更直观,因为 ActionBar 的布局无法将它们放在栏上,因此需要用户从触摸(屏幕)交互跳转到基于按钮的交互。
在模拟器上,我可以将“Hardware Back/Home Keys”值设置为“no”并获得此效果。我已经在代码中搜索了一种方法来为具有菜单按钮但不能很好的实际设备执行此操作。谁能帮我?
你也可以在这里使用这个小技巧:
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) {
}
放置它的好地方是您的 Application 类的 onCreate
-Method。
它将强制应用程序显示溢出菜单。菜单按钮仍然有效,但会在右上角打开菜单。
[编辑] 因为它现在已经出现了好几次:这个 hack 只适用于 Android 3.0 中引入的本机 ActionBar,而不是 ActionBarSherlock。后者使用自己的内部逻辑来决定是否显示溢出菜单。如果您使用 ABS,则所有小于 4.0 的平台都由 ABS 处理,因此受制于其逻辑。该 hack 仍然适用于 Android 4.0 或更高版本的所有设备(您可以放心地忽略 Android 3.x,因为实际上没有任何带有菜单按钮的平板电脑)。
有一个特殊的 ForceOverflow-Theme 将强制 ABS 中的菜单,但显然它是 going to be removed in future versions due to complications。
编辑:修改以回答物理菜单按钮的情况。
这实际上是通过设计防止的。根据Compatibility Section of the Android Design Guide,
“...操作溢出可从菜单硬件键获得。结果操作弹出...显示在屏幕底部。”
您会在屏幕截图中注意到,带有物理菜单按钮的手机在操作栏中没有溢出菜单。这避免了用户的歧义,本质上有两个按钮可用于打开完全相同的菜单。
解决跨设备的一致性问题:最终,对于用户体验而言,您的应用与同一设备上的所有其他应用的行为一致比它在所有设备上与自身的行为一致更为重要。
我曾经通过像这样定义我的菜单来解决它(在我的示例中也使用了 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 Developers Design System 阻止了这种方法,但我找到了通过它的方法:
将此添加到您的 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;
}
}
好吧,我认为亚历山大卢卡斯提供了(不幸的是)正确答案,所以我将其标记为“正确”答案。我在这里添加的替代答案只是将任何新读者指向this post in the Android Developers blog作为对该主题的相当完整的讨论,并提供一些关于在从 pre-level 11 过渡到新 Action 时如何处理代码的具体建议酒吧。
我仍然认为这是一个设计错误,没有让菜单按钮在启用菜单按钮的设备中充当冗余的“操作溢出”按钮,作为过渡用户体验的更好方式,但此时它在桥下。
我不确定这是否是您要查找的内容,但我在 ActionBar 的菜单中构建了一个子菜单,并将其图标设置为与溢出菜单的图标匹配。虽然它不会自动将项目发送给它,(IE 你必须选择总是可见的和总是溢出的)在我看来这种方法可能会对你有所帮助。
在预装 ICS 的 gmail 应用程序中,当您选择了多个项目时,菜单按钮会被禁用。溢出菜单在这里“强制”通过使用溢出按钮而不是物理菜单按钮来触发。有一个名为 ActionBarSherlock 的第 3 方库,可让您“强制”溢出菜单。但这仅适用于 API 级别 14 或更低(ICS 之前)
对不起,如果这个问题已经死了。
这是我为解决错误所做的。我去了布局并创建了两个包含工具栏的布局。一个是 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);
}
Field
选择这个java.lang.reflect.Field
;)