web-dev-qa-db-fra.com

Comment forcer l'utilisation du menu de débordement sur les périphériques avec le bouton de menu

Je souhaite que tous les éléments de menu qui ne rentrent pas dans la barre d’action entrent dans le menu de débordement (celui accessible à partir de la barre d’action, pas le bouton de menu) , même sur Les appareils qui do ont un bouton Menu . Cela semble beaucoup plus intuitif pour les utilisateurs que de les ajouter à une liste de menus distincte qui oblige l'utilisateur à passer d'une interaction tactile (écran) à une interaction basée sur un bouton, tout simplement parce que la disposition de la barre Action ne peut pas les adapter à la barre.

Sur l'émulateur, je peux définir la valeur "non" de la valeur "Hardware Back/Home Keys" et obtenir cet effet. J'ai cherché un moyen de le faire dans le code pour un périphérique réel qui possède un bouton de menu mais ne peut en régler un. Quelqu'un peut-il m'aider?

158
PaulP

EDIT: Modifié pour répondre à la situation du bouton de menu physique.

Ceci est en fait empêché par la conception. Selon le Section de compatibilité du Android Guide de conception ,

"... le dépassement d’action est disponible à partir de la clé matérielle du menu. La fenêtre contextuelle des actions résultantes ... est affichée en bas de l’écran."

Vous remarquerez que dans les captures d'écran, les téléphones dotés d'un bouton de menu physique ne disposent pas d'un menu de dépassement de capacité dans la barre d'actions. Ceci évite toute ambiguïté pour l'utilisateur, ayant essentiellement deux boutons disponibles pour ouvrir exactement le même menu.

Pour résoudre le problème de la cohérence entre les appareils: En définitive, il est plus important pour l'expérience utilisateur que votre application se comporte de manière cohérente avec toutes les autres applications d'un même appareil, plutôt que de se comporter de manière cohérente avec tous les appareils.

54
Alexander Lucas

Vous pouvez aussi utiliser ce petit bidouillage ici:

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

Un bon endroit pour le mettre serait la méthode onCreate- de votre classe d’application.

Cela forcera l'application à afficher le menu de débordement. Le bouton de menu fonctionnera toujours, mais ouvrira le menu dans le coin supérieur droit.

[Modifier] Puisqu'il a été soulevé à plusieurs reprises maintenant: Ce hack ne fonctionne que pour le ActionBar natif introduit dans Android 3.0, pas ActionBarSherlock. Ce dernier utilise sa propre logique interne pour décider d'afficher le Si vous utilisez ABS, toutes les plates-formes <4.0 sont gérées par ABS et sont donc soumises à sa logique.Le hack fonctionnera toujours pour tous les appareils avec Android 4.0 ou supérieur (vous pouvez en toute sécurité ignore Android 3.x, car il n’ya pas vraiment de tablette avec un bouton de menu).

Il existe un thème spécial ForceOverflow qui forcera le menu dans ABS, mais il est apparemment il sera supprimé dans les versions futures à cause de complications .

323
Timo Ohr

J'avais l'habitude de contourner le problème en définissant mon menu comme suit (également avec l'icône ActionBarSherlock utilisée dans mon exemple):

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

J'admets que cela nécessitera peut-être une "gestion de débordement" manuelle dans votre code xml, mais j'ai trouvé cette solution utile.

Vous pouvez également forcer l’appareil à utiliser le bouton matériel pour ouvrir le menu de débordement, dans votre activité:

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

:-)

35
Berťák

Si vous utilisez la barre d’actions de la bibliothèque de support (Android.support.v7.app.ActionBar), utilisez le suivant:

<?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>
11
a fair player

Ce type de méthode est empêché par le Android Developers Design System, mais j’ai trouvé un moyen de le transmettre:

Ajoutez ceci à votre fichier de menu 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" />

Ensuite, créez une classe nommée 'AppPickActionProvider', et copiez-y le code suivant:

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

Eh bien, je pense que Alexander Lucas a fourni la réponse (malheureusement) correcte, alors je la marque comme "correcte". La réponse alternative que j’ajoute ici est simplement de pointer tout nouveau lecteur sur ce message dans le Android blog Développeurs comme une discussion assez complète sur le sujet avec des des suggestions quant à la façon de traiter votre code lors de la transition du niveau antérieur à la version 11 à la nouvelle barre d’action.

Je crois toujours que c’est une erreur de conception que le bouton de menu ne se comporte pas comme un bouton redondant "Action Overflow" dans les périphériques activés pour les boutons de menu comme un meilleur moyen de faire la transition de l’expérience utilisateur, mais que son eau est sous le pont à ce stade.

5
PaulP

Je ne sais pas si c'est ce que vous cherchez, mais j'ai créé un sous-menu dans le menu de la barre d'actions et défini son icône pour correspondre à celle du menu de dépassement. Bien que les éléments ne lui soient pas automatiquement envoyés (vous devez par exemple choisir ce qui est toujours visible et ce qui est toujours débordé), il me semble que cette approche peut vous aider.

4
Chris

Si vous utilisez Toolbar , vous pouvez afficher le débordement sur toutes les versions et tous les périphériques. J'ai essayé sur certains périphériques 2.x. Cela fonctionne.

2
TeeTracker

Dans l'application Gmail fournie avec ICS pré-installé, le bouton de menu est désactivé lorsque plusieurs éléments sont sélectionnés. Le menu de débordement est ici "forcé" pour être déclenché par l'utilisation du débordement bouton au lieu du bouton du menu physique. Il existe une bibliothèque tierce appelée ActionBarSherlock qui vous permet de "forcer" le menu de débordement, mais cela ne fonctionnera que sur les API de niveau 14 ou inférieur (pré-ICS)

2
borislemke

Désolé si ce problème est mort.

Voici ce que j'ai fait pour résoudre l'erreur. Je suis allé dans les mises en page et en ai créé deux avec des barres d’outils. L'un était une mise en page pour la version 8 de sdk et l'autre, pour la version 21 de sdk. Sur la version 8, j'ai utilisé Android.support.v7.widget.Toolbar alors que j'utilisais Android.widget.Toolbar sur la présentation de sdk 21.

Ensuite, je gonfle la barre d’outils dans mon activité. Je vérifie le SDK pour voir s'il était 21 ou plus. Je gonfle ensuite la mise en page correspondante. Cela oblige le bouton matériel à correspondre à la barre d'outils que vous avez réellement conçue.

1
Dolandlod

Pour ceux qui utilisent le nouveau 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);
}
0
Maksim Ivanov