Cara memaksa penggunaan menu overflow pada perangkat dengan tombol menu

159

Saya ingin semua item menu yang tidak masuk ke dalam ActionBar masuk ke menu overflow (item yang dicapai dari Action Bar bukan tombol menu) bahkan pada perangkat yang melakukan memiliki tombol Menu . Ini tampaknya jauh lebih intuitif bagi pengguna daripada melemparkan mereka ke daftar menu terpisah yang mengharuskan pengguna untuk beralih dari interaksi sentuh (layar) ke interaksi berbasis tombol hanya karena tata letak ActionBar tidak dapat memuatnya di bar.

Pada emulator saya dapat mengatur nilai "Hardware Back / Home Keys" menjadi "tidak" dan mendapatkan efek ini. Saya telah mencari cara untuk melakukan ini dalam kode untuk perangkat aktual yang memiliki tombol menu tetapi tidak bisa baik-baik saja. Ada yang bisa bantu saya?

PaulP
sumber

Jawaban:

54

EDIT: Dimodifikasi untuk menjawab situasi tombol menu fisik.

Ini sebenarnya dicegah oleh desain. Menurut Bagian Kompatibilitas dari Panduan Desain Android ,

"... action overflow tersedia dari tombol perangkat keras menu. Popup tindakan yang dihasilkan ... ditampilkan di bagian bawah layar."

Anda akan perhatikan di tangkapan layar, ponsel dengan tombol menu fisik tidak memiliki menu overflow di ActionBar. Ini menghindari ambiguitas bagi pengguna, pada dasarnya memiliki dua tombol yang tersedia untuk membuka menu yang sama persis.

Untuk mengatasi masalah konsistensi antar perangkat: Pada akhirnya lebih penting bagi pengalaman pengguna bahwa aplikasi Anda berperilaku konsisten dengan setiap aplikasi lain di perangkat yang sama, daripada berperilaku konsisten dengan dirinya sendiri di semua perangkat.

Alexander Lucas
sumber
1
Alexander - Tidak, saya sudah mencoba semua nilai showAsAction dan beberapa kombinasi dan tidak ada yang melakukan trik (setidaknya pada emulator). Menu melimpah di bilah tindakan hanya muncul jika saya meniru perangkat tanpa tombol menu. Saya ingin melihat elipsis vertikal dan item yang meluap muncul di perangkat dengan tombol menu. Saya telah mengedit pertanyaan saya untuk membuatnya lebih jelas.
PaulP
41
Mari kita selami percakapan ini dan diskusikan: Saya tahu ini terhalang oleh desain (saya membaca pedoman desain). Tapi itu semacam% $ /% # +, kurasa. Misalnya: pengguna beralih dari Galaxy Nexus (-> w Overflow) ke Nexus One (w 4.0 / -> no Overflow). Saya yakin pengguna tidak akan menemukan item menu lagi. Untuk alasan itu saya ingin penggunaan yang sama untuk semua perangkat. Jadi, saya berakhir dengan masalah yang sama dengan paulp. Apakah tidak ada solusi bersih yang tersedia?
Sprigg
10
Saya juga membaca Panduan Desain terlebih dahulu. Bagi saya ini adalah pilihan desain yang buruk dalam paket dukungan. Strategi yang lebih baik untuk mentransisikan pengguna JAUH dari tombol (tujuannya, kan?) Adalah membuatnya berlebihan, meletakkan fungsionalitas di layar serta di tombol. Seperti sekarang, tombol tidak mencantumkan semua pilihan menu, hanya yang tidak ada di actionbar, jadi desain ini tidak mendukung transisi yang mulus ke actionbar juga tidak melakukan apa yang biasa dilakukan sebelum menambahkan actionbar (tampilkan semua menu) pilihan). Saya curiga Anda benar dan tidak ada solusi sederhana.
PaulP
18
Google menentang ini di aplikasi Google + baru mereka. Itu memiliki item meluap terlepas dari perangkat .. namun mereka masih mencegah pengembang melakukan hal yang sama dan saran untuk itu, setahu saya.
Karl
10
Jujur, saya telah melihat terlalu banyak pengguna yang tidak mencoba menu hard key yang pernah mereka harapkan. Jika desain mengatakan bahwa pengguna di ponsel apa pun seharusnya tidak memiliki indikator di layar bahwa opsi menu ada, desain itu adalah informasi yang kurang.
Lance Nanek
323

