Cách buộc sử dụng menu tràn trên các thiết bị có nút menu


159

Tôi muốn có tất cả các mục trong menu mà không phù hợp với ActionBar đi vào menu tràn (một trong đó là đạt từ Thanh tác vụ không phải là nút menu) thậm chí trên các thiết bị mà làm có một nút Menu . Điều này có vẻ trực quan hơn nhiều đối với người dùng so với việc ném chúng vào một danh sách menu riêng biệt yêu cầu người dùng chuyển từ tương tác cảm ứng (màn hình) sang tương tác dựa trên nút chỉ vì cách bố trí của ActionBar không phù hợp với họ trên thanh.

Trên trình giả lập, tôi có thể đặt giá trị "Back Back / Home Home" thành "không" và có được hiệu ứng này. Tôi đã tìm kiếm một cách để làm điều này trong mã cho một thiết bị thực tế có nút menu nhưng không thể tốt. Ai giúp tôi với?

Câu trả lời:


54

EDIT: Được sửa đổi để trả lời cho tình huống của nút menu vật lý.

Điều này thực sự được ngăn chặn bởi thiết kế. Theo Phần tương thích của Hướng dẫn thiết kế Android ,

"... tràn hành động có sẵn từ phím phần cứng menu. Cửa sổ bật lên hành động kết quả ... được hiển thị ở dưới cùng của màn hình."

Bạn sẽ lưu ý trong ảnh chụp màn hình, điện thoại có nút menu vật lý không có menu tràn trong ActionBar. Điều này tránh sự mơ hồ cho người dùng, về cơ bản có sẵn hai nút để mở cùng một menu.

Để giải quyết vấn đề về tính nhất quán giữa các thiết bị: Cuối cùng, điều quan trọng hơn đối với trải nghiệm người dùng là ứng dụng của bạn hoạt động nhất quán với mọi ứng dụng khác trên cùng một thiết bị, hơn là nó hoạt động nhất quán với tất cả các thiết bị.


1
Alexander - Không, tôi đã thử tất cả các giá trị showAsAction và một số kết hợp và không ai trong số chúng thực hiện thủ thuật (ít nhất là trên trình giả lập). Menu tràn trên thanh hành động chỉ hiển thị nếu tôi mô phỏng thiết bị không có nút menu. Tôi muốn thấy dấu chấm lửng dọc và có các mục tràn ra hiển thị trên đó trên các thiết bị nút menu. Tôi đã chỉnh sửa câu hỏi của mình để làm cho nó rõ ràng hơn một chút.
PaulP

41
Hãy bước vào cuộc trò chuyện này và thảo luận: Tôi biết nó bị ngăn cản bởi thiết kế (tôi đọc hướng dẫn thiết kế). Nhưng đó là loại% $ /% # +, tôi nghĩ vậy. Ví dụ: người dùng đang chuyển từ Galaxy Nexus (-> w Overflow) sang Nexus One (w 4.0 / -> no Overflow). Tôi cá là người dùng sẽ không tìm thấy các mục menu nữa. Vì lý do đó, tôi muốn sử dụng giống nhau cho tất cả các thiết bị. Vì vậy, tôi kết thúc với cùng một vấn đề như paulp. Không có cách giải quyết nào có sẵn?
Sprigg

10
Tôi cũng đọc Hướng dẫn thiết kế đầu tiên. Đối với tôi đây là một lựa chọn tồi trong thiết kế trong gói hỗ trợ. Một chiến lược tốt hơn để chuyển người dùng AWAY từ nút (mục tiêu, phải không?) Sẽ là làm cho nó dư thừa, đưa chức năng lên màn hình cũng như trong nút. Hiện tại, nút này không liệt kê tất cả các lựa chọn menu, chỉ có những lựa chọn không có trên thanh hành động, vì vậy thiết kế này không hỗ trợ chuyển đổi mượt mà sang thanh hành động cũng như không làm gì trước khi thêm một thanh hành động (hiển thị tất cả menu lựa chọn). Tôi nghi ngờ bạn đúng và không có cách giải quyết đơn giản.
PaulP

