2011-10-14 10 views
53

Trong các ứng dụng của tôi, tôi thường bật/tắt các mục menu và hiển thị chúng từ onPrepareOptionsMenu.Làm cách nào tôi có thể làm mới ActionBar khi onPrepareOptionsMenu chuyển các mục menu?

Hôm nay tôi bắt đầu thêm thuộc tính menu android: showAsAction vào một số ứng dụng Android 2.x của tôi để hiển thị các mục trình đơn được sử dụng nhiều nhất trên ActionBar.

Thanh tác vụ không phản ánh bật/tắt và hiển thị ngay lập tức. Tôi cần nhấp vào menu thả xuống ở bên phải để xem thay đổi này xảy ra.

Ok, tôi hiểu rằng trình đơn kích hoạt onPrepareOptionsMenu. Nhưng tôi cần phải làm gì để làm mới ActionBar? Tôi nghĩ rằng thay đổi này cần phải được áp dụng từ bên trong onOptionsItemSelected nhưng tôi không biết những gì tôi nên gọi.

Dưới đây là menu:

<item 
    android:icon="@drawable/ic_menu_mapmode" 
    android:id="@+id/men_mapview" 
    android:showAsAction="ifRoom|withText" 
    android:title="@string/txt_mapview" /> 

<item 
    android:icon="@drawable/ic_menu_mapmode" 
    android:id="@+id/men_satelliteview" 
    android:showAsAction="ifRoom|withText" 
    android:title="@string/txt_satelliteview" /> 

Đây là onPrepareOptionsMenu:

@Override 
public boolean onPrepareOptionsMenu(final Menu menu) { 
    MenuItem menuItemMapView = menu.findItem(R.id.men_mapview); 
    MenuItem menuItemSatelliteView = menu.findItem(R.id.men_satelliteview); 

    if (mapView.isSatellite()) { 
     menuItemMapView.setEnabled(true).setVisible(true); 
     menuItemmenuItemSatelliteView.setEnabled(false).setVisible(false); 
    } else { 
     menuItemMapView.setEnabled(false).setVisible(false); 
     menuItemmenuItemSatelliteView.setEnabled(true).setVisible(true); 
    } 

    return super.onPrepareOptionsMenu(menu); 
} 

Đây là onOptionsItemSelected

@Override 
public boolean onOptionsItemSelected(final MenuItem menuItem) { 
    switch (menuItem.getItemId()) { 
     case R.id.men_mapview: 
      mapView.setSatellite(false); 
      mapView.setStreetView(true); 
      mapView.invalidate(); 

      invalidateOptionsMenu(); // This works on Android 3.x devices only 
      return true; 
     case R.id.men_satelliteview: 
      mapView.setSatellite(true); 
      mapView.setStreetView(false); 
      mapView.invalidate(); 

      invalidateOptionsMenu(); // This works on Android 3.x devices only 
      return true; 
    } 

    return super.onOptionsItemSelected(menuItem); 
} 

EDIT: Nếu tôi thêm invalidateOptionsMenu này hoạt động trên Android 3. x ứng dụng nhưng gặp sự cố Thiết bị Android 2.x do phương pháp bị thiếu. Cách được khuyến nghị để làm điều đó là đúng?

Trả lời

77

Phương pháp lựa chọn của tôi là tạo lớp trợ giúp. Ví dụ:

class VersionHelper 
{ 
    static void refreshActionBarMenu(Activity activity) 
    { 
     activity.invalidateOptionsMenu(); 
    } 
} 

Bây giờ trong mã của bạn ở trên, thay thế invalidateOptionsMenu(); với:

if (Build.VERSION.SDK_INT >= 11) 
{ 
    VersionHelper.refreshActionBarMenu(this); 
} 

tín dụng cho phương pháp này đi vào CommonsWare (tìm kiếm HoneycombHelper, và kiểm tra cuốn sách của ông - rất khuyến khích)

+5

