菜单项未显示在操作栏上

53

我制作了一个全新的项目。我已经向menu布局文件添加了项目,但这些项目没有显示在操作栏的右侧。我记得会出现三个点的图标,点击后会打开菜单。

enter image description here

这是我的Activity

public class MainActivity extends Activity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        ActionBar actionBar = getActionBar();
        actionBar.setBackgroundDrawable(new ColorDrawable(Color.BLUE));     
        actionBar.show();
    }

    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        // Inflate the menu; this adds items to the action bar if it is present.
        getMenuInflater().inflate(R.menu.main, menu);
        return true;
    }

}

这是我的main.xml文件:

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

    <item
        android:id="@+id/action_settings"
        android:orderInCategory="100"
        android:showAsAction="never"
        android:title="@string/action_option1"/>
    <item
        android:id="@+id/action_settings34"
        android:orderInCategory="100"
        android:showAsAction="never"
        android:title="@string/action_option2"/>
    <item
        android:id="@+id/action_settings3"
        android:orderInCategory="100"
        android:showAsAction="never"
        android:title="@string/action_option3"/>


</menu>

这是在哪个设备上发生的?另外,你能给我们展示一些代码吗?这很相关。 - gunar
你可以在这里发布你的代码吗? - Sanket Shah
抱歉,我忘记了代码。@David - prometheuspk
设备是HTC One V。我正在运行CyanogenMod 10。我已经更新了文本@gunar。 - prometheuspk
1
http://stackoverflow.com/questions/16196368/android-want-to-show-3-dots-menu-on-ics - Raghunandan
你的安卓操作系统版本是多少? - Sanket Shah
13个回答

118

背景

在菜单配置中,关于showAsAction属性似乎存在一些误解。我在许多stackoverflow答案中找到的信息似乎总是不完整的。所以这里尝试着改变这种情况。

三个点 | 溢出 | 选项菜单

没有办法在代码中控制你的操作栏是否会显示三个点溢出菜单。

好吧,你可以通过确保没有选项菜单来强制它不显示。但公平地说,你可以绕过这个问题,在 How to force use of overflow menu on devices with menu button 更多的信息。

点的显示与否取决于测试设备。带有菜单按钮的设备不会在操作栏上显示三个点图标,因为用户可以使用设备上的菜单按钮。

设备上的选项菜单按钮

没有这个选项菜单按钮的设备(例如从Galaxy开始的Nexus设备)没有触发该选项菜单的其他方法。在这些设备上运行同一个应用程序将在操作栏中显示三个点溢出菜单选项。

操作栏显示选项菜单

您可以控制什么

在菜单xml文件中,有showAsAction选项,您可以使用它来控制单个菜单选项在操作栏中的显示方式

根据官方菜单资源文档,选项包括:

android:showAsAction=["ifRoom" | "never" | "withText" | "always" | "collapseActionView"]

ifRoom标志仅在有足够空间时显示选项。这应该是大多数情况下的首选项。不过,这将使操作栏中的标题压缩(请参见垂直方向的屏幕截图)。

never标志将始终将此选项放在溢出菜单中,而不是直接放在操作栏中。

不建议使用always标志,因为它会强制该选项始终显示在操作栏中,即使运行在非常小的屏幕尺寸上也是如此。这可能会完全使标题不可见。

正如您现在所知道的,选项菜单可以具有android:titleandroid:icon属性。您可以将withText标志与alwaysifRoom一起使用(两者之间用管道符|隔开),以在渲染到操作栏时强制显示项目的文本。

collapseActionView仅受API level 14支持,因此让我忽略它。

以下代码片段在竖屏模式下的设备上的操作截图:

collapsed title and mostly icons on vertical orientation

以及在横屏模式下由于操作栏有更多空间而呈现的另一个屏幕截图:

landscape mode actionbar rendered

Android文档

有关此操作栏的最佳开发文档请参见操作栏指南。如果您正在寻找更多设计准则,请访问此链接菜单资源链接列在前面。对于一般菜单,请查看此处

代码片段

只提供参考代码,因为大多数答案中这部分似乎是正确的。可以在https://github.com/AndroidExamples/fragment-navigation找到更完整的示例。

/res/menu/main.xml文件内容:

<menu xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
tools:context="be.hcpl.android.example.MainActivity" >

<!-- an option that never appears as a fixed text/icon in the actionbar -->
<item android:id="@+id/action_one"
    android:title="@string/action_one"
    android:orderInCategory="100"
    app:showAsAction="never" />

