即使有足够的空间,showAsAction="ifRoom"也不显示项。

50

我正在尝试在我的应用程序上正确地使用ActionBar(我正在使用ActionBarSherlock以在Android 2.x和4.x之间实现统一的UI)。我感觉android:showAsAction="ifRoom"是一个大谎言。每当我将操作设置为ifRoom时,它总是出现在溢出菜单中,即使有足够的空间。这里有两个来自同一模拟器的截图。第一个显示了所有选项都设置为always的ActionBar,第二个显示了最后两个选项设置为ifRoom的ActionBar。正如您所看到的,当它们都在always截图中显示时,有足够的空间,那么为什么它们不在第二个截图中显示,因为它们确实有空间?

enter image description here

enter image description here

这是我的menu.xml:

<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android" >

    <item
        android:id="@+id/add"
        android:icon="@drawable/ic_menu_btn_add"
        android:showAsAction="always"
        android:title="Add"/>
    <item
        android:id="@+id/calculateNPV"
        android:icon="@drawable/menu_icon_npv"
        android:showAsAction="always"
        android:title="NPV"/>
    <item
        android:id="@+id/calculateIRR"
        android:icon="@drawable/menu_icon_irr"
        android:showAsAction="always"
        android:title="IRR/YR"/>
    <item
        android:id="@+id/send"
        android:icon="@android:drawable/ic_menu_share"
        android:showAsAction="always"
        android:title="@string/share_pdf"/>
    <item
        android:id="@+id/graph"
        android:icon="@drawable/ic_menu_gallery"
        android:showAsAction="ifRoom"
        android:title="@string/view_cashflow_diagram"/>
    <item
        android:id="@+id/deleteReorder"
        android:icon="@drawable/ic_menu_clear_playlist"
        android:showAsAction="ifRoom"
        android:title="@string/delete_reorder_cashflows"/>

</menu>
10个回答

43

这并不是一个大谎言,而是一个小疏忽。

showAsAction 属性必须使用不同的命名空间 "http://schemas.android.com/apk/res-auto" 来定义。

因此,在您的顶部菜单标记中应定义一个命名空间,如下所示: xmlns:app="http://schemas.android.com/apk/res-auto"

然后使用它来定义您的 showAsAction 属性,例如: app:showAsAction="ifRoom"

这样应该就可以解决了。


12
我遇到了完全相同的问题 - 实际上在我的情况下 - 我不得不做完全相反的事情:使用android:showAsAction命名空间来修复此问题。 - KurtCobain
5
如果您正在使用 ActionBarActivity,则需要使用命名空间。如果使用 Activity,则可以使用 android:showAsAction。 - nickromano
1
我尝试过了,对我没用。Android文档甚至都不支持它。 - The Original Android
1
@KurtCobain 使用 android 命名空间解决了我的问题! - Derek 朕會功夫
1
如果您正在使用appcompat库,则需要使用app。否则,您应该使用android - Soren Stoutner
只是想补充一下,如果你在Android Studio中写showAsAction时没有加上app:前缀,那么它很可能会被添加到父标签中,就像josagyemang提到的那样。 - newbie

15
这是因为ActionBar中指定了最多可以放置的项目数量,似乎是4个。当然,您可以通过设置showAsAction: always来强制它们显示,但根据谷歌API指南:
如果您认为超过四个菜单项可以作为操作项进行验证,则应仔细考虑它们的相对重要性,并尝试将不超过四个菜单项设置为操作项(并使用“ifRoom”值在屏幕较小时允许系统将一些菜单项放回溢出菜单中)。即使在宽屏上有空间,您也不应创建一个长长的操作项流,以此来保持UI整洁,看起来像桌面工具栏,因此请尽量将操作项的数量保持在最少。
此外,以下操作永远不应出现为操作项:设置、帮助、反馈或类似操作,请始终将它们放在溢出菜单中。

17
不总是数字4。请看这张表格:http://developer.android.com/design/media/action_bar_pattern_table.png - Jake Wharton
4
但正如你所看到的,确实有空间进行这些操作,因此 -ifRoom- 是一个大大的谎言。 :) 令人沮丧的是,没有明显的指示表明通过菜单按钮还有更多选项可用。显示一些选项但没有指示符而不是全部选项更糟糕,因为显示一些选项会告诉用户这是需要查找的位置。那么为什么还需要另一个位置呢? - Kenny Wyland
1
@Jake Wharton:没错!我知道我以前见过这样的东西,但我想不起来在哪里看到过。现在我想是在 Google 设计行动视频中的 ActionBar 中...谢谢! - Michał Z.
1
@Kenny Wyland: 看看这个 http://www.youtube.com/watch?v=jes1iXRFRw0 它应该能解释一些问题。ActionBar 上的东西不仅限于“按钮”。我同意关于物理菜单按钮的问题,以及没有指示符表明还有更多项的问题。 - Michał Z.
1
Jake Wharton:为了提供上下文和我回答中引用的规则,我提供了与设计指南相关页面的链接:http://developer.android.com/design/patterns/actionbar.html - arne.jans
图表 http://developer.android.com/design/media/action_bar_pattern_table.png 显示,showAsAction:ifRoom 图标的最大数量为4个,右侧的选项溢出图标占据第五个位置。https://developer.android.com/design/patterns/actionbar.html 或许随着 Google Play 商店引入 Chrome OS,他们会更新 Android 以允许更多的图标,但我并不抱有太大期望。 - Soren Stoutner

