15

Tôi đã tìm kiếm rất nhiều trên invalidateOptionsMenu() và tôi biết nó làm gì. Nhưng tôi không thể nghĩ ra bất kỳ ví dụ thực tế nào về cuộc sống mà phương pháp này có thể hữu ích. Ví dụ:Android - Sử dụng đúng invalidateOptionsMenu()

Ví dụ: giả sử chúng tôi muốn thêm MenuItem mới vào ActionBar, chúng tôi chỉ cần lấy Menu từ onCreateOptionsMenu(Menu menu) và sử dụng nó trong bất kỳ thao tác nào của nút.

Bây giờ, câu hỏi thực sự của tôi là chỉ theo cách cách sử dụng invalidateOptionsMenu()?

bool _OtherMenu; 
protected override void OnCreate (Bundle bundle) 
{ 
    _OtherMenu = false; 
    base.OnCreate (bundle); 
    SetContentView (Resource.Layout.Main); 
    Button button = FindViewById<Button> (Resource.Id.myButton); 
    button.Click += delegate 
    { 
     if(_OtherMenu) 
      _OtherMenu = false; 
     else 
      _OtherMenu = true; 

     InvalidateOptionsMenu(); 
    }; 
} 

public override bool OnCreateOptionsMenu (IMenu menu) 
{ 
    var inflater = this.SupportMenuInflater; 
    if(_OtherMenu) 
     inflater.Inflate (Resource.Menu.another_menu, menu); 
    else 
     inflater.Inflate (Resource.Menu.main_activity_menu, menu); 

    return base.OnCreateOptionsMenu (menu); 
} 

Nhấp vào nút và menu khác xuất hiện. Nhấp lại vào nút và menu trước xuất hiện.

P.S. Xin lỗi về cú pháp C#.

+0

minSdkVersion của bạn là gì? – Xcihnegn

+0

Nó hoạt động trên 11+. Tôi là 15. –

+0

Vì vậy, nó nên gọi OnCreateOptionsMenu(), bạn có thể thử chạy gỡ lỗi để đi qua các mã số – Xcihnegn

Trả lời

2

Bạn cần ghi đè phương thức onPrepareOptionsMenu(), viết mã cập nhật của menu tác vụ theo cùng một phương pháp và nếu bạn đang sử dụng phân đoạn, hãy thêm setHasOptionsMenu(true); vào onCreateView().

Hy vọng nó giúp bạn

+0

được, nhưng onPrepareOptionsMenu() chỉ là một phương thức cố định. Bởi cố định tôi có nghĩa là, nó không phải là trường hợp một thời gian onPrepareOptionsMenu() làm một cái gì đó và thời gian khác nó làm cái gì khác. –

+0

Tại sao không? Có điều như điều kiện (nếu có), bạn biết đấy.Bạn có thể làm cho nó làm bất cứ điều gì bạn muốn trong bất kỳ tình huống nào bạn tưởng tượng –

+0

đó là chính xác câu hỏi của tôi. Đây có phải là phương pháp duy nhất để sử dụng phương pháp này không ??? –

44

invalidateOptionsMenu() được sử dụng để nói Android, mà nội dung của menu đã thay đổi, và menu nên được vẽ lại. Ví dụ, bạn bấm vào một nút có thêm một mục trình đơn khác trong thời gian chạy hoặc ẩn nhóm các mục menu. Trong trường hợp này, bạn nên gọi invalidateOptionsMenu() để hệ thống có thể vẽ lại trên giao diện người dùng. Phương pháp này là một tín hiệu cho hệ điều hành để gọi onPrepareOptionsMenu(), nơi bạn thực hiện các thao tác menu cần thiết. Hơn nữa, OnCreateOptionsMenu() được gọi chỉ một lần trong quá trình tạo đoạn (hoạt động), do đó, các thay đổi menu thời gian chạy không thể được xử lý bằng phương pháp này.

