Làm cách nào để cập nhật một mục menu được hiển thị trong Thanh tác vụ?


93

Tôi có một Hoạt động có 2 phân đoạn. Cả hai đều là ListFragment và cả hai đều đóng góp MenuItems vào Menu. Tôi có một MenuItem mà tôi đã đặt thuộc tính android: showAsAction để nó hiển thị dưới dạng một nút trên ActionBar. Mà hoạt động tốt.

Bây giờ MenuItem phụ thuộc vào trạng thái. Đó là tùy chọn menu Tạm dừng / Tiếp tục để tạm dừng và tiếp tục hàng đợi. Vấn đề của tôi là tôi không thể tìm ra cách đặt bức tượng ban đầu của nó khi Fragment được tạo.

Trạng thái của nó phụ thuộc vào việc hàng đợi có bị tạm dừng hay không. Vì vậy, tôi có một AsyncTask nhận hàng đợi và đặt boolean (tạm dừng) dựa trên trạng thái của hàng đợi. Tôi đang gọi onPrepareOptionsMenu để đặt văn bản cho mục menu Tạm dừng dựa trên trạng thái cuối cùng đã biết của hàng đợi và điều này hoạt động tốt nếu tôi để MenuItem trong menu thực tế. Bạn nhấn vào biểu tượng menu và onPrepareOptionsMenu được kích hoạt và menu được cập nhật trước khi hiển thị.

Vấn đề là, nếu tôi đặt cùng một MenuItem đó trên ActionBar (showAsAction), làm thế nào tôi có thể buộc nó cập nhật mà không cần phải gọi onPrepareOptionsMenu? Tôi cần có thể thực hiện việc này bởi vì trong lần khởi chạy ứng dụng đầu tiên, tôi gửi yêu cầu nhận hàng đợi, nhưng tác vụ sẽ trả lại sau khi ActionBar được thiết lập và hiển thị. Tôi đã tạo một trình xử lý trong phân đoạn của mình được gọi mỗi khi tôi nhận được bản cập nhật hàng đợi, nhưng từ đó, làm cách nào để cập nhật văn bản cho MenuItem của tôi trên ActionBar? Tôi dường như không thể tìm ra cách để có được Menu hiện đang đặt để thao tác nó ngoại trừ trong onPrepareOptionMenu.

Rob W.

Câu trả lời:


174

Tùy chọn số 1: Thử invalidateOptionsMenu(). Tôi không biết liệu điều này có buộc phải vẽ lại thanh tác vụ ngay lập tức hay không.

Tùy chọn # 2: Xem liệu có getActionView()trả lại bất kỳ thứ gì cho người bị ảnh hưởng không MenuItem. Có thể showAsActionchỉ đơn giản là tự động tạo chế độ xem hành động cho bạn. Nếu vậy, bạn có thể bật / tắt nó View.

Tôi dường như không thể tìm ra cách để có được Menu hiện đang đặt để thao tác nó ngoại trừ trong onPrepareOptionMenu.

Bạn có thể bám vào Menuđồ vật mà bạn đã được giao onCreateOptionsMenu(). Trích dẫn tài liệu :

Bạn có thể giữ một cách an toàn menu (và bất kỳ mục nào được tạo từ nó), thực hiện sửa đổi nó như mong muốn, cho đến khi lần tiếp theo onCreateOptionsMenu () được gọi.


2
Đã thử Tùy chọn số 1 và điều này đã thành công. Vì tôi đang cố gắng cập nhật giao diện người dùng trong một cuộc gọi lại từ một chuỗi riêng biệt, nó đã ném ra một ngoại lệ vì tôi thực sự không ở trên chuỗi giao diện người dùng. Để khắc phục điều này, tôi đã tạo một Trình xử lý và gửi thông báo làm mới tới trình xử lý khi cuộc gọi lại của tôi được gọi. Nhưng cuối cùng tôi đã sử dụng getActivity (). InvalidateOptionsMenu () để làm mới menu.
brockoli

@brockoli: Ah, tốt! Với cách viết của Javadocs cho phương pháp đó, tôi đã nghi ngờ rằng nó sẽ mang lại hiệu quả mong muốn, mặc dù có vẻ như đó là lý do họ thêm nó vào API Cấp 11 ngay từ đầu. Rất vui khi biết nó có hiệu quả với bạn!
CommonsWare

Tôi đã đập đầu vào tường để cố gắng tìm ra điều này và nó hoạt động như một sự quyến rũ!
MinceMan

7
Nếu bạn đang sử dụng các thư viện hỗ trợ, sử dụng supportInvalidateOptionsMenu()thay vì
Tim Kist

2
@TimKist, supportInvalidateOptionsMenu()hiện không được dùng nữa; bạn có thể yên tâm sử dụng invalidateOptionsMenu().
Primož Kralj

12

trong trường hợp của tôi: invalidateOptionsMenuchỉ cần đặt lại văn bản thành văn bản ban đầu, nhưng truy cập trực tiếp vào mục menu và viết lại văn bản mong muốn đã hoạt động mà không có vấn đề gì:

