Come forzare l'uso del menu di overflow sui dispositivi con il pulsante menu


159

Mi piacerebbe avere tutti gli elementi di menu che non rientrano nel movimento ActionBar nel menu di overflow (quello che si raggiunge dalla azione non Barra il tasto menu) anche su dispositivi che fare avere un pulsante Menu . Ciò sembra molto più intuitivo per gli utenti rispetto al loro lancio in un elenco di menu separato che richiede all'utente di passare da un'interazione touch (schermo) a un'interazione basata su pulsante semplicemente perché il layout di ActionBar non può adattarsi alla barra.

Sull'emulatore posso impostare il valore "Hardware Indietro / Chiavi di casa" su "no" e ottenere questo effetto. Ho cercato un modo per farlo nel codice per un dispositivo reale che ha un pulsante di menu ma non può andare bene. Qualcuno può aiutarmi?

Risposte:


54

EDIT: modificato per rispondere alla situazione del pulsante del menu fisico.

Questo è effettivamente impedito dal design. Secondo la sezione Compatibilità della Guida alla progettazione di Android ,

"... l'overflow delle azioni è disponibile dalla chiave hardware del menu. Il popup delle azioni risultanti ... viene visualizzato nella parte inferiore dello schermo."

Noterai negli screenshot, i telefoni con un pulsante di menu fisico non hanno un menu di overflow in ActionBar. Questo evita l'ambiguità per l'utente, essenzialmente avendo due pulsanti disponibili per aprire lo stesso menu.

Per affrontare il problema della coerenza tra i dispositivi: in definitiva, per l'utente è più importante che l'app si comporti in modo coerente con ogni altra app sullo stesso dispositivo, piuttosto che si comporti in modo coerente con se stessa su tutti i dispositivi.


1
Alexander - No, ho provato tutti i valori di showAsAction e diverse combinazioni e nessuna di esse ha funzionato (almeno sull'emulatore). Il menu di overflow sulla barra delle azioni viene visualizzato solo se emulo un dispositivo senza un pulsante di menu. Voglio vedere i puntini di sospensione verticali e gli elementi traboccanti vengono visualizzati lì sui dispositivi con un pulsante di menu. Ho modificato la mia domanda per renderlo un po 'più chiaro.
PaulP,

41
Entriamo in questa conversazione e discutiamo: so che è impedito dal design (ho letto le linee guida per il design). Ma è una specie di% $ /% # +, credo. Ad esempio: l'utente sta passando da un Galaxy Nexus (-> w Overflow) a un Nexus One (w 4.0 / -> no Overflow). Scommetto che l'utente non troverà più le voci di menu. Per questo motivo desidero lo stesso utilizzo per tutti i dispositivi. Quindi, sto finendo con lo stesso problema di Paul. Non è disponibile una soluzione alternativa pulita?
Sprigg

10
Anch'io ho letto prima la Guida alla progettazione. Per me questa è stata una cattiva scelta di design nel pacchetto di supporto. Una strategia migliore per trasferire gli utenti LONTANO dal pulsante (l'obiettivo, giusto?) Sarebbe quella di renderlo ridondante, mettere la funzionalità sullo schermo e nel pulsante. Allo stato attuale, il pulsante non elenca tutte le opzioni di menu, solo quelle non presenti sulla barra delle azioni, quindi questo design non supporta una transizione graduale alla barra delle azioni né fa ciò che era solito fare prima di aggiungere una barra delle azioni (visualizza tutto il menu scelte). Ho il sospetto che tu abbia ragione e che non ci sia una soluzione semplice.
PaulP,

18
Google si oppone a questo nelle loro nuove app Google +. Ha un elemento di overflow a prescindere dal dispositivo .. tuttavia impediscono agli sviluppatori di fare lo stesso e sconsigliare, a mia conoscenza.
Karl

10
Onestamente, ho visto troppi utenti non provare il tasto di scelta rapida del menu per aspettarselo. Se il design dice che qualsiasi utente su qualsiasi telefono non dovrebbe avere un indicatore sullo schermo che esistano opzioni di menu, quel design è scarsamente informato.
Lance Nanek,

323

Puoi anche usare questo piccolo trucco qui:

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 buon posto per dirlo sarebbe il onCreatemetodo della tua classe di applicazione.

Costringerà l'app a mostrare il menu di overflow. Il pulsante menu continuerà a funzionare, ma aprirà il menu nell'angolo in alto a destra.

[Modifica] Da quando è uscito diverse volte: questo trucco funziona solo con ActionBar nativo introdotto in Android 3.0, non con ActionBarSherlock. Quest'ultimo utilizza la propria logica interna per decidere se mostrare il menu di overflow. Se si utilizza ABS, tutte le piattaforme <4.0 sono gestite da ABS e sono quindi soggette alla sua logica. L'hacking continuerà a funzionare su tutti i dispositivi con Android 4.0 o versioni successive (puoi tranquillamente ignorare Android 3.x, dal momento che in realtà non ci sono tablet con un pulsante di menu).

Esiste uno speciale tema ForceOverflow che forzerà il menu in ABS, ma apparentemente verrà rimosso nelle versioni future a causa di complicazioni .


4
Ho guardato attraverso il codice sorgente. Tesoro di funzionalità prive di documenti :) Assicurati di avere un fallback funzionale per cose del genere.
Timo Ohr,