18
Google đi ngược lại điều này trong các ứng dụng Google + mới của họ. Nó có mục tràn bất kể thiết bị nào .. tuy nhiên họ vẫn ngăn các nhà phát triển làm điều tương tự và lời khuyên chống lại nó, theo hiểu biết của tôi.
Karl

10
Thành thật mà nói, tôi đã thấy quá nhiều người dùng không thử dùng phím cứng để không bao giờ mong đợi. Nếu thiết kế cho biết bất kỳ người dùng nào trên bất kỳ điện thoại nào cũng không nên có chỉ báo trên màn hình rằng các tùy chọn menu tồn tại, thiết kế đó là một thông tin kém.
Lance Nanek

323

Bạn cũng có thể sử dụng bản hack nhỏ này tại đây:

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

Nơi tốt để đặt nó sẽ là onCreate-Method của lớp Ứng dụng của bạn.

Nó sẽ buộc Ứng dụng hiển thị menu tràn. Nút menu vẫn sẽ hoạt động, nhưng nó sẽ mở menu ở góc trên cùng bên phải.

[Chỉnh sửa] Vì nó đã xuất hiện nhiều lần rồi: Bản hack này chỉ hoạt động cho ActionBar gốc được giới thiệu trong Android 3.0, không phải ActionBarSherlock. Cái sau sử dụng logic bên trong của chính nó để quyết định có hiển thị menu tràn hay không. Nếu bạn sử dụng ABS, tất cả các nền tảng <4.0 đều được xử lý bởi ABS và do đó phải tuân theo logic của nó. Bản hack vẫn sẽ hoạt động cho tất cả các thiết bị có Android 4.0 trở lên (bạn có thể bỏ qua Android 3.x một cách an toàn, vì thực sự không có máy tính bảng nào có nút menu).

Tồn tại một ForceOverflow-Theme đặc biệt sẽ buộc menu trong ABS, nhưng rõ ràng nó sẽ bị xóa trong các phiên bản trong tương lai do các biến chứng .


4
Tôi đã xem qua mã nguồn. Kho báu của các tính năng không có giấy tờ :) Chỉ cần đảm bảo rằng bạn có một dự phòng hoàn toàn khả thi cho những thứ như thế.
Timo Ohr

4
Cảm ơn rất nhiều! Điều này thực sự tuyệt vời. Tôi muốn đưa đánh giá, bugreport và chia sẻ các hành động vào tràn, nhưng nó không hiển thị trên Nexus S. Người dùng thậm chí sẽ không nhấp vào nút Menu. Với người dùng tràn, thấy rằng các hành động bổ sung có sẵn.
Yuriy Kulikov

4
@Ewoks Tôi khá muộn khi nhận xét ở đây, nhưng tôi chỉ thử nó với phiên bản ActionBarCompat mới nhất và nó hoạt động.
jacobhyphenated

3
Điều này hoạt động trên Samsung Galaxy S3 và S4, nhưng không phải trên LG G2 (nghi ngờ họ khó mã hóa kiểm tra để hiển thị nút menu tràn)
dvd

18
Xinh đẹp! Nếu Eclipse cung cấp cho bạn 6 loại nhập khác nhau để chọn, Fieldhãy chọn loại này java.lang.reflect.Field;)
Eugene van der Merwe 27/12/13

35

Tôi sử dụng để giải quyết nó bằng cách xác định menu của mình như thế này (cũng với biểu tượng ActionBarSherlock được sử dụng trong ví dụ của tôi):

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

Tôi thừa nhận rằng điều này có thể yêu cầu "quản lý tràn" thủ công trong xml của bạn, nhưng tôi thấy giải pháp này hữu ích.

Bạn cũng có thể buộc thiết bị sử dụng nút CTNH để mở menu tràn, trong hoạt động của bạn:

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
Làm thế nào để sử dụng nút CTNH để mở menu tràn?
bladefury

1
Xem câu trả lời cập nhật của tôi để mở menu tràn bằng nút CTNH. :)
Berťák

11

Nếu bạn đang sử dụng thanh hành động từ thư viện hỗ trợ ( android.support.v7.app.ActionBar), hãy sử dụng như sau:

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

Khi sử dụng thư viện hỗ trợ tôi cũng đã thực hiện điều này và nó hoạt động tốt trên cả thiết bị trước và sau 3.0
cắt lá