if (mnuTopMenuActionBar_ != null) {
    MenuItem mnuPageIndex = mnuTopMenuActionBar_
        .findItem(R.id.menu_magazin_pageOfPage_text);

    if (mnuPageIndex != null) {
        if (getScreenOrientation() == 1) {
            mnuPageIndex.setTitle((i + 1) + " von " + pages);
        }
        else {
            mnuPageIndex.setTitle(
                (i + 1) + " + " + (i + 2) + " " + " von " + pages);
        }
        // invalidateOptionsMenu();
    }
}

do nhận xét bên dưới, tôi đã có thể truy cập mục menu thông qua mã sau:

@Override
public boolean onCreateOptionsMenu(Menu menu) {
    MenuInflater inflater = getMenuInflater();
    inflater.inflate(R.menu.magazine_swipe_activity, menu);
    mnuTopMenuActionBar_ = menu;
    return true;
}

Làm thế nào bạn có được một xử lý cho dạng xem ActionBar với mnuTopMenuActionBar_?
Paul Mennega

1
khi thanh tác vụ được khởi tạo, tôi đã lưu chế độ xem vào một biến thành viên ... như thế này: @Override public boolean onCreateOptionsMenu (Menu menu) {MenuInflater Inflater = getMenuInflater (); Inflater.inflate (R.menu.magazine_swipe_activity, menu); mnuTopMenuActionBar_ = menu; trả về true; }
cV2

Bằng cách đó, bạn có thể gặp sự cố đồng bộ hóa phải không? Ý tôi là. bạn không biết CHÍNH XÁC khi nào onCreateOptionMenu sẽ chạy, vì vậy bạn có thể tiếp cận đoạn mã của mình khi mnuTopMenuActionBar_chưa khởi tạo, phải không? Bạn sẽ giải quyết vấn đề đó như thế nào?
acrespo

hey, nếu actionbar được sử dụng (có, ở đây nó là) phương pháp này được gọi là luôn luôn, vì vậy không có vấn đề với điều đó ... (trực tiếp tại bắt đầu hoạt động) stackoverflow.com/questions/7705927/...
CV2

11

Để làm mới menu từ Fragment, chỉ cần gọi:

getActivity().invalidateOptionsMenu();

4

Tôi đã sử dụng mã này:

public boolean onPrepareOptionsMenu (Menu menu) {       
    MenuInflater inflater = getMenuInflater();
    TextView title  = (TextView) findViewById(R.id.title);
    menu.getItem(0).setTitle(
        getString(R.string.payFor) + " " + title.getText().toString());
    menu.getItem(1).setTitle(getString(R.string.payFor) + "...");
    return true;        
}

Và làm việc như một cái duyên với tôi, bạn có thể tìm thấy OnPrepareOptionsMenu tại đây


4
Mục đích của MenuInflater ở đây là gì?
IgorGanapolsky

Điều này thật tuyệt vời
Steve Kamau

2

Trước tiên, hãy làm theo hai dòng mã để cập nhật các mục trên thanh tác vụ trước đó bạn nên đặt một điều kiện trong oncreateOptionMenu (). Ví dụ:

Boolean mISQuizItemSelected = false;

/**
 * Called to inflate the action bar menus
 *
 * @param menu
 *      the menu
 *
 * @return true, if successful
 */

@Override
public boolean onCreateOptionsMenu(Menu menu) {

    // Inflate the menu items for use in the action bar

    inflater.inflate(R.menu.menu_demo, menu);

    //condition to hide the menus
    if (mISQuizItemSelected) {
        for (int i = 0; i < menu.size(); i++) {
            menu.getItem(i).setVisible(false);
        }
    }

    return super.onCreateOptionsMenu(menu);
}

/**
 * Called when the item on the action bar being selected.
 *
 * @param item
 *      menuitem being selected
 *
 * @return true if the menuitem id being selected is matched
 * false if none of the menuitems id are matched
 */
@Override
public boolean onOptionsItemSelected(MenuItem item) {
    if (item.getId() == R.id.action_quiz) {
        //to navigate based on the usertype either learner or leo
        mISQuizItemSelected = true;

        ActionBar actionBar = getActionBar();
        invalidateOptionMenu();
    }
}

1

Để rõ ràng hơn, tôi nghĩ rằng một ví dụ trực tiếp về việc nắm bắt một tài nguyên có thể được hiển thị từ sau đây mà tôi nghĩ sẽ góp phần vào câu trả lời cho câu hỏi này bằng một ví dụ trực tiếp nhanh chóng.

private MenuItem menuItem_;

@Override
public boolean onCreateOptionsMenu(Menu menuF) 
{
    MenuInflater inflater = getMenuInflater();
    inflater.inflate(R.menu.menu_layout, menuF);
    menuItem_ = menuF.findItem(R.id.menu_item_identifier);
    return true;
}

Trong trường hợp này, bạn giữ một tham chiếu MenuItem lúc đầu và sau đó thay đổi trạng thái của nó (ví dụ: thay đổi trạng thái biểu tượng) tại một thời điểm nhất định sau đó.


-1

Trong Kotlin 1.2 chỉ cần gọi:

invalidateOptionsMenu()

onCreateOptionsMenuhàm sẽ được gọi lại.

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.