メニューボタンのあるデバイスでオーバーフローメニューを強制的に使用する方法


159

メニューボタンのあるデバイスでも、アクションバーに収まらないすべてのメニュー項目をオーバーフローメニュー(メニューボタンではなくアクションバーからアクセスするメニュー)に移動させたいのです。これは、ActionBarのレイアウトがバーに収まらないためにタッチ(画面)インタラクションからボタンベースのインタラクションにジャンプする必要がある別のメニューリストにそれらを投げ込むよりも、ユーザーにとってはるかに直感的です。

エミュレーターで、「ハードウェアバック/ホームキー」の値を「いいえ」に設定して、この効果を得ることができます。私は、メニューボタンがある実際のデバイスのコードでこれを行う方法を探しましたが、メニューボタンはうまくできません。誰か助けてもらえますか?

回答:


54

編集:物理的なメニューボタンの状況に答えるために変更されました。

これは実際には設計により防止されています。Android設計ガイド互換性セクションによると、

「...メニューのハードウェアキーからアクションオーバーフローを利用できます。結果のアクションポップアップ...が画面の下部に表示されます。」

スクリーンショットを見るとわかるように、物理的なメニューボタンを持つ電話のActionBarにはオーバーフローメニューがありません。これにより、本質的にまったく同じメニューを開くための2つのボタンが利用できるようになり、ユーザーのあいまいさが回避されます。

デバイス間の一貫性の問題に対処するには:最終的に、ユーザーエクスペリエンスにとって、アプリが同じデバイス上の他のすべてのアプリと一貫して動作することは、すべてのデバイスで一貫して動作することよりも重要です。


1
アレクサンダー-いいえ、私はすべてのshowAsAction値といくつかの組み合わせを試しましたが、どれも(少なくともエミュレータでは)トリックを行いません。アクションバーのオーバーフローメニューは、メニューボタンのないデバイスをエミュレートした場合にのみ表示されます。メニューボタンのあるデバイス、縦の省略記号とオーバーフロー項目が表示されることを確認したいと思います。質問を少しわかりやすくするために編集しました。
PaulP

41
この会話に足を踏み入れて話し合いましょう。私はそれが設計によって妨げられていることを知っています(私は設計ガイドラインを読みます)。しかし、それは%$ /%#+のようなものだと思います。たとえば、ユーザーはGalaxy Nexus(-> wオーバーフロー)からNexus One(w 4.0 /->オーバーフローなし)に切り替えています。ユーザーがメニュー項目をもう見つけられないに違いない。そのため、すべてのデバイスで同じ使用法を求めています。だから、私はパルプと同じ問題を抱えています。利用可能なクリーンな回避策はありませんか?
Sprigg

10
私も最初に設計ガイドを読みました。私にとって、これはサポートパッケージの設計の悪い選択でした。ユーザーをボタンから遠ざけるためのより良い戦略(目的、そうですか?)を冗長にして、機能を画面とボタンの両方に配置することです。現在のところ、ボタンにはすべてのメニュー選択肢がリストされておらず、アクションバーにないものだけがリストされているため、このデザインはアクションバーへのスムーズな移行をサポートしておらず、アクションバーを追加する前に行っていた操作も行いません(すべてのメニューを表示します)選択肢)。私はあなたが正しいと思い、簡単な回避策はないと思います。
PaulP

18
Googleは新しいGoogle +アプリでこれに反対しています。それはデバイスに関係なくオーバーフロー項目を持っています。
Karl

10
正直なところ、メニューのハードキーを試してみて、期待することができないユーザーが多すぎることを私は見てきました。どの電話のどのユーザーにもメニューオプションが存在することを示す画面上のインジケーターがあってはならないという設計の場合、その設計は十分な情報を得られていないものです。
Lance Nanek、2012年

323

ここでこの小さなハックを使用することもできます:

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です。

アプリに強制的にオーバーフローメニューを表示します。メニューボタンは引き続き機能しますが、右上隅にメニューが開きます。

[編集]何度か発生したため、このハックはAndroid 3.0で導入されたネイティブのActionBarでのみ機能し、ActionBarSherlockでは機能しません。後者は、独自の内部ロジックを使用して、オーバーフローメニューを表示するかどうかを決定します。ABSを使用する場合、4.0未満のすべてのプラットフォームはABSによって処理されるため、そのロジックに従います。ハッキングは、Android 4.0以降を搭載したすべてのデバイスで引き続き機能します(メニューボタン付きのタブレットは実際にはないため、Android 3.xは無視しても問題ありません)。

ABSでメニューを強制する特別なForceOverflow-Themeが存在しますが、複雑なため、将来のバージョンでは削除される予定です


4
ソースコードを調べました。文書化されていない機能の宝庫:)そのようなことのために実行可能なフォールバックがあることを確認してください。
Timo Ohr、2012

4
どうもありがとう!これは本当に素晴らしいです。レビュー、バグレポート、共有アクションをオーバーフローに入れたかったのですが、Nexus Sには表示されませんでした。ユーザーがメニューボタンをクリックすることすらありません。オーバーフローにより、ユーザーは追加のアクションを使用できることがわかります。
ユーリークリコフ2013

4
@Ewoksここのコメントにはかなり遅れましたが、私はこれをActionBarCompatの最新バージョンで試してみましたが、うまくいきました。
jacobhyphenated 2013

3
これは、Samsung Galaxy S3およびS4で機能しますが、LG G2では機能しません(オーバーフローメニューボタンを表示するためにチェックをハードコーディングしていると思われます)
dvd

18
綺麗な!Eclipseが6つの異なるインポートから選択できるようにしたField場合、この1つを選択してくださいjava.lang.reflect.Field;)
Eugene van der Merwe '27

35

私は次のようにメニューを定義することで回避策を使用しています(この例でも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で手動の「overflow-management」を必要とするかもしれないことを認めますが、私はこの解決策が有用であると思いました。

また、アクティビティでデバイスにHWボタンを使用してオーバーフローメニューを開くように強制することもできます。

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

:-)


2
HWボタンを使用してオーバーフローメニューを開く方法
bladefury 2014年

1
HWボタンでオーバーフローメニューを開くための私の最新の回答を参照してください。:)
Berťák

11

サポートライブラリ(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デバイスの両方で[OK]を動作します
leafcutter

7

この種類のメソッドは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
Android開発者

5

さて、アレクサンダールーカスは(残念ながら)正しい答えを提供してくれたと思うので、「正しい」ものとしてマークします。ここに追加する別の答えは、新しい読者にAndroid Developersブログのこの投稿を紹介するだけであり、トピックのかなり完全なディスカッションとして、レベル11以前からの移行時にコードを処理する方法に関するいくつかの具体的な提案を示します。新しいアクションバーに。

ユーザーエクスペリエンスをこの時点でブリッジの下に移行するためのより良い方法として、メニューボタンが有効なデバイスでメニューボタンが冗長な「アクションオーバーフロー」ボタンとして動作しないのは、設計ミスだと私はまだ信じています。


私は設計ミスについてあなたに完全に同意します-そして、これはイライラします!
ポールハニセット

1
最近のG +アプリでGoogle自体がそのルールに違反し始めたという事実がなかったのであれば、これに同意します。そして当然です。メニューボタンはレガシーではなく、SGS3のような新しいデバイスでも使用できます。残念ながら、ここにとどまっています。そして、それはユーザビリティを深刻に妨げます。
Timo Ohr 2012

4

これがあなたが探しているものかどうかはわかりませんが、ActionBarのメニュー内にサブメニューを作成し、そのアイコンをオーバーフローメニューのアイコンと一致するように設定しました。アイテムが自動的に送信されることはありませんが(つまり、常に表示されるものと常にオーバーフローするものを選択する必要があります)、このアプローチが役立つと思われます。


2

ICSがプリインストールされているGmailアプリでは、複数のアイテムを選択するとメニューボタンが無効になります。オーバーフローメニューは、物理的なメニューボタンの代わりにオーバーフローボタンを使用することによってトリガーされるように「強制」されています。オーバーフローメニューを「強制」できるActionBarSherlockと呼ばれるサードパーティのlibがあります。ただし、これはAPIレベル14以下(ICS以前)でのみ機能します。


2

ツールバーを使用すると、すべてのバージョンとすべてのデバイスでオーバーフローを表示できます。一部の2.xデバイスで試しましたが、動作します。


1

この問題が死んでいる場合は申し訳ありません。

これがエラーを解決するために私がしたことです。レイアウトに行き、ツールバーを含む2つのレイアウトを作成しました。1つはsdkバージョン8のレイアウトで、もう1つはsdkバージョン21のレイアウトです。バージョン8では、sdk 21レイアウトでandroid.widget.Toolbarを使用しながら、android.support.v7.widget.Toolbarを使用しました。

次に、アクティビティでツールバーを膨らませます。SDKをチェックして、21以上かどうかを確認します。次に、対応するレイアウトを膨らませます。これにより、ハードウェアボタンが実際に設計したツールバーにマップされます。


0

新しいを使用している人のために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);
}
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.