Как принудительно использовать меню переполнения на устройствах с помощью кнопки меню

Я бы хотел, чтобы все элементы меню, которые не вписываются в ActionBar, переходят в меню переполнения (тот, который достигается из панели действий, а не кнопки меню) даже на устройствах, которые делают есть кнопка меню. Это кажется гораздо более понятным для пользователей, чем бросание их в отдельный список меню, который требует от пользователя перехода от сенсорного (экранного) взаимодействия к взаимодействию на основе кнопок просто потому, что макет ActionBar не может поместиться на панели.

В эмуляторе я могу установить значение "Оборудование назад/Домашние ключи" на "нет" и получить этот эффект. Я искал способ сделать это в коде для фактического устройства, которое имеет кнопку меню, но не может его отличить. Кто-нибудь может мне помочь?

Ответ 1

EDIT: изменено для ответа на ситуацию с физической кнопкой меню.

Это фактически предотвращается дизайном. Согласно разделу совместимости Руководства по дизайну Android,

"... переполнение действия доступно с помощью аппаратного ключа меню. Результатные всплывающие окна отображаются в нижней части экрана.

На снимках экрана вы заметите, что телефоны с физической кнопкой меню не имеют меню переполнения в ActionBar. Это позволяет избежать двусмысленности для пользователя, по существу имеющего две кнопки для открытия того же самого меню.

Чтобы решить проблему согласованности между устройствами: в конечном счете, более важно, чтобы ваше приложение работало последовательно с каждым другим приложением на том же самом устройстве, а не тем, что оно ведет себя с собой на всех устройствах.

Ответ 2

Вы также можете использовать этот маленький хак здесь:

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 вашего класса Application.

Это заставит приложение отображать меню переполнения. Кнопка меню по-прежнему будет работать, но она откроет меню в верхнем правом углу.

[Edit] Так как он появился несколько раз: этот хак работает только для родного ActionBar, представленного в Android 3.0, а не ActionBarSherlock. Последний использует свою собственную внутреннюю логику, чтобы решить, показывать ли это меню переполнения. Если вы используете ABS, все платформы < 4.0 обрабатываются АБС и, таким образом, подвергаются его логике. Хак по-прежнему будет работать на всех устройствах с Android 4.0 или выше (вы можете спокойно игнорировать Android 3.x, поскольку на нем нет никаких таблеток с кнопкой меню).

Существует специальная ForceOverflow-тема, которая заставит меню в АБС, но, возможно, будет удалено в будущих версиях из-за осложнений.

Ответ 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, но я нашел это решение полезным.

Вы также можете заставить устройство использовать кнопку 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);
}

: -)

Ответ 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>

Ответ 5

Этот метод запрещен системой разработки Android Developers, но я нашел способ передать ее:

Добавьте это в свой файл меню 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

Ну, я думаю, что Александр Лукас предоставил (к сожалению) правильный ответ, поэтому я отмечаю его как "правильный". Альтернативный ответ, который я добавляю здесь, - это просто указать всех новых читателей на этот пост в блоге Android Developers как довольно полное обсуждение темы с некоторыми конкретными предложениями, как как обращаться с вашим кодом при переходе с предварительного уровня 11 на новую панель действий.

Я по-прежнему считаю, что ошибкой дизайна не было, если кнопка меню ведет себя как избыточная кнопка "Переполнение действия" на устройствах с включенной кнопкой меню, что является лучшим способом перехода на пользовательский интерфейс, но его вода под мостом на данный момент.

Ответ 7

Я не уверен, что это то, что вы ищете, но я создал подменю в меню ActionBar и установил его значок в соответствии с иконкой меню переполнения. Хотя он не будет автоматически отправляться на него, (IE вы должны выбрать то, что всегда видно и что всегда переполнено), мне кажется, что этот подход может вам помочь.

Ответ 8

В приложении gmail, которое поставляется с установленной программой ICS, кнопка меню отключена, когда у вас есть несколько элементов. Меню переполнения здесь "принудительно" запускается с помощью кнопки переполнения вместо кнопки физического меню. Theres - сторонняя библиотека под названием ActionBarSherlock, которая позволяет "принудительно" переполнять меню. Но это будет работать только на уровне API 14 или ниже (pre-ICS)

Ответ 9

Если вы используете Toolbar, вы можете показать переполнение всех версий и всех устройств, я пробовал на некоторых 2.x устройств, он работает.

Ответ 10

Извините, если эта проблема не работает.

Вот что я сделал для устранения ошибки. Я пошел в макеты и создал два, содержащих панели инструментов. Один из них был макет для SDK версии 8, а другой для sdk версии 21. В версии 8 я использовал android.support.v7.widget.Toolbar, в то время как я использовал android.widget.Toolbar на макете sdk 21.

Затем я раздуваю панель инструментов в своей деятельности. Я проверяю 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);
}