Tất cả có thể được tìm thấy trong documentation:

Sau khi hệ thống gọi onCreateOptionsMenu(), nó vẫn giữ được một thể hiện của Menu bạn cư và sẽ không gọi onCreateOptionsMenu() một lần nữa trừ menu không còn giá trị cho một số lý do. Tuy nhiên, bạn nên chỉ sử dụng onCreateOptionsMenu() để tạo trạng thái menu ban đầu và không thực hiện thay đổi trong suốt vòng đời hoạt động.

Nếu bạn muốn sửa đổi menu tùy chọn dựa trên các sự kiện xảy ra trong vòng đời hoạt động, bạn có thể làm như vậy trong phương thức onPrepareOptionsMenu(). Phương thức này chuyển cho bạn đối tượng Menu vì nó hiện đang tồn tại để bạn có thể sửa đổi nó, chẳng hạn như thêm, xóa hoặc vô hiệu hóa các mục. (Những mảnh vỡ cũng cung cấp một callback onPrepareOptionsMenu() .)

On 2.3.x Android và thấp hơn, hệ thống gọi onPrepareOptionsMenu() mỗi lần người dùng mở trình đơn tùy chọn (nhấn nút Menu).

Trên Android 3.0 trở lên, menu tùy chọn được coi là luôn mở là khi mục trình đơn được hiển thị trong thanh tác vụ. Khi sự kiện xảy ra và bạn muốn thực hiện cập nhật menu, bạn phải gọi invalidateOptionsMenu() để yêu cầu hệ thống gọi onPrepareOptionsMenu().

+0

nhưng tôi không phải gọi invalidateOptionsMenu() .Tôi chỉ cần thực hiện menu.add() và hiển thị –

+0

Cần thiết cho các menu động.) 'từ bên ngoài' onCreateOptionsMenu() '? Làm thế nào bạn có thể thực hiện, ví dụ, các mục menu thay đổi khi người dùng cuộn xuống một listview? Bằng cách vô hiệu hóa menu trên cuộn, buộc hoạt động tạo lại nó và kiểm tra một điều kiện nhất định trong' onCreateOptionsMenu() '. Điều này sẽ không hoạt động nếu bạn kiểm tra điều kiện trong' onCreateOptionsMenu() 'mà không làm mất hiệu lực, vì hoạt động sẽ cho rằng menu vẫn là OK. – natario

+0

Tôi không biết cách viết mã ở đây nhưng cho phép xem: OnCreateOptionsMenu (menu IMenu) { _Menu = menu; } Và bạn có tham chiếu đến Menu. Bây giờ làm bất cứ điều gì bạn muốn làm –

0

Chỉnh sửa: Đây là câu trả lời hay hơn cho câu hỏi.

Một sử dụng tốt cho invalidateOptionsMenu() là khi chúng ta có một ListView và Delete All MenuItem vì vậy khi ListView trống chúng ta nên sử dụng invalidateOptionsMenu() để loại bỏ các Delete All MenuItem.

Đây là câu hỏi liên quan đến câu trả lời này: Question.

+0