<!-- another option that only appears if there is enough room -->
<item android:id="@+id/action_two"
    android:title="@string/action_two"
    android:orderInCategory="200"
    app:showAsAction="ifRoom" />

<!-- a last option that always appears -->
<item android:id="@+id/action_three"
    android:title="@string/action_three"
    android:orderInCategory="300"
    app:showAsAction="always" />

<!-- an option to show with both icon and text -->
<item android:id="@+id/action_four"
    android:icon="@android:drawable/ic_menu_directions"
    android:title="@string/action_four"
    android:orderInCategory="400"
    app:showAsAction="withText|always" />

<!-- an option to always show as an icon only -->
<item android:id="@+id/action_five"
    android:icon="@android:drawable/ic_menu_info_details"
    android:title="@string/action_five"
    android:orderInCategory="500"
    app:showAsAction="always" />

</menu>

一些相关的回答


太棒了,我在一个测试设备上摸索时忘了看菜单按钮。 - Selvam
哇,我从没想到过这个。感谢你的回答! - Bram
非常感谢。我以为我的共享项目没有出现,已经试图找出原因好几天了。你的帖子告诉我它只是在溢出中!!! - Index Hacker
你太棒了!!在我找到这个答案之前,我一直在Galaxy Note GT上遇到这个问题。我尝试了添加工具栏、编辑showAsAction、卸载等所有方法,最终找到了这个答案。非常感谢你!! - sophin
事实上,有一种方法可以强制三个点菜单选项显示在操作栏的右侧,尽管我不确定这样做是否合法。请参考此SO答案以获取详细信息:https://dev59.com/qGIj5IYBdhLWcg3w8JRZ#27502405。仅出于不想丢失代码的考虑,我在这里发布关键行 ViewConfiguration config = ViewConfiguration.get(this); Field menuKeyField = ViewConfiguration.class.getDeclaredField("sHasPermanentMenuKey"); if (menuKeyField != null) { menuKeyField.setAccessible(true); menuKeyField.setBoolean(config, false); }已在Android Jelly Beans 4.2.2上测试。 - e2l3n

44

如果您将showAsAction属性设置为never,则这些菜单项将永远不会显示为操作视图。请尝试以下操作:

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

    <item
        android:id="@+id/action_settings"
        android:orderInCategory="100"
        android:showAsAction="ifRoom|withText"
        android:title="@string/action_option1"/>
    <item
        android:id="@+id/action_settings34"
        android:orderInCategory="100"
        android:showAsAction="ifRoom|withText"
        android:title="@string/action_option2"/>
    <item
        android:id="@+id/action_settings3"
        android:orderInCategory="100"
        android:showAsAction="ifRoom|withText"
        android:title="@string/action_option3"/>

</menu>

1
太棒了!谢谢 :) 我没想到它是那么简单明了的。 - Shobhit Puri
谷歌对此有哪些设计建议?应该使用 ifRoom 还是 never - prometheuspk
2
我所见过关于此问题最好的文章是来自开发者的那篇。篇幅相当长,所以你可以拿一瓶啤酒来仔细研究,因为它对你的应用程序导航非常关键:http://developer.android.com/guide/topics/ui/actionbar.html - gunar
为什么我的菜单从底部打开? - Shaktisinh Jadeja

13

我有同样的问题。我尝试了上面说的所有方法。我的问题是我忘记重写onCreateOptionsMenu(Menu menu)。

@Override
public boolean onCreateOptionsMenu(Menu menu) {
    getMenuInflater().inflate(R.menu.menu,menu);
    return super.onCreateOptionsMenu(menu);
}

9
我觉得你希望总是在右上角显示溢出菜单图标,并且希望从那里打开菜单。尝试以下操作以强制将其放置在那里:
在你的 onCreate() 中执行以下操作:
  try {
        ViewConfiguration config = ViewConfiguration.get(this);
        Field menuKeyField = ViewConfiguration.class.getDeclaredField("sHasPermanentMenuKey");
        if(menuKeyField != null) {
            menuKeyField.setAccessible(true);
            menuKeyField.setBoolean(config, false);
        }
    } catch (Exception ex) {
        // Ignore
    }

