So erzwingen Sie die Verwendung des Überlaufmenüs auf Geräten mit der Menütaste

159

Ich möchte, dass alle Menüelemente, die nicht in die ActionBar passen, in das Überlaufmenü (das über die Aktionsleiste und nicht über die Menüschaltfläche erreicht wird) verschoben werden, auch auf Geräten, die über eine Menüschaltfläche verfügen . Dies scheint für Benutzer viel intuitiver zu sein, als sie in eine separate Menüliste zu werfen, in der der Benutzer von einer Touchscreen-Interaktion (Bildschirminteraktion) zu einer auf Schaltflächen basierenden Interaktion springen muss, nur weil das Layout der ActionBar nicht in die Leiste passt.

Auf dem Emulator kann ich den Wert "Hardware Back / Home Keys" auf "no" setzen und diesen Effekt erzielen. Ich habe nach einer Möglichkeit gesucht, dies im Code für ein tatsächliches Gerät zu tun, das eine Menüschaltfläche hat, aber keine in Ordnung bringen kann. Kann mir jemand helfen?

PaulP
quelle

Antworten:

54

BEARBEITEN: Geändert, um auf die Situation der physischen Menütaste zu reagieren.

Dies wird tatsächlich durch Design verhindert. Gemäß der Kompatibilität Abschnitt des Android Design Guide ,

"... der Aktionsüberlauf ist über die Menü-Hardwaretaste verfügbar. Das resultierende Aktions-Popup ... wird am unteren Bildschirmrand angezeigt."

Sie werden in den Screenshots feststellen, dass Telefone mit einer physischen Menütaste kein Überlaufmenü in der Aktionsleiste haben. Dies vermeidet Mehrdeutigkeiten für den Benutzer, da im Wesentlichen zwei Schaltflächen verfügbar sind, um genau dasselbe Menü zu öffnen.

So lösen Sie das Problem der Konsistenz zwischen Geräten: Letztendlich ist es für die Benutzererfahrung wichtiger, dass sich Ihre App mit jeder anderen App auf demselben Gerät konsistent verhält, als dass sie sich auf allen Geräten konsistent mit sich selbst verhält.

Alexander Lucas
quelle
1
Alexander - Nein, ich habe alle showAsAction-Werte und mehrere Kombinationen ausprobiert und keine davon macht den Trick (zumindest auf dem Emulator). Das Überlaufmenü in der Aktionsleiste wird nur angezeigt, wenn ich ein Gerät ohne Menüschaltfläche emuliere . Ich möchte sehen, dass vertikale Auslassungspunkte und überlaufende Elemente dort auf Geräten mit einer Menütaste angezeigt werden. Ich habe meine Frage bearbeitet, um das etwas klarer zu machen.
PaulP
41
Lassen Sie uns in dieses Gespräch eintreten und diskutieren: Ich weiß, dass es durch Design verhindert wird (ich habe die Designrichtlinien gelesen). Aber das ist eine Art% $ /% # +, denke ich. Beispiel: Der Benutzer wechselt von einem Galaxy Nexus (-> w Überlauf) zu einem Nexus One (w 4.0 / -> kein Überlauf). Ich wette, der Benutzer findet die Menüpunkte nicht mehr. Aus diesem Grund möchte ich für alle Geräte die gleiche Verwendung. Also habe ich das gleiche Problem wie Paulp. Gibt es keine saubere Problemumgehung?
Sprigg
10
Ich habe auch zuerst den Design Guide gelesen. Für mich war dies eine schlechte Wahl des Designs im Support-Paket. Eine bessere Strategie, um Benutzer von der Schaltfläche fernzuhalten (das Ziel, richtig?), Wäre, sie überflüssig zu machen und die Funktionalität sowohl auf dem Bildschirm als auch in der Schaltfläche anzuzeigen. Aus heutiger Sicht listet die Schaltfläche nicht alle Menüoptionen auf, sondern nur diejenigen, die sich nicht in der Aktionsleiste befinden. Daher unterstützt dieses Design weder einen reibungslosen Übergang zur Aktionsleiste noch das, was es vor dem Hinzufügen einer Aktionsleiste getan hat ( alle Menüs anzeigen) Entscheidungen). Ich vermute, Sie haben Recht und es gibt keine einfache Problemumgehung.
PaulP
18
Google geht in seinen neuen Google + Apps dagegen vor. Es hat ein Überlaufelement, unabhängig vom Gerät. Dennoch verhindern sie meines Wissens Entwickler, dasselbe zu tun, und raten davon ab.
Karl
10
Ehrlich gesagt habe ich viel zu viele Benutzer gesehen, die den Menü-Hardkey nicht ausprobiert haben, um es jemals zu erwarten. Wenn das Design besagt, dass ein Benutzer eines Telefons keine Anzeige auf dem Bildschirm haben sollte, dass Menüoptionen vorhanden sind, ist dieses Design schlecht informiert.
Lance Nanek
323

