Як змусити використовувати меню переповнення на пристроях з кнопкою меню


159

Мені б хотілося, щоб усі пункти меню, які не входять у панель ActionBar, перейшли в меню переповнення (те, що дістається з панелі дій, а не кнопка меню), навіть на пристроях, у яких є кнопка меню . Користувачам це здається набагато інтуїтивнішим, ніж кидання їх в окремий список меню, який вимагає від користувача перейти з взаємодії на дотику (екрані) до взаємодії на основі кнопок просто тому, що макет ActionBar не може вмістити їх на панелі.

На емуляторі я можу встановити значення "Назад / Домашні ключі" на "ні" і отримати цей ефект. Я шукав спосіб зробити це в коді для фактичного пристрою, на якому є кнопка меню, але не вдається виправити її. Хтось може мені допомогти?

Відповіді:


54

EDIT: Змінено, щоб відповідати ситуації фізичної кнопки меню.

Це фактично заважає дизайну. Відповідно до розділу сумісності Посібника з дизайну Android ,

"... переповнення дії доступне з апаратної клавіші меню. Отримані спливаючі дії ... відображаються внизу екрана."

Зауважте на знімках екрана, що у телефонів із фізичною кнопкою меню немає меню переповнення в панелі дій. Це дозволяє уникнути неоднозначності для користувача, фактично маючи дві кнопки для відкриття точно такого ж меню.

Щоб вирішити проблему послідовності на різних пристроях: Зрештою, для користувачів важливіше, щоб ваш додаток поводився послідовно з усіма іншими програмами на тому ж пристрої, ніж те, що він веде себе послідовно на всіх пристроях.


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

41
Давайте вступимо в цю розмову і обговоримо: я знаю, що дизайну це заважає (я читаю рекомендації щодо дизайну). Але такий вид% $ /% # +, я думаю. Наприклад: користувач переходить з Galaxy Nexus (-> w Overflow) на Nexus One (w 4.0 / -> без переповнення). Надіюсь, користувач більше не знайде пунктів меню. З цієї причини я хочу використовувати однакове використання для всіх пристроїв. Отже, я закінчую ту саму проблему, що і паульп. Чи не доступний чистий спосіб вирішення?
Sprigg

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 обробляються АБС, тому вони підлягають його логіці. Злом все ще працюватиме на всіх пристроях з Android 4.0 або новішою версією (ви можете сміливо ігнорувати Android 3.x, оскільки насправді там немає ніяких планшетів із кнопкою меню).

Існує спеціальна ForceOverflow-Theme, яка змусить меню в ABS, але, очевидно, вона буде видалена в наступних версіях через ускладнення .


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

4
Дуже дякую! Це справді чудово. Я хотів включити перегляд, bugreport і поділити дії в переповнення, але це не відображалося на Nexus S. Користувачі навіть не натискають кнопку Меню. З переповненням користувачі бачать, що доступні додаткові дії.
Юрій Куликов

4
@Ewoks Я досить пізно зауважую тут коментар, але я просто спробував це з останньою версією ActionBarCompat, і це DID працює.
Якобфінований

3
Це працює на Samsung Galaxy S3 і S4, а не на LG G2 (підозрюють , що вони жорстке кодування перевірки , щоб показати кнопку меню переповнення)
DVD

18
Гарний! Якщо Eclipse дає вам як 6 різних імпортів на вибір, Fieldвиберіть цей java.lang.reflect.Field;)
Євген ван дер Мерве

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
листопад

7

Система дизайну 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;
    }
}

яка різниця між використанням цього методу та просто використанням підменю, як показано тут: stackoverflow.com/a/14634780/878126 ?
андроїд розробник

5

Я думаю, що Олександр Лукас дав (на жаль) правильну відповідь, тому я відзначаю це як "правильний". Альтернативна відповідь, яку я додаю тут, полягає в тому, щоб просто вказати будь-яким новим читачам на цю публікацію в блозі розробників Android як досить повне обговорення теми з деякими конкретними пропозиціями щодо того, як поводитися зі своїм кодом при переході з 11 рівня попереднього рівня до нової панелі дій.

Я все ще вважаю, що це була помилка дизайну: не те, що кнопка меню поводиться як надмірна кнопка "Переповнення дії" на пристроях із кнопкою меню, як кращий спосіб переходу користувальницького досвіду, але його вода під мостом у цей момент.


Я повністю згоден з вами щодо помилки дизайну - і я вважаю це неприємним!
Пол Хуннісетт

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

4

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


2

У додатку gmail, який постачається з попередньо встановленою ICS, кнопка меню відключається, якщо у вас вибрано кілька елементів. Меню переповнення тут "змушене" спрацьовувати за допомогою кнопки переповнення замість фізичної кнопки меню. Є сторона-ліб під назвою ActionBarSherlock, яка дозволяє "форсувати" меню переповнення. Але це буде працювати лише на рівні API 14 або нижчого (до ICS)


2

Якщо ви використовуєте Панель інструментів , ви можете показувати переповнення на всіх версіях та на всіх пристроях, я пробував на деяких пристроях 2.x, він працює.


1

Вибачте, якщо ця проблема померла.

Ось що я зробив, щоб усунути помилку. Я перейшов до макетів і створив дві з панелей інструментів. Один був макетом для версії 8 SDK, а інший для версії 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.