ChatGPT解决这个技术问题 Extra ChatGPT

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

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

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


J
Jared Rummler

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

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


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

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

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

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

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

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


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

我曾经通过像这样定义我的菜单来解决它(在我的示例中也使用了 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 按钮打开溢出菜单。 :)
a
a fair player

如果您使用支持库 (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 之前和之后的设备上都可以正常工作
E
Eli Revah

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

使用这种方法和只使用子菜单有什么区别,如下所示:stackoverflow.com/a/14634780/878126
P
PaulP

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

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


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

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


b
borislemke

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


T
TeeTracker

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


D
Dolandlod

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

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

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


M
Maksim Ivanov

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

关注公众号,不定期副业成功案例分享
关注公众号

不定期副业成功案例分享

领先一步获取最新的外包任务吗?

立即订阅