7

Loại phương pháp này bị Hệ thống Thiết kế Nhà phát triển Android ngăn chặn, nhưng tôi đã tìm ra cách để vượt qua:

Thêm phần này vào tệp menu XML của bạn:

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

Tiếp theo, tạo một lớp có tên 'AppPickActionProvider' và sao chép mã sau vào nó:

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

sự khác biệt giữa việc sử dụng phương pháp này và chỉ sử dụng một menu con, như được hiển thị ở đây: stackoverflow.com/a/14634780/878126 ?
nhà phát triển Android

5

Vâng, tôi nghĩ rằng Alexander Lucas đã cung cấp câu trả lời đúng (không may) vì vậy tôi đánh dấu nó là câu trả lời "đúng". Câu trả lời thay thế mà tôi thêm vào ở đây chỉ đơn giản là hướng bất kỳ độc giả mới nào đến bài đăng này trong blog Nhà phát triển Android dưới dạng thảo luận khá đầy đủ về chủ đề này với một số đề xuất cụ thể về cách xử lý mã của bạn khi chuyển từ cấp 11 trước đến Action Bar mới.

Tôi vẫn tin rằng đó là một lỗi thiết kế khi không có nút menu hoạt động như nút "Hành động tràn" dự phòng trong nút menu cho phép các thiết bị như một cách tốt hơn để chuyển đổi trải nghiệm người dùng nhưng nước ở dưới cầu vào thời điểm này.


Tôi hoàn toàn đồng ý với bạn về lỗi thiết kế - và đang tìm thấy sự bực bội này!
Paul Hunnisett

1
Tôi đồng ý với bạn về điều này, nếu thực tế là chính Google đã bắt đầu vi phạm quy tắc đó trong ứng dụng G + gần đây. Và đúng như vậy. Nút menu không phải là di sản, ngay cả các thiết bị mới như SGS3 cũng có. Thật không may ở đây, thật không may. Và nó nghiêm trọng cản trở khả năng sử dụng.
Timo Ohr

4

Tôi không chắc đây có phải là thứ bạn đang tìm hay không, nhưng tôi đã tạo một Menu con trong Menu của ActionBar và đặt biểu tượng của nó khớp với Biểu tượng của Menu tràn. Mặc dù nó sẽ không có các mục tự động được gửi đến nó, (IE bạn phải chọn những gì luôn hiển thị và những gì luôn tràn ra) đối với tôi, phương pháp này có thể giúp bạn.


2

Trong ứng dụng gmail đi kèm với cài đặt sẵn ICS, nút menu bị tắt khi bạn có nhiều mục được chọn. Menu tràn ở đây "bắt buộc" phải được kích hoạt bằng cách sử dụng nút tràn thay vì nút menu vật lý. Có một lib của bên thứ 3 được gọi là ActionBarSherlock, cho phép bạn "buộc" menu tràn. Nhưng điều này sẽ chỉ hoạt động trên API cấp 14 trở xuống (tiền ICS)


2

Nếu bạn sử dụng Thanh công cụ , bạn có thể hiển thị tràn trên tất cả các phiên bản và tất cả các thiết bị, tôi đã thử trên một số thiết bị 2.x, nó hoạt động.


1

Xin lỗi nếu vấn đề này đã chết.

Đây là những gì tôi đã làm để giải quyết lỗi. Tôi đã đi đến bố cục và tạo ra hai cái có chứa các thanh công cụ. Một cái là bố cục cho sdk phiên bản 8 và cái kia là cho sdk phiên bản 21. Trên phiên bản 8, tôi đã sử dụng android.support.v7.widget.Toolbar trong khi tôi sử dụng android.widget.Toolbar trên bố cục sdk 21.

Sau đó, tôi thổi phồng thanh công cụ trong hoạt động của tôi. Tôi kiểm tra sdk để xem nó là 21 hoặc cao hơn. Tôi sau đó thổi phồng bố cục tương ứng. Điều này buộc nút phần cứng ánh xạ lên thanh công cụ bạn thực sự thiết kế.


0

Đối với bất cứ ai sử dụng mới 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);
}
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.