4
Molte grazie! Questo è davvero fantastico. Volevo mettere recensioni, segnalazioni di bug e condividere azioni in overflow, ma non era mostrato su Nexus S. Gli utenti non avrebbero nemmeno fatto clic sul pulsante Menu. Con l'overflow, gli utenti vedono che sono disponibili azioni extra.
Yuriy Kulikov,

4
@Ewoks Sono abbastanza in ritardo sul commento qui, ma ho appena provato questo con la versione più recente di ActionBarCompat e ha funzionato.
Jacobhyphenated

3
Funziona su Samsung Galaxy S3 e S4, ma non su LG G2 (sospetto che stiano codificando il controllo per mostrare il pulsante del menu di overflow)
dvd

18
Bellissimo! Se Eclipse ti offre 6 diverse importazioni tra cui scegliere per Fieldscegliere questa java.lang.reflect.Field;)
Eugene van der Merwe,

35

Uso per aggirare il problema definendo il mio menu in questo modo (anche con l'icona ActionBarSherlock utilizzata nel mio esempio):

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

Ammetto che questo potrebbe richiedere una "gestione dell'overflow" manuale nel tuo XML, ma ho trovato utile questa soluzione.

Puoi anche forzare il dispositivo a utilizzare il pulsante HW per aprire il menu di overflow, nella tua attività:

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
come utilizzare il pulsante HW per aprire il menu di overflow?
bladefury

1
Vedi la mia risposta aggiornata per l'apertura del menu di overflow con il pulsante HW. :)
Berťák,

11

Se si utilizza la barra delle azioni dalla libreria di supporto ( android.support.v7.app.ActionBar), utilizzare quanto segue:

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

Quando ho usato la libreria di supporto ho implementato anche questo e funziona bene su entrambi i dispositivi pre e post 3.0
leafcutter

7

Questo tipo di metodo è impedito da Android Developers Design System, ma ho trovato un modo per passarlo:

Aggiungi questo al tuo file di 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" />

Successivamente, crea una classe denominata "AppPickActionProvider" e copia il seguente codice:

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

qual è la differenza tra l'utilizzo di questo metodo e l'utilizzo di un sottomenu, come mostrato qui: stackoverflow.com/a/14634780/878126 ?
sviluppatore Android

5

Beh, penso che Alexander Lucas abbia fornito (purtroppo) la risposta corretta, quindi la segnerò come "corretta". La risposta alternativa che sto aggiungendo qui è semplicemente quella di indicare qualsiasi nuovo lettore a questo post nel blog degli sviluppatori Android come una discussione piuttosto completa sull'argomento con alcuni suggerimenti specifici su come gestire il codice quando si passa dal pre-livello 11 alla nuova barra delle azioni.

Credo ancora che sia stato un errore di progettazione il fatto che il pulsante menu non si comporti come un pulsante "Action Overflow ridondante" nei dispositivi abilitati pulsante pulsante come un modo migliore per trasferire l'esperienza dell'utente, ma la sua acqua sotto il ponte a questo punto.


Sono completamente d'accordo con te sull'errore di progettazione e lo trovo frustrante!
Paul Hunnisett,

1
Concordo con te su questo, se non fosse per il fatto che Google stesso ha iniziato a violare quella regola nella sua recente app G +. E giustamente. Il pulsante menu non è legacy, anche i nuovi dispositivi come SGS3 ce l'hanno. Purtroppo è qui per restare. E ostacola seriamente l'usabilità.
Timo Ohr,

4

Non sono sicuro se questo è quello che stai cercando, ma ho creato un sottomenu nel menu di ActionBar e impostato la sua icona in modo che corrisponda all'icona del menu di overflow. Sebbene non gli vengano inviati automaticamente degli articoli, (IE devi scegliere ciò che è sempre visibile e ciò che è sempre traboccato), mi sembra che questo approccio possa aiutarti.


2

Nell'app Gmail fornita con ICS preinstallato, il pulsante menu è disabilitato quando sono selezionati più elementi. Il menu di overflow è qui "forzato" per essere attivato dall'uso del pulsante di overflow invece del pulsante di menu fisico. C'è una libreria di terze parti chiamata ActionBarSherlock che ti permette di "forzare" il menu di overflow. Ma questo funzionerà solo a livello API 14 o inferiore (pre-ICS)


2

Se usi Toolbar , puoi mostrare l'overflow su tutte le versioni e tutti i dispositivi, ho provato su alcuni dispositivi 2.x, funziona.


1

Scusa se questo problema è morto.

Ecco cosa ho fatto per risolvere l'errore. Sono andato ai layout e ne ho creati due contenenti barre degli strumenti. Uno era un layout per SDK versione 8 e l'altro era per SDK versione 21. Nella versione 8, ho usato android.support.v7.widget.Toolbar mentre ho usato android.widget.Toolbar sul layout SDK 21.

Quindi gonfio la barra degli strumenti nella mia attività. Controllo lo sdk per vedere se era 21 o superiore. Quindi gonfio il layout corrispondente. In questo modo il pulsante hardware viene mappato sulla barra degli strumenti effettivamente progettata.


0

Per chiunque utilizzi il nuovo 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);
}
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.