các differnece giữa câu trả lời của bạn là gì và chỉ cần đặt phiên bản chec k xung quanh cuộc gọi ban đầu của anh ta nếu (Build.VERSION.SDK_INT> = 11) {invalidateOptionsMenu(); }? bạn có thể kiểm tra phiên bản trong cuộc gọi phương thức versionHelper không? – topwik

+9

@towpse Lý do anh ta có lớp trợ giúp có cấu trúc vì nó là để tránh một vụ tai nạn do khả năng tương thích không ngược. Phương thức 'invalidateOptionsMenu()' chỉ tồn tại trong API 11 (tổ ong) và lên. Vì vậy, nếu ứng dụng của bạn chạy trên bất kỳ thứ gì thấp hơn API 11 thì ứng dụng đó sẽ gặp sự cố. Để tránh điều này, bạn quấn phương thức được đề cập đến trong một phương thức ** static ** khác (ví dụ 'refreshActionBarMenu()') và ** only ** gọi phương thức tĩnh này nếu bạn đang chạy trên API> 11 (do đó kiểm tra phiên bản _before_) bạn gọi phương thức tĩnh).Điều này làm việc vì lớp 'VersionHelper' không được nạp cho đến khi bạn thực sự sử dụng nó. –

+0

@Turbo ok tuyệt vời, cảm ơn vì lời giải thích, vậy bạn sẽ làm gì trong trường hợp khác? không cập nhật trình đơn ở tất cả hoặc cách cũ hơn để thực hiện cập nhật mục menu nếu người dùng đang chạy hệ điều hành cũ hơn là gì? – topwik

10

lưu tham chiếu đến menu và gọi:

this.menu.clear(); 
this.onCreateOptionsMenu(this.menu); 
+3

Đây là câu trả lời đúng cho cách chuyển đổi chương trình hiển thị các mục menu tùy chọn trong thanh tác vụ trên thiết bị trước API 11. –

3

Bas ed trên "Klaasvaak" câu trả lời ở trên. Tôi đang sử dụng subMenus của nó. Này làm việc cho tôi:

// Declare and save the menu as global, so it can be called anywhere. 
Menu absTopSubMenus; 

public boolean onCreateOptionsMenu(Menu menu) { 

absTopSubMenus = menu; // Used for re-drawing this menu anywhere in the codes. 

// The remainder of your code below 
} 

Sau đó, để lại vẽ này, chỉ cần gọi:

// Redraw the top sub-menu 
absTopSubMenus.clear(); 
onCreateOptionsMenu(absTopSubMenus); 
3

Tôi không chắc chắn bạn đã nhìn thấy nó đã có, nhưng nếu bạn sử dụng actionbar rộng rãi, và kế hoạch hỗ trợ API thấp hơn (> 8), hãy xem thư viện actionBarSherlock. Nó sẽ làm cho nó, do đó bạn không cần phải phần mã actionBar của bạn cho thấp hơn và cao hơn của API, và sau đó bạn chỉ có thể chạy:

runOnUiThread(new Runnable(){ 
    @Override 
    public void run(){ 
    supportInvalidateOptionsMenu(); 
    } 
}); 
+0

tùy chọn tốt nhất của nó. –

1

Kudos để @Klaasvaak cho thấy chúng ta con đường ở đây.Tôi sử dụng sau đó hoạt động trên cả trước và hậu API Cấp 11:

private void invalidOptionsMenuHelper() { 
    if (Build.VERSION.SDK_INT >= 11) { 
     invalidateOptionsMenu(); 

    } else if (mOptionsMenu != null) { 
     mOptionsMenu.clear(); 
     onCreateOptionsMenu(mOptionsMenu); 
    } 
} 

Tất nhiên, bạn phải lưu một tham chiếu đến menu (mOptionsMenu trong trường hợp này) mà tôi thực hiện thông qua:

@Override 
public boolean onCreateOptionsMenu(Menu menu) { 
    mOptionsMenu = menu; 

    //... create and manage the menu normally 
} 
14

Sử dụng

ActivityCompat.invalidateOptionsMenu(Activity activity) 

từ compatibility library.

Xem: https://stackoverflow.com/a/14748687/435855

+0

Trên Gingerbread, onCreateOptionsMenu() không được gọi sau khi gọi phương thức này. – lemuel