这将强制App显示溢出菜单。菜单按钮仍然有效,但它会在右上角打开菜单。引用自答案,摘自如何强制在具有菜单按钮的设备上使用溢出菜单。这可能是一种“黑客”方法,但它起作用。 编辑: 基于@gunar有用的评论,我要求不要使用此方法。以下是原因:
  • 私有字段sHasPermanentMenuKey可以在未来的版本中进行重构。然后你的应用就会停止工作。

  • 如果您强制移动操作项到操作栏,因为您习惯于使用它们,您最终会使用户混淆,他们已经习惯了设备上的应用程序运行方式。那些硬件menu键的设备将习惯于从菜单硬件键中显示选项。如果你故意向他们展示溢出菜单的三个点,可能会让他们感到困惑。

所以让所有的应用程序在这方面保持统一。那些没有硬件键的设备将自动显示它们。

1
我以前见过这种东西,它是一个可怕的黑客程序。 - gunar
你说得很对。实际上,我也寻找了很长时间的替代方案,但最终不得不使用这个。到目前为止,我没有遇到任何问题,但如果你们能提供另一种方法,那肯定会有所帮助。我会非常感激。谢谢。 - Shobhit Puri
1
有没有人保证私有字段sHasPermanentMenuKey在将来的版本中不会被重构?如果是这样,上面的代码将停止工作...此外,如果某个设备不应该有一个操作溢出按钮,因为它有一个“选项”硬件按钮,那么就很自然地有一个功能,顶部右侧的空间可以用于其他事情。 - gunar
2
你的用户更习惯于使用你的设备,而不是你的应用程序。如果你强制将动作项移动到操作栏中“因为你喜欢这样做”,你最终会使那些习惯于设备运行方式(即他们习惯从菜单硬件键显示选项)的用户感到困惑。 :) 这有意义吗? - gunar
@gunar 哦哦哦。是的,现在有意义了。我学到了一个教训,开发人员不应该根据自己的舒适程度假设所有事情。必须遵循规则。谢谢 Gunar! - Shobhit Puri
显示剩余2条评论

7

或者你可以创建像这样的结构:

<?xml version="1.0" encoding="utf-8"?>
<menu >
<item
    android:id="@+id/menu_main"
    android:icon="@drawable/icon_menu"
    android:showAsAction="always"
    android:title="@string/menu_A"
    android:visible="true">
    <menu>
        <item
            android:id="@+id/menu_settings1"
            android:showAsAction="never"
            android:title="@string/menu_A1"/>
        <item
            android:id="@+id/menu_settings2"
            android:showAsAction="never"
            android:title="@string/menu_A2"/>
        <item
            android:id="@+id/menu_settings3"
            android:showAsAction="never"
            android:title="@string/menu_A3"/>
    </menu>
</item>
</menu>

在“图标菜单”中,您可以使用三点图标剪贴画创建新的图标集。

6

添加

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

在onCreate方法中。


2
在搜索和阅读了很多答案后,我发现还有另一件小事需要注意。至少这是我的问题,我没有找到任何上述答案的解决方法。在你的.XML文件中,你的android:showAsAction应该不是来自android包,而应该来自app包,就像下面的例子一样:
app:showAsAction=

不要忘记导入app包。


兄弟说得对,我的代码没有生效是因为它使用了 android:showAsAction 而不是 app:showAsAction。 - Juan Manuel

1

只需在oncreate中写入setHasOptionsMenu(true)即可。


1

我必须在onViewCreatedonCreate中设置setHasOptionsMenu(true)


0
我的解决方案是在menu.xml文件中修改一个属性。
<menu xmlns:android="http://schemas.android.com/apk/res/android">
  <item android:id="@+id/gamingactivity_filter" android:showAsAction="ifRoom"   android:icon="@drawable/ic_filter"/> 

这在 Material 主题下有效,但在 AppCompat 主题和 Activity 中无效,所以我更改了我的 menu.xml,并在命名空间 "http://schemas.android.com/apk/res-auto" 下添加了 app:showAsAction= 属性。

<menu xmlns:android="http://schemas.android.com/apk/res/android"
      xmlns:app="http://schemas.android.com/apk/res-auto">
  <item android:id="@+id/gamingactivity_filter" android:showAsAction="ifRoom"  app:showAsAction="ifRoom" android:icon="@drawable/ic_filter"/>

从活动膨胀菜单到 OnCreateOptionsMenu(IMenu menu),现在我也可以从 OnOptionsItemSelected() 获取所选项目的 ID。

 public override bool OnOptionsItemSelected(IMenuItem item)
        {
                switch (item.ItemId)
                {
                    case Resource.Id.gamingactivity_filter:
                        OnBackPressed();
                        break;
                }
            }
            return true;
        }

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接