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


159

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

На эмуляторе я могу установить значение «Аппаратные ключи назад / Домашние ключи» на «нет» и получить этот эффект. Я искал способ сделать это в коде для фактического устройства, которое имеет кнопку меню, но не может точно. Может кто-нибудь помочь мне?

Ответы:


54

РЕДАКТИРОВАТЬ: модифицировано, чтобы отвечать за положение кнопки физического меню.

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

«... переполнение действий доступно с помощью аппаратной клавиши меню. Полученное всплывающее окно действий… отображается внизу экрана».

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

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


1
Александр - Нет, я пробовал все значения showAsAction и несколько комбинаций, и ни одна из них не сработала (по крайней мере, на эмуляторе). Меню переполнения на панели действий отображается только в том случае, если я эмулирую устройство без кнопки меню. Я хочу видеть, что вертикальный многоточие и переполненные элементы отображаются там на устройствах с кнопкой меню. Я отредактировал свой вопрос, чтобы сделать это немного яснее.
PaulP

41
Давайте войдем в этот разговор и обсудим: я знаю, что это предотвращено дизайном (я прочитал рекомендации по дизайну). Но это вроде% $ /% # +, я думаю. Например: пользователь переключается с Galaxy Nexus (-> w Overflow) на Nexus One (w 4.0 / -> no Overflow). Могу поспорить, что пользователь больше не найдет пункты меню. По этой причине я хочу одинаковое использование для всех устройств. Итак, я столкнулся с той же проблемой, что и paulp. Нет ли доступного чистого решения?
Спригг

10
Я тоже сначала прочитал Руководство по дизайну. Для меня это был неудачный выбор дизайна в пакете поддержки. Лучшей стратегией для перехода пользователей в сторону от кнопки (цель, верно?) Было бы сделать ее избыточной, отобразить функциональность как на экране, так и в кнопке. Как и сейчас, кнопка не перечисляет все пункты меню, только те, которые не находятся на панели действий, поэтому этот дизайн не поддерживает плавный переход к панели действий и не выполняет то, что делал до добавления панели действий (отображать все меню выбор). Я подозреваю, что вы правы, и что нет простого обходного пути.
PaulP

18
Google идет против этого в своих новых приложениях Google +. У него есть пункт переполнения независимо от устройства ... но они все еще мешают разработчикам делать то же самое и советовать против этого, насколько мне известно.
Карл

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

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

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

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

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


4
Я просмотрел исходный код. Сокровищница недокументированных функций :) Просто убедитесь, что у вас есть работоспособный запасной вариант для подобных вещей.
Тимо Ор

4
Большое спасибо! Это действительно здорово. Я хотел поместить обзор, отчет об ошибках и поделиться действиями в переполнение, но это не показывалось на Nexus S. Пользователи даже не нажимают кнопку Меню. При переполнении пользователи видят, что доступны дополнительные действия.
Юрий Куликов

4
@Ewoks Я довольно опоздал на комментарий здесь, но я только что попробовал это с самой последней версией ActionBarCompat, и она работала.
января

3
Это работает на Samsung Galaxy S3 и S4, но не на LG G2 (подозреваю, что они жестко кодируют чек, чтобы показать кнопку меню переполнения)
DVD

18
Прекрасный! Если Eclipse дает вам 6 различных вариантов импорта, Fieldвыберите этот java.lang.reflect.Field;)
Eugene van der Merwe

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

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

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
leafcutter

7

Этот метод не поддерживается системой разработки для разработчиков Android, но я нашел способ его пройти:

Добавьте это в ваш файл меню 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 как довольно полное обсуждение темы с некоторыми конкретными предложениями о том, как обращаться с вашим кодом при переходе с уровня до 11 к новой панели действий.

Я все еще верю, что это была ошибка дизайна, потому что кнопка меню не функционировала как избыточная кнопка «Переполнение действия» в устройствах с включенной кнопкой меню, как лучший способ перенести пользовательский опыт, но его вода под мостом на данном этапе.


Я полностью согласен с вами по поводу ошибки дизайна - и это меня расстраивает!
Пол Ханнисетт

1
Я бы согласился с вами в этом, если бы не тот факт, что сам Google начал нарушать это правило в своем недавнем приложении G +. И по праву так. Кнопка меню не является устаревшей, даже у таких новых устройств, как SGS3. К сожалению, он здесь, чтобы остаться. И это серьезно затрудняет юзабилити.
Тимо Ор

4

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


2

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


2

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


1

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

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

Затем я раздуваю панель инструментов в своей деятельности. Я проверяю 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);
}
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.