Anda juga dapat menggunakan hack kecil ini di sini:

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

Tempat yang baik untuk meletakkannya adalah onCreate-Metode dari kelas Aplikasi Anda.

Ini akan memaksa App untuk menampilkan menu overflow. Tombol menu akan tetap berfungsi, tetapi akan membuka menu di sudut kanan atas.

[Sunting] Karena sudah muncul beberapa kali sekarang: Peretasan ini hanya berfungsi untuk ActionBar asli yang diperkenalkan di Android 3.0, bukan ActionBarSherlock. Yang terakhir menggunakan logika internalnya sendiri untuk memutuskan apakah akan menampilkan menu overflow. Jika Anda menggunakan ABS, semua platform <4.0 ditangani oleh ABS dan karenanya tunduk pada logikanya. Peretasan masih akan bekerja untuk semua perangkat dengan Android 4.0 atau lebih tinggi (Anda dapat dengan aman mengabaikan Android 3.x, karena sebenarnya tidak ada tablet di luar sana dengan tombol menu).

Ada ForceOverflow-Theme khusus yang akan memaksa menu di ABS, tetapi tampaknya akan dihapus di versi masa depan karena komplikasi .

Timo Ohr
sumber
4
Saya melihat melalui kode sumber. Hutan harta karun dari fitur tidak berdokumen :) Pastikan Anda memiliki fallback yang bisa diterapkan untuk hal-hal seperti itu.
Timo Ohr
4
Terima kasih banyak! Ini sangat bagus. Saya ingin memberi ulasan, melaporkan bug, dan berbagi tindakan ke dalam luapan, tetapi tidak muncul di Nexus S. Pengguna bahkan tidak akan mengklik tombol Menu. Dengan meluapnya pengguna melihat bahwa tindakan tambahan tersedia.
Yuriy Kulikov
4
@Ewoks Saya sangat terlambat dengan komentar di sini, tapi saya baru saja mencoba ini dengan versi terbaru dari ActionBarCompat, dan itu TIDAK berfungsi.
jacobhyphenated
3
Ini bekerja pada Samsung Galaxy S3 dan S4, tetapi tidak pada LG G2 (menduga mereka mengkodekan cek untuk menunjukkan tombol menu melimpah)
dvd
18
Cantik! Jika Eclipse memberi Anda suka 6 impor berbeda untuk dipilih, Fieldpilih ini java.lang.reflect.Field;)
Eugene van der Merwe
35

Saya menggunakan untuk mengatasinya dengan mendefinisikan menu saya seperti ini (juga dengan ikon ActionBarSherlock yang digunakan dalam contoh saya):

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

Saya akui ini mungkin memerlukan manual "manajemen overflow" di xml Anda, tetapi saya menemukan solusi ini bermanfaat.

Anda juga dapat memaksa perangkat untuk menggunakan tombol HW untuk membuka menu overflow, dalam aktivitas Anda:

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
sumber
2
bagaimana cara menggunakan tombol HW untuk membuka menu overflow?
bladefury
1
Lihat jawaban saya yang diperbarui untuk membuka menu overflow dengan tombol HW. :)
Berťák
11

Jika Anda menggunakan bilah tindakan dari perpustakaan dukungan ( android.support.v7.app.ActionBar), gunakan yang berikut ini:

<?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>
pemain yang adil
sumber
Saat menggunakan perpustakaan dukungan, saya menerapkan ini juga dan berfungsi baik pada perangkat pra dan pasca 3.0
leafcutter
7

