【问题标题】:How to force use of overflow menu on devices with menu button如何在带有菜单按钮的设备上强制使用溢出菜单
【发布时间】:2012-03-06 09:46:40
【问题描述】:

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

在模拟器上,我可以将“Hardware Back/Home Keys”值设置为“no”并获得此效果。 我已经在代码中搜索了一种方法来为具有菜单按钮但不能很好的实际设备执行此操作。谁能帮帮我?

【问题讨论】:

    标签: android android-actionbar


    【解决方案1】:

    你也可以在这里使用这个小技巧:

    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。

    它将强制应用显示溢出菜单。菜单按钮仍然有效,但会在右上角打开菜单。

    [编辑] 因为它已经出现了好几次了:这个 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

    【讨论】:

    • 我查看了源代码。未记录功能的宝库 :) 只需确保您对此类事情有一个可行的备用方案。
    • 非常感谢!这真的很棒。我想将审查、错误报告和共享操作放入溢出中,但它没有显示在 Nexus S 上。用户甚至不会点击菜单按钮。通过溢出,用户可以看到额外的操作可用。
    • @Ewoks 我在这里发表评论已经很晚了,但我刚刚使用最新版本的 ActionBarCompat 进行了尝试,它确实有效。
    • 这适用于三星 Galaxy S3 和 S4,但不适用于 LG G2(怀疑他们正在硬编码检查以显示溢出菜单按钮)
    • 漂亮!如果 Eclipse 为 Field 提供了 6 种不同的导入供您选择,请选择这个 java.lang.reflect.Field ;)
    【解决方案2】:

    编辑:针对物理菜单按钮的情况进行了修改。

    这实际上是通过设计防止的。根据Compatibility Section of the Android Design Guide

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

    您会在屏幕截图中注意到,带有物理菜单按钮的手机在操作栏中没有溢出菜单。这避免了用户的歧义,基本上有两个按钮可用于打开完全相同的菜单。

    要解决跨设备的一致性问题:归根结底,对于用户体验而言,您的应用与同一设备上的所有其他应用的行为一致比它在所有设备上与自身的行为一致更为重要。

    【讨论】:

    • Alexander - 不,我已经尝试了所有的 showAsAction 值和几种组合,但没有一个能奏效(至少在模拟器上)。只有当我模拟一个没有菜单按钮的设备时,操作栏上的溢出菜单才会显示。我想看到那个垂直省略号,并且有溢出的项目显示在设备上带有一个菜单按钮。我已经编辑了我的问题以使其更清晰。
    • 让我们进入这个对话并讨论:我知道它是被设计阻止的(我阅读了设计指南)。但那是 %$/%#+,我想。例如:用户正在从 Galaxy Nexus (-> w Overflow) 切换到 Nexus One (w 4.0/ -> no Overflow)。我打赌用户再也找不到菜单项了。出于这个原因,我希望所有设备都使用相同的用法。所以,我最终遇到了和保罗一样的问题。没有任何干净的解决方法可用吗?
    • 我也先阅读了设计指南。对我来说,这是支持包中设计的错误选择。让用户远离按钮(目标,对吗?)的更好策略是使其冗余,将功能放在屏幕和按钮中。按照现在的情况,按钮并没有列出所有菜单选项,只列出那些不在操作栏上的选项,因此这种设计既不支持平滑过渡到操作栏,也不像以前添加操作栏之前所做的那样(显示 所有菜单选项)。我怀疑您是对的,并且没有简单的解决方法。
    • Google 在他们的新 Google+ 应用程序中反对这一点。无论设备如何,它都有溢出项目。但据我所知,他们仍然阻止开发人员做同样的事情并建议反对它。
    • 老实说,我见过太多的用户没有尝试菜单硬键,没想到他们会这样做。如果设计说任何手机上的任何用户都不应该在屏幕上显示菜单选项存在的指示符,那么这种设计是不明智的。
    【解决方案3】:

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

    :-)

    【讨论】:

    • 如何使用HW按钮打开溢出菜单?
    • 查看我的更新答案以使用硬件按钮打开溢出菜单。 :)
    【解决方案4】:

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

    【讨论】:

    • 在使用支持库时,我也实现了这一点,它在 3.0 之前和之后的设备上都可以正常工作
    【解决方案5】:

    这种方法被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;
        }
    }
    

    【讨论】:

    【解决方案6】:

    好吧,我认为亚历山大卢卡斯提供了(不幸的是)正确答案,所以我将其标记为“正确”答案。我在此处添加的替代答案只是将任何新读者指向this post in the Android Developers blog 作为对该主题的相当完整的讨论,并提供一些关于在从 pre-level 11 过渡到新 Action 时如何处理代码的具体建议酒吧。

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

    【讨论】:

    • 我完全同意你关于设计错误的看法——我觉得这很令人沮丧!
    • 如果不是因为 Google 本身在其最近的 G+ 应用程序中开始违反该规则,我会同意你的看法。理所当然地。菜单按钮不是传统的,即使是像 SGS3 这样的新设备也有它。不幸的是,它留在这里。它严重影响了可用性。
    【解决方案7】:

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

    【讨论】:

      【解决方案8】:

      在预装 ICS 的 gmail 应用中,当您选择了多个项目时,菜单按钮会被禁用。溢出菜单在这里“强制”通过使用溢出按钮而不是物理菜单按钮来触发。有一个名为 ActionBarSherlock 的第 3 方库,可让您“强制”溢出菜单。但这仅适用于 API 级别 14 或更低(ICS 之前)

      【讨论】:

        【解决方案9】:

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

        【讨论】:

          【解决方案10】:

          对不起,如果这个问题已经死了。

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

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

          【讨论】:

            【解决方案11】:

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

            【讨论】:

              猜你喜欢
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 2012-02-04
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              相关资源
              最近更新 更多