+1

Có. Đó là bởi vì preHoneycomb không hỗ trợ trên các nút màn hình và một nút menu phần cứng được mong đợi. Vì vậy, phương thức onCreateOptionMenu() được gọi khi người dùng nhấn nút menu. invalidateOptionsMenu tập trung vào việc làm mới thanh tác vụ 3.0+ hỗ trợ nút phần cứng menu cũ. – Urizev

62

Nhờ câu trả lời được chấp nhận. Tôi đang sử dụng ActionBarActivity. trong lớp học này, bạn có thể sử dụng

supportInvalidateOptionsMenu(); 
+3

Cho người đàn ông này một cookie .... Lý do tại sao tôi không thể đặt khả năng hiển thị của trình đơn thành sai là tôi chỉ sử dụng invalidateOptionsMenu(); cho đến khi tôi tìm thấy câu trả lời của bạn. Cảm ơn anh bạn. – Cjames

+4

Đây phải là câu trả lời đã chọn. – Guy

+0

Vì các biểu tượng (biểu tượng) trong Thanh công cụ được hiển thị bên trong bằng TextView thay vì ImageView (và tôi hiểu tại sao), tôi phải tự tay vẽ lại các đối tượng ghép bên trong TextView, và bổ sung thêm một TouchListener sẽ đổi màu chúng khi nhấn/kích hoạt. Vì vậy, về cơ bản tôi chỉ tô màu các biểu tượng. Bất cứ ai có tình huống tương tự? Việc vô hiệu hóa menu không hoạt động đối với tôi .. – milosmns

4

Bây giờ bạn có thể sử dụng phương thức supportInvalidateOptionsMenu() từ ActionbarActivity với thư viện hỗ trợ. Vì vậy, bạn không cần phải kiểm tra phiên bản của sdk. Chuyển đến API 7 trở lên.

http://developer.android.com/reference/android/support/v7/app/ActionBarActivity.html

làm để như vậy, bạn cần phải nhập v7 của thư viện hỗ trợ sử dụng này

http://developer.android.com/tools/support-library/setup.html

2

getActivity() invalidateOptionsMenu().

hoàn thành công việc.

0

Cũng chắc chắn rằng bạn không gọi

myAppCompatActivity.setToolbarTitle("some dynamic title"); 

ngay sau khi bạn đã làm mới thực đơn của bạn.

Tôi đã gặp sự cố rằng bản vẽ sẽ không hiển thị ngay cả khi có chỗ cho chúng được hiển thị. Một khi tôi đã làm một định hướng thay đổi drawables sau đó xuất hiện ..?

Trong Tóm tắt:

MainActivity:

public class MainActivity extends AppCompatActivity { 

    private boolean showMenu = true; 

    public void setShowMenu(boolean show) { 
     showMenu = show; 
     supportInvalidateOptionsMenu(); 
    } 

    @Override 
    public boolean onCreateOptionsMenu(Menu menu) { 
     getMenuInflater().inflate(R.menu.my_menu, menu); 
     menu.findItem(R.id.menu_share).setVisible(showMenu); 
     // menu.findItem(... 
     return true; 
    } 
} 

FragmentNoMenu:

public abstract class FragmentNoMenu extends Fragment { 

    protected MainActivity mainActivity; 

    @Override 
    public void onCreate(Bundle savedInstanceState) { 
     super.onCreate(savedInstanceState); 
     setHasOptionsMenu(true); 
     mainActivity = (MainActivity) getActivity(); 
     if (mainActivity != null) { 
      mainActivity.setShowMenu(false); 
     } 
    } 

} 

FragmentWithMenu:

public abstract class FragmentWithMenu extends Fragment { 

    protected MainActivity mainActivity; 

    @Override 
    public void onCreate(Bundle savedInstanceState) { 
     super.onCreate(savedInstanceState); 
     setHasOptionsMenu(true); 
     mainActivity = (MainActivity) getActivity(); 
     if (mainActivity != null) { 
      mainActivity.setShowMenu(true); 
     } 
    } 

}