Metode semacam ini dicegah oleh Sistem Desain Pengembang Android, tapi saya menemukan cara untuk melewatinya:

Tambahkan ini ke file menu XML Anda:

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

Selanjutnya, buat kelas bernama 'AppPickActionProvider', dan salin kode berikut untuk itu:

    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
sumber
apa perbedaan antara menggunakan metode ini dan hanya menggunakan submenu, seperti yang ditunjukkan di sini: stackoverflow.com/a/14634780/878126 ?
pengembang android
5

Yah saya pikir Alexander Lucas telah memberikan (sayangnya) jawaban yang benar jadi saya menandainya sebagai jawaban yang "benar". Jawaban alternatif yang saya tambahkan di sini adalah dengan mengarahkan pembaca baru ke pos ini di blog Android Developers sebagai diskusi yang agak lengkap tentang topik tersebut dengan beberapa saran spesifik tentang bagaimana menangani kode Anda saat beralih dari pra-level 11 ke Action Bar baru.

Saya masih percaya itu adalah kesalahan desain yang tidak memiliki tombol menu berperilaku sebagai tombol "Aksi Overflow" yang berlebihan dalam tombol menu yang mengaktifkan perangkat sebagai cara yang lebih baik untuk mentransisikan pengalaman pengguna tetapi air di bawah jembatan pada saat ini.

PaulP
sumber
Saya sepenuhnya setuju dengan Anda tentang kesalahan desain - dan saya merasa frustasi!
Paul Hunnisett
1
Saya setuju dengan Anda tentang ini, jika bukan karena fakta bahwa Google sendiri mulai melanggar aturan itu dalam aplikasi G + baru-baru ini. Dan memang seharusnya begitu. Tombol menu bukan warisan, bahkan perangkat baru seperti SGS3 memilikinya. Itu di sini untuk tinggal, sayangnya. Dan itu benar-benar menghambat kegunaan.
Timo Ohr
4

Saya tidak yakin apakah ini yang Anda cari, tetapi saya membangun Submenu di dalam ActionBar's Menu dan mengatur ikonnya agar sesuai dengan Ikon Menu Overflow. Meskipun tidak akan ada item yang dikirim secara otomatis ke sana, (yaitu Anda harus memilih apa yang selalu terlihat dan apa yang selalu meluap) menurut saya pendekatan ini dapat membantu Anda.

Chris
sumber
2

Di aplikasi gmail yang datang dengan ICS pra-instal, tombol menu dinonaktifkan ketika Anda memiliki beberapa item yang dipilih. Menu overflow di sini "dipaksa" untuk dipicu oleh penggunaan tombol overflow daripada tombol menu fisik. Ada lib pihak ke-3 yang disebut ActionBarSherlock yang memungkinkan Anda "memaksa" menu overflow. Tetapi ini hanya akan bekerja pada API level 14 atau lebih rendah (pra-ICS)

borislemke
sumber
2

Jika Anda menggunakan Bilah Alat , Anda dapat menampilkan overflow pada semua versi dan semua perangkat, saya sudah mencoba beberapa perangkat 2.x, ini berfungsi.

TeeTracker
sumber
1

Maaf jika masalah ini sudah mati.

Inilah yang saya lakukan untuk mengatasi kesalahan. Saya pergi ke tata letak dan membuat dua yang berisi toolbar. Satu adalah tata letak untuk sdk versi 8 dan yang lainnya adalah untuk sdk versi 21. Pada versi 8, saya menggunakan android.support.v7.widget.Toolbar sementara saya menggunakan android.widget.Toolbar pada tata letak sdk 21.

Lalu saya mengembang toolbar di aktivitas saya. Saya memeriksa SDK untuk melihat apakah itu 21 atau lebih tinggi. Saya kemudian mengembang tata letak yang sesuai. Ini memaksa tombol perangkat keras untuk memetakan ke toolbar yang sebenarnya Anda rancang.

Dolandlod
sumber
0

Bagi siapa pun yang menggunakan yang baru 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
sumber