Nếu bạn có câu hỏi mới, hãy hỏi nó bằng cách nhấp vào nút [Hỏi câu hỏi] (http://stackoverflow.com/questions/ask) . Bao gồm một liên kết đến câu hỏi này nếu nó giúp cung cấp ngữ cảnh. - [Từ đánh giá] (/ review/low-quality-posts/14147349) – sushildlh

+0

Trên thực tế, liên kết này cung cấp ngữ cảnh cho câu trả lời @sushildlh –

0
/** 
* Set a hint for whether this fragment's menu should be visible. This 
* is useful if you know that a fragment has been placed in your view 
* hierarchy so that the user can not currently seen it, so any menu items 
* it has should also not be shown. 
* 
* @param menuVisible The default is true, meaning the fragment's menu will 
* be shown as usual. If false, the user will not see the menu. 
*/ 
public void setMenuVisibility(boolean menuVisible) { 
    if (mMenuVisible != menuVisible) { 
     mMenuVisible = menuVisible; 
     if (mHasMenu && isAdded() && !isHidden()) { 
      mHost.onSupportInvalidateOptionsMenu(); 
     } 
    } 
} 

mẫu đơn XML:

<?xml version="1.0" encoding="utf-8"?> 
<menu xmlns:android="http://schemas.android.com/apk/res/android" 
xmlns:app="http://schemas.android.com/apk/res-auto"> 
<item 
    android:id="@+id/action_edit" 
    android:icon="@drawable/ic_edit" 
    android:title="Edit Task" 
    app:showAsAction="always" /> 

<item 
    android:id="@+id/action_delete" 
    android:icon="@drawable/ic_delete" 
    android:title="Delete Task" 
    app:showAsAction="always" /> 

<item 
    android:id="@+id/action_check" 
    android:icon="@drawable/ic_check" 
    android:title="Check Task" 
    app:showAsAction="always" /> 

<item 
    android:id="@+id/action_uncheck" 
    android:icon="@drawable/ic_undo" 
    android:title="Uncheck Task" 
    app:showAsAction="always" /> 
</menu> 

Mã bên trong một đoạn mẫu:

private boolean isMenuItemChecked; 

@Override 
public void onViewCreated(View view, @Nullable Bundle savedInstanceState) { 
    super.onViewCreated(view, savedInstanceState); 
    setMenuVisibility(false); 
} 

@Override 
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) { 
    inflater.inflate(R.menu.my_menu, menu); 
    super.onCreateOptionsMenu(menu, inflater); 
} 

@Override 
public void onPrepareOptionsMenu(Menu menu) { 
    super.onPrepareOptionsMenu(menu); 
    try { 
     menu.findItem(R.id.action_check).setVisible(!isMenuItemChecked); 
     menu.findItem(R.id.action_uncheck).setVisible(isMenuItemChecked); 
    } 
    catch(Exception e) { 
     Log.e(TAG, "onPrepareOptionsMenu error"); 
    } 
} 

public void loadUi(boolean isMenuItemChecked) { 
    this.isMenuItemChecked = isMenuItemChecked; 
    setMenuVisibility(true); 
} 
12

này sử dụng để tải lại menu mới trong vòng đời ứng dụng:

ActivityCompat.invalidateOptionsMenu(getActivity()); 
+0

trong đó chúng ta gọi vòng đời của Fragment? –

+2

bất kỳ điểm nào trong vòng đời, nhấp, v.v. – itzhar

0

Cách tốt nhất mà làm việc đối với tôi là chứng minh dưới đây

  1. Đặt tình trạng ban đầu của trình đơn trong onCreateOptionsMenu (...)

  2. Sử dụng invalidateOptionsMenu() để buộc onCreateOptionsMenu (.. .) và onPrepareOptionsMenu (...)

  3. Trong onPrepareOptionsMenu (...), hãy gọi menu.clear() để xóa tất cả các mục khỏi menu.

  4. Vẫn trong onPrepareOptionsMenu (...) đặt thay đổi trình đơn động của bạn sau khi rõ ràng

Hope this helps ...

0

Một sử dụng tôi đã tìm thấy là buộc một trật tự hoạt động giữa onResumeonCreateOptionsMenu/onPrepareOptionsMenu. Thứ tự tự nhiên (như của nền tảng 22 ít nhất) dường như lật flop xung quanh, đặc biệt là khi định hướng lại thiết bị của bạn.

Gọi invalidateOptionsMenu() trong onResume() và bạn sẽ đảm bảo rằng onPrepareOptionsMenu sẽ được gọi sau onResume (có thể được gọi thêm trước đó). Ví dụ: điều này sẽ cho phép bật mục menu dựa trên dữ liệu được truy xuất trong onResume.

Các vấn đề liên quan