Sie können diesen kleinen Hack auch hier verwenden:

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

Ein guter Ort, um es onCreateauszudrücken, wäre die Methode Ihrer Anwendungsklasse.

Dadurch wird die App gezwungen, das Überlaufmenü anzuzeigen. Die Menüschaltfläche funktioniert weiterhin, öffnet jedoch das Menü in der oberen rechten Ecke.

[Bearbeiten] Da es jetzt schon mehrmals aufgetaucht ist: Dieser Hack funktioniert nur für die native ActionBar, die in Android 3.0 eingeführt wurde, nicht für ActionBarSherlock. Letzterer verwendet seine eigene interne Logik, um zu entscheiden, ob das Überlaufmenü angezeigt werden soll. Wenn Sie ABS verwenden, werden alle Plattformen <4.0 von ABS verwaltet und unterliegen somit seiner Logik. Der Hack funktioniert weiterhin für alle Geräte mit Android 4.0 oder höher (Sie können Android 3.x ignorieren, da es keine Tablets mit einer Menüschaltfläche gibt).

Es gibt ein spezielles ForceOverflow-Theme, das das Menü in ABS erzwingt, aber es wird anscheinend in zukünftigen Versionen aufgrund von Komplikationen entfernt .

Timo Ohr
quelle
4
Ich habe den Quellcode durchgesehen. Schatzkamm mit undokumentierten Funktionen :) Stellen Sie einfach sicher, dass Sie für solche Dinge einen funktionsfähigen Fallback haben.
Timo Ohr
4
Vielen Dank! Das ist wirklich toll. Ich wollte Überprüfungs-, Fehlerberichterstellungs- und Freigabeaktionen in den Überlauf einfügen, aber es wurde auf Nexus S nicht angezeigt. Benutzer klicken nicht einmal auf die Menüschaltfläche. Mit dem Überlauf sehen Benutzer, dass zusätzliche Aktionen verfügbar sind.
Yuriy Kulikov
4
@Ewoks Ich bin ziemlich spät dran, aber ich habe es gerade mit der neuesten Version von ActionBarCompat versucht, und es hat funktioniert.
jacobhyphenated
3
Dies funktioniert auf dem Samsung Galaxy S3 und S4, aber nicht auf dem LG G2 (vermutlich verdunkeln sie die Prüfung, um die Schaltfläche für das Überlaufmenü anzuzeigen)
DVD
18
Wunderschönen! Wenn Eclipse Ihnen 6 verschiedene Importe zur Auswahl bietet, wählen FieldSie diesen aus java.lang.reflect.Field;)
Eugene van der Merwe
35

Um dies zu umgehen, definiere ich mein Menü wie folgt (auch mit dem in meinem Beispiel verwendeten ActionBarSherlock-Symbol):

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

Ich gebe zu, dass dies möglicherweise ein manuelles "Überlaufmanagement" in Ihrer XML erfordert, aber ich fand diese Lösung nützlich.

Sie können das Gerät in Ihrer Aktivität auch zwingen, die HW-Taste zum Öffnen des Überlaufmenüs zu verwenden:

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

:-)

Berťák
quelle
2
Wie öffne ich mit der HW-Taste das Überlaufmenü?
Bladefury
1
Siehe meine aktualisierte Antwort zum Öffnen des Überlaufmenüs mit der HW-Taste. :)
Berťák
11

Wenn Sie die Aktionsleiste aus der Support-Bibliothek ( android.support.v7.app.ActionBar) verwenden, verwenden Sie Folgendes:

<?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>
ein fairer Spieler
quelle
Bei Verwendung der Support-Bibliothek habe ich dies ebenfalls implementiert und es funktioniert sowohl auf Geräten vor als auch nach 3.0
Leafcutter
7

Diese Art von Methode wird vom Android Developers Design System verhindert, aber ich habe einen Weg gefunden, sie zu bestehen:

Fügen Sie dies Ihrer XML-Menüdatei hinzu:

<item android:id="@+id/pick_action_provider"
    android:showAsAction="always"
    android:title="More"
    android:icon="@drawable/ic_action_overflow"
    android:actionProviderClass="com.example.AppPickActionProvider" />

Erstellen Sie als Nächstes eine Klasse mit dem Namen 'AppPickActionProvider' und kopieren Sie den folgenden Code:

    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;
    }
}
Eli Revah
quelle
Was ist der Unterschied zwischen der Verwendung dieser Methode und der Verwendung eines Untermenüs, wie hier gezeigt: stackoverflow.com/a/14634780/878126 ?
Android-Entwickler
5

Nun, ich denke, dass Alexander Lucas die (leider) richtige Antwort gegeben hat, also markiere ich sie als die "richtige". Die alternative Antwort, die ich hier hinzufüge, besteht einfach darin, neue Leser auf diesen Beitrag im Android Developers-Blog als eine ziemlich vollständige Diskussion des Themas mit einigen spezifischen Vorschlägen zum Umgang mit Ihrem Code beim Übergang von Pre-Level 11 hinzuweisen zur neuen Aktionsleiste.

Ich glaube immer noch, dass es ein Designfehler war, wenn sich die Menüschaltfläche nicht als redundante "Aktionsüberlauf" -Schaltfläche in Geräten mit Menüschaltfläche verhält, um die Benutzererfahrung zu verbessern, sondern das Wasser unter der Brücke zu diesem Zeitpunkt.

PaulP
quelle
Ich stimme Ihnen in Bezug auf den Designfehler voll und ganz zu - und finde das frustrierend!
Paul Hunnisett
1
Ich würde Ihnen darin zustimmen, wenn Google nicht in seiner jüngsten G + App gegen diese Regel verstoßen hätte. Und das zu Recht. Die Menüschaltfläche ist kein Legacy, auch neue Geräte wie das SGS3 haben sie. Es ist leider hier, um zu bleiben. Und es beeinträchtigt ernsthaft die Benutzerfreundlichkeit.
Timo Ohr
4

Ich bin mir nicht sicher, ob dies das ist, wonach Sie suchen, aber ich habe ein Untermenü im Menü der Aktionsleiste erstellt und das Symbol so eingestellt, dass es mit dem Symbol des Überlaufmenüs übereinstimmt. Obwohl keine Elemente automatisch an ihn gesendet werden (dh Sie müssen auswählen, was immer sichtbar und was immer übergelaufen ist), scheint mir dieser Ansatz hilfreich zu sein.

Chris
quelle
2

In der mit vorinstalliertem ICS gelieferten Google Mail-App ist die Menüschaltfläche deaktiviert, wenn Sie mehrere Elemente ausgewählt haben. Das Überlaufmenü wird hier "gezwungen", durch die Verwendung der Überlauftaste anstelle der physischen Menütaste ausgelöst zu werden. Es gibt eine Drittanbieter-Bibliothek namens ActionBarSherlock, mit der Sie das Überlaufmenü "erzwingen" können. Dies funktioniert jedoch nur auf API-Ebene 14 oder niedriger (vor ICS).

Borislemke
quelle
2

Wenn Sie die Symbolleiste verwenden , können Sie den Überlauf auf allen Versionen und allen Geräten anzeigen. Ich habe es auf einigen 2.x-Geräten versucht. Es funktioniert.

TeeTracker
quelle
1

Entschuldigung, wenn dieses Problem behoben ist.

Folgendes habe ich getan, um den Fehler zu beheben. Ich ging zu Layouts und erstellte zwei mit Symbolleisten. Eines war ein Layout für SDK Version 8 und das andere war für SDK Version 21. In Version 8 habe ich die android.support.v7.widget.Toolbar verwendet, während ich android.widget.Toolbar für das SDK 21 Layout verwendet habe.

Dann blase ich die Symbolleiste in meiner Aktivität auf. Ich überprüfe das SDK, um festzustellen, ob es 21 oder höher war. Ich blase dann das entsprechende Layout auf. Dadurch wird die Hardware-Schaltfläche gezwungen, der tatsächlich entworfenen Symbolleiste zuzuordnen.

Dolandlod
quelle
0

Für alle, die das neue verwenden 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);
}
Maksim Ivanov
quelle