快顯功能表是停靠在一個View上的一個模式菜單。如果View對象下方有空間,那麼快顯功能表將顯示在停靠對象的下方,否則會顯示在上方。這是非常有用的:
1. 給指定內容的操作提供一個溢出式菜單(4所示的Gmail的郵件標頭)。
圖4. Gmail應用中的一個快顯功能表,停靠於右上方的溢出按鈕。
注意:這是跟操作功能表不一樣,操作功能表是對選擇內容有影響的操作。針對應用選擇內容的操作,請使用上下文操作模式或浮動內容菜單。
2. 提供命令語句的第二部分(如一個標記為“Add”按鈕,用快顯功能表來產生不同的“Add”選項)。
3. 提供一個不保留持久選擇的類似Spinner組件的下拉式功能表。
注意:快顯功能表是在API 層級 11和更高版本上才有效。
如果你在XML中定義了你的菜單,以下是如何顯示快顯功能表的方法:
1. 用它的構造器執行個體化一個PopupMenu對象,它需要當前應用程式的Context和菜單要停靠的那個View兩個對象作為參數。
2. 使用MenuInflater對象把你的菜單資源裝載到由PopupMenu.getMenu()方法返回的Menu對象中。在API 層級 14以上的版本,你能夠使用PopupMenu.inflate()方法來替代。
3. 調用PopupMenu.show()方法來顯示快顯功能表。
例如,下列是一個帶有android:onClick屬性的按鈕顯示快顯功能表的方法:
資訊清單檔中的定義:
<ImageButton
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@drawable/ic_overflow_holo_dark"
android:contentDescription="@string/descr_overflow_button"
android:onClick="showPopup" />
Activity中的代碼:
public void showPopup(View v) {
PopupMenu popup = new PopupMenu(this, v);
MenuInflater inflater = popup.getMenuInflater();
inflater.inflate(R.menu.actions, popup.getMenu());
popup.show();
}
在API 層級 14和更高的版本上,你能夠用PopupMenu.inflate()方法把填充菜單的兩個代碼合并到一起。
當使用者選擇了一個功能表項目或在觸摸了菜單地區的外部,這個菜單就會消失。你能使用PopupMenu.OnDismissListener回調方法來監聽菜單消失事件。
處理點擊事件
當使用者選擇一個功能表項目來執行一個操作時,你必須要實現PopupMenu.OnMenuItemClickListener介面並且通過調用setOnMenuItemClickListener()方法把它註冊給你的PopupMenu對象。當使用者選擇一個項目是,系統會調用你的介面中的onMenuItemClick()回調方法。如:
public void showMenu(View v) {
PopupMenu popup = new PopupMenu(this, v);
// This activity implements OnMenuItemClickListener
popup.setOnMenuItemClickListener(this);
popup.inflate(R.menu.actions);
popup.show();
}
@Override
public boolean onMenuItemClick(MenuItem item) {
switch (item.getItemId()) {
case R.id.archive:
archive(item);
return true;
case R.id.delete:
delete(item);
return true;
default:
return false;
}
}
建立菜單組
菜單組是共用某些特性的功能表項目的集合,使用菜單組,可以做以下事情:
1. 用setGroupVisible()方法顯示或隱藏組內的所有功能表項目;
2. 用setGroupEnabled()方法啟用或禁用組內的所有功能表項目;
3. 用setGroupCheckable()方法指定所有組內項目是否可複選。
你能夠通過把菜單資源中<item>元素嵌套進<group>元素中來建立分組菜單,或者使用帶有分組ID的add()方法。
以下是包含了一個分組的菜單資源
<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android">
<item android:id="@+id/menu_save"
android:icon="@drawable/menu_save"
android:title="@string/menu_save" />
<!-- menu group -->
<group android:id="@+id/group_delete">
<item android:id="@+id/menu_archive"
android:title="@string/menu_archive" />
<item android:id="@+id/menu_delete"
android:title="@string/menu_delete" />
</group>
</menu>
這個分組菜單中的項目與第一個項目顯示在同一個層次層級上---菜單中的三個項目是同級的,你能夠使用上面列出的方法,通過引用組ID來修改分組菜單中兩個項目的屬性。系統也不會把分組的功能表項目給分開。如,如果你給每個功能表項目聲明了android:showAsAction=”ifRoom”屬性,那麼它們將既可以同時顯示在操作欄中,也可以同時顯示在操作溢出中。
使用可複選的功能表項目
菜單能夠用於切換選項的介面,針對一個獨立的選項使用一個可複選的Checkbox菜單,對於一組互斥的選項可使用一組帶有選項按鈕的菜單(5所示)。
圖5.帶有複選功能表項目的子功能表。
注意:表徵圖菜單(選項類型的菜單)中的功能表項目不能顯示一個複選框或選項按鈕。如果你選擇了讓表徵圖菜單中的功能表項目可複選,那麼就必須在每次狀態改變時通過更換手動的更換表徵圖或文本來的指明複選的狀態。
你能夠使用<item>元素中的android:checkable屬性給單獨的功能表項目定義可複選的行為,或者用<group>元素中的android:checkableBehavior屬性給一組功能表項目定義可複選行為。如,下例中菜單組中的每個功能表項目都帶有一個可複選的複選按鈕:
<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android">
<group android:checkableBehavior="single">
<item android:id="@+id/red"
android:title="@string/red" />
<item android:id="@+id/blue"
android:title="@string/blue" />
</group>
</menu>
android:checkableBehavior屬性可以有以下三種設定:
1. single:菜單組中僅有一個菜單能夠被複選(複選按鈕)
2. all:所有功能表項目都能夠被複選(複選框)
3. none:沒有項目是可複選的
你能夠在<item>元素中使用android:checked屬性給一個功能表項目設定預設的複選狀態,並且可以用setChecked()方法在代碼中改變它。
當一個可複選的功能表項目被選擇的時候,系統會調用對應被選擇的功能表項目的回調方法(如onOptionsItemSelected())。你必須在這時設定複選框的狀態,因為複選框或複選按鈕不會自動的改變它們的狀態。你能夠用isChecked()方法來查詢複選菜單的目前狀態(被使用者選擇之前的狀態),然後用setChecked()方法設定複選狀態。如:
@Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case R.id.vibrate:
case R.id.dont_vibrate:
if (item.isChecked()) item.setChecked(false);
else item.setChecked(true);
return true;
default:
return super.onOptionsItemSelected(item);
}
}
如果不用這種方式設定複選狀態,那麼當使用者選擇功能表項目(複選框或複選按鈕)的時候,它的可視狀態將不會發生改變。在你設定這個狀態時,Activity會保留菜單的狀態,以便使用者隨後開啟這個菜單時,讓你設定的複選狀態可見。
注意:可複選功能表項目打算僅在每個會話的基礎上使用,並且在應用銷毀之後不儲存複選狀態。如果你的應用打算儲存使用者的設定,你應該使用共用的方式來儲存資料。
基於Intent對象來添加功能表項目
有些時候,你想要功能表項目使用一個Intent對象來啟動一個Activity(不管這個Activity是你的應用程式中的還是其他應用程式中的)。
當你知道你要使用的Intent對象,並且也指定了啟動這個Intent對象的功能表項目時,你就能夠在對應的on-item-selected回調方法(如onOptionsItemSelected()回調方法)調用期間用startActivity()方法執行這個Intent對象。
但是,如果你不確定使用者裝置上是否包含了處理這個Intent對象的應用程式,那麼添加調用這個Intent對象的功能表項目就有可能導致一個非功能性菜單的產生,因為可能沒有接受這個Intent對象的Activity。要解決這個問題,Android能夠讓你在裝置上尋找處理你的Intent對象的Activity時,動態把功能表項目添加到菜單中。
以下是在能夠接受Intent對象的有效Activity基礎上來添加功能表項目的方法:
1. 用CATEGORY_ALTERNATIVE或CATEGORY_SELECTED_ALTERNATIVE分類,再加上一些其他的要求,定義一個Intent對象。
2. 調用Menu.addIntentOptions()方法,Android會搜尋系統中能夠接受這個Intent對象的任何應用程式,並把它們添加到你的菜單中。
如果沒有安裝能夠滿足Intent要求的應用程式,那麼就不會添加功能表項目。
注意:CATEGORY_SELECTED_ALTERNATIVE被用於處理螢幕上當前被選擇的元素。因此,應該只在用onCreateContextMenu()方法建立菜單時使用這個分類。
如:
@Override
public boolean onCreateOptionsMenu(Menu menu){
super.onCreateOptionsMenu(menu);
// Create an Intent that describes the requirements to fulfill, to be included
// in our menu. The offering app must include a category value of Intent.CATEGORY_ALTERNATIVE.
Intent intent = new Intent(null, dataUri);
intent.addCategory(Intent.CATEGORY_ALTERNATIVE);
// Search and populate the menu with acceptable offering applications.
menu.addIntentOptions(
R.id.intent_group, // Menu group to which new items will be added
0, // Unique item ID (none)
0, // Order for the items (none)
this.getComponentName(), // The current activity name
null, // Specific items to place first (none)
intent, // Intent created above that describes our requirements
0, // Additional flags to control items (none)
null); // Array of MenuItems that correlate to specific items (none)
return true;
}
對於找到的每個提供了跟定義的Intent對象匹配的Intent過濾器的Activity,都會添加一個功能表項目,這個功能表項目使用Intent過濾器的android:label的屬性值做為功能表項目的標題、應用程式的表徵圖做為功能表項目的表徵圖。addIntentOptions()方法返回被添加的菜單的個數。
注意:當你調用addIntentOptions()方法時,它會覆蓋在第一個參數中指定的菜單組的所有功能表項目。
允許你的Activity被添加給其他菜單
你也能夠包Activity的服務提供給其他的應用程式,以便你的應用能夠包含在其他應用的菜單中。
要想在其他的應用程式菜單中包含你的應用程式,你需要向通常那樣定義一個Intent過濾器,但要確認包括CATEGORY_ALTERNATIVE或CATEGORY_SELECTED_ALTERNATIVE分類,如:
<intent-filter label="@string/resize_image">
...
<category android:name="android.intent.category.ALTERNATIVE" />
<category android:name="android.intent.category.SELECTED_ALTERNATIVE" />
...
</intent-filter>