11
为了补充Michal Z.的回答: Android设计指南页面模式-ActionBar在“操作按钮”章节中说到:

http://developer.android.com/design/patterns/actionbar.html

主操作栏可以容纳多少个操作? 操作栏的容量由以下规则控制:

  • 主操作栏中的操作按钮不能占据超过50%的宽度
  • 底部操作栏上的操作按钮可以使用整个宽度。
  • 以密度无关像素(dp)表示的屏幕宽度确定可以容纳多少项在主操作栏中:
    • 小于360 dp = 2个图标
    • 360-499 dp = 3个图标
    • 500-599 dp = 4个图标
    • 大于等于600 dp = 5个图标

6
请使用app:showAsAction="always"替代android:showAsAction="always"

1

使用

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

6
请解释您的回答,因为只有代码的答案通常不清楚且更难理解。 - SuperBiasedMan

1

ActivityBar strives not to exceed some amount of visible elements. And that limit is lower than ActivityBar can contain indeed. The limit is set in android.support.v7.view.ActionBarPolicy class:

`/**
     * Returns the maximum number of action buttons that should be permitted within an action
     * bar/action mode. This will be used to determine how many showAsAction="ifRoom" items can fit.
     * "always" items can override this.
     */
    public int getMaxActionButtons() {
        final Resources res = mContext.getResources();
        final int widthDp = ConfigurationHelper.getScreenWidthDp(res);
        final int heightDp = ConfigurationHelper.getScreenHeightDp(res);
        final int smallest = ConfigurationHelper.getSmallestScreenWidthDp(res);

如你所见,限制范围在2到5之间,并取决于屏幕宽度。
我还没有找到改变这种行为的方法。因此,如果您想超过限制,您应该使用showAsAction="always"或为ActionBar创建自己的视图。

0

使用以下代码,它将始终有效

<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=".MainActivity">
    <item 
        android:id="@+id/menu_share" 
        android:title="Share"
        android:orderInCategory="100" 
        app:showAsAction="ifRoom"
        android:actionProviderClass="android.widget.ShareActionProvider"/>
</menu>

使用app:actionProviderClass="android.support.v7.widget.ShareActionProvider"/>而非android:actionProviderClass="android.widget.ShareActionProvider"/>。 - Quimbo

0

Android 最多会显示 5 个按钮,包括菜单,但如果您想要覆盖这种行为,可以这样做。

请记住,Material 设计指南是在工具栏上有限数量的按钮。并且请记住,即使有空间,某些操作也不应该显示为按钮。

但是,如果您有一些特定的操作是有意义的,即使总共超过 5 个,您也可以显示它们。您只需要自己检查屏幕宽度。

首先,在菜单定义中,对于您希望始终显示的最多 4 个按钮,请使用 "always"。对于所有其他按钮,请使用 "never",包括您可能以编程方式显示为图标的按钮。

然后,覆盖 onPrepareOptionsMenu 来添加逻辑,以强制显示更多操作作为按钮。

@Override
public boolean onPrepareOptionsMenu(Menu menu) {
    final Configuration config = getResources().getConfiguration();
    final int width = config.screenWidthDp;

    if (width > 400) {
        MenuItem item = menu.findItem(R.id.your_action);
        item.setShowAsAction(SHOW_AS_ACTION_ALWAYS);

        item = menu.findItem(R.id.another_action);
        item.setShowAsAction(SHOW_AS_ACTION_ALWAYS);
    }

    return super.onPrepareOptionsMenu(menu);
}

您还可以在方向更改时动态地执行此操作,因为通常在横向模式下有足够的空间,特别是在平板电脑上。

    @Override
    public void onConfigurationChanged(@NonNull Configuration newConfig) {
        super.onConfigurationChanged(newConfig);

        invalidateOptionsMenu();
    }

但不要在工具栏上杂乱无章。记得在小设备上测试。


0
只是想补充一下,如果你在Android Studio中写(showAsAction)时没有加上app:前缀,那么它很可能会被添加到父标签中,就像josagyemang所提到的那样。
这真的不是一个大谎言,而是一个小疏忽。
showAsAction属性必须使用不同的命名空间"http://schemas.android.com/apk/res-auto"来定义。
因此,在你的顶部菜单标签中,你应该定义一个命名空间,如xmlns:app="http://schemas.android.com/apk/res-auto"。
然后,使用该命名空间来定义你的showAsAction属性,例如app:showAsAction="ifRoom"。
这样应该就可以解决问题了。

0

这与AppCompatActivity或appcompat库无关。

只需使用

menuInflater.inflate(R.menu.main_menu, menu)

替代

MenuInflater(this).inflate(R.menu.main_menu, menu)

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