在很多類型的應用程式中,菜單是一個常用的使用者介面組件。要提供友好的和前後一致的使用者體驗,就應該使用Menu APIs把Activity的動作和其他選項展現給使用者。
從Android3.0(API 層級 11)開始,Android裝置不再需要提供一個專用的Menu按鈕,隨著這種改變,Android應用程式將會從對傳統的6項菜單面板的依賴中解脫出來,取而代之的是提供了一個使用者展現常用使用者動作的操作欄。
儘管針對一些功能表項目的設計和使用者體驗已經改變,但是定義一組動作和選項的語意依然是基於Menu APIs的。本指南展示了如何建立能夠在Android所有版本上示範的三種基本類型的菜單和動作。
選項菜單和操作欄
選項菜單(options menu)是針對Activity的主要菜單集合。它是你放置應用程式中有全域影響的動作的地方,如“搜尋”、“編寫電子郵件”、和“設定”等功能。
如果你針對Android2.3或更低的版本來開發應用,那麼使用者要通過按Menu按鈕來展現選項菜單面板。
在Android3.0或更高版本上,源於選項菜單的項目是通過操作欄(action bar)來展現的,它由螢幕上的動作項目和剩餘的選項組合而成。從Android3.0開始,Menu按鈕被棄用了(有些裝置根本就沒有這個按鈕),因此,你應該使用操作欄來提供對動作和其他選項的訪問。
上下菜單和上下文操作模式
一個操作功能表是一個當使用者在一個元素上執行long-click事件時才顯示的浮動菜單。它提供了影響選擇內容或上下文架構的動作。
當給Android3.0和更高的版本開發應用程式時,你應該改用上下文動作模式(contextual action mode)來確保被選內容的動作。這種模式把影響選擇內容的動作項目顯示在螢幕頂部的一個橫條中,並允許使用者選擇多重專案。
快顯功能表
一個快顯功能表在一個垂直列表中顯示項目的列表,它靠在調用這個菜單的View對象旁邊。它對給相關指定內容提供動作的展現或給一個命令的第二部分提供選項是有好處的。快顯功能表中的動作不應該直接影響對應的內容,相反,快顯功能表是為了擴充Activity中相關內容地區的動作而設計的。
在XML中定義一個菜單
對於所有的菜單類型,Android提供了標準的XML格式來定義功能表項目。你應該在一個XML菜單資源中定義一個菜單和它的所有的項目,而不是在你Activity代碼中建立一個菜單。然後你就能夠把菜單資源作為一個Menu對象載入到Activity或Fragment對象中。
由於以下原因,使得使用菜單資源是一個好的選擇:
1. 更容易看清XML檔案中的菜單結構;
2. 它把針對菜單的內容和應用程式的行為代碼給分離開了;
3. 它允許你針對不同的平台版本、螢幕尺寸和其他的被應用資源架構利用的配置來建立可選的菜單配置。
要定義菜單,就要在你的項目內部的res/menu/目錄內部建立一個XML檔案,並且要使用下列元素來構建菜單:
<menu>
定義一個菜單,它包含功能表項目。<menu>元素必須是這個檔案的根節點,並且能夠擁有多個<item>和<group>元素。
<item>
建立一個MenuItem對象,它代表了一個菜單中的單獨項目。為了建立一個子功能表,這個元素可以包含一個嵌套的<menu>元素。
<group>
一個可選的針對<item>元素的非可見容器。它允許把功能表項目分類,以便它們共用諸如活動狀態和可見度等屬性。
以下是一個名叫game_menu.xml的菜單:
<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android">
<item android:id="@+id/new_game"
android:icon="@drawable/ic_new_game"
android:title="@string/new_game"
android:showAsAction="ifRoom"/>
<item android:id="@+id/help"
android:icon="@drawable/ic_help"
android:title="@string/help" />
</menu>
<item>元素支援以下幾個用於定義功能表項目的外觀和行為的屬性:
android:id
功能表項目的唯一資源ID,在使用者選擇這個功能表項目時,應用程式能夠用這個ID來識別它。
android:icon
指向一個可描畫的資源,用作這個功能表項目的表徵圖。
android:title
指向一個用作功能表標題的字串。
android:showAsAction
指明這個功能表項目作為操作欄(action bar)中的一個動作項應該顯示的時機和方式。
以上只是你應該使用的最重要的屬性,但是還有一些有效屬性。有關菜單支援的所有屬性資訊,請看“菜單資源”的文檔。
你能夠給菜單中的任意一個項目(子功能表除外)添加一個子功能表,通過把<menu>元素作為<item>元素的一個子項目方式來添加。當應用程式中有很多能夠被組織到一個專題中的功能時,子功能表是有益的,就像PC應用程式的功能表列中的項目(File、Edit、View等)一樣,如:
<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android">
<item android:id="@+id/file"
android:title="@string/file" >
<!-- "file" submenu -->
<menu>
<item android:id="@+id/create_new"
android:title="@string/create_new" />
<item android:id="@+id/open"
android:title="@string/open" />
</menu>
</item>
</menu>
要在Activity中使用菜單,你需要使用MenuInflater.inflate()方法來載入菜單資源(把XML資源轉換成可程式化對象)。在下列章節中,你會看到每種類型菜單的建立方法。
建立一個選項菜單
選項菜單應該是包含動作和與當前Activity上下文環境相關的其他選項,如:“搜尋”、“編寫電子郵件”、和“設定”等。
選項菜單中項目在螢幕上顯示的位置依賴與你的應用程式所依賴的Android平台版本:
1. 如果你的應用程式依賴Android2.3.x(API 層級 10)或更低的版本,那麼當使用者按下Menu按鈕時,你的選項菜單內容會顯示在螢幕的底部,1所示:當菜單被開啟時,首先看到的是表徵圖菜單,它們被六個功能表項目持有。如果你的菜單包含的功能表項目大於6,那麼Adroid會放入第六個項目並把其餘的項目放到溢出菜單中,使用者能夠同選擇更多的功能表項目來開啟其餘的功能表項目。
圖1.Android2.3上的瀏覽器的可選菜單
2. 如果你的應用程式依賴Android3.0(API 層級 11)或更高的版本,可先菜單的項目在操作欄(action bar)中是有效。預設情況下,系統會把所有的項目放到動作溢出中,使用者能夠在操作欄(action bar)的右邊看到動作溢出表徵圖(或者,如果Menu按鈕有效,按下裝置的Menu按鈕也可以)。要讓重要的動作快速存取,你能夠通過在<item>元素中添加android:showAsAction=”ifRoom”屬性設定,把一些功能表項目放到操作欄中顯示。
注意:即使你的應用不依賴Android3.0或更高的版本,你也能夠構建自己的操作欄(action bar)來模仿類似的效果。
圖2.Honeycomb Gallery應用程式的操作欄,顯示了導航標籤和照相機動作項(被加在動作溢出按鈕上)
Honeycomb Gallery應用程式網址:
http://developer.android.com/resources/samples/HoneycombGallery/index.html
你既可以給Activity子類,也可以給Fragment子類聲明選項功能表項目。如果Activity和Fragment都聲明了選項功能表項目,它們會在UI中組合到一起。Activity的選項菜單會首先顯示,緊接著按照每個Fragmeng被添加的順序來顯示Fragment的選項菜單。如果需要,你能夠在每個需要移動的<item>元素中用android:orderInCategory屬性來重新指定選項菜單的順序。
要給一個Activity指定選項菜單,需要重寫onCreateOptionsMenu()方法(Fragment也提供它們自己的onCreateOptionsMenu()方法)。在這個方法中,能夠把菜單資源(在XML檔案中定義)載入到這個回調方法提供的Menu對象中。如:
@Override
public boolean onCreateOptionsMenu(Menu menu) {
MenuInflater inflater =
getMenuInflater();
inflater.inflate(R.menu.game_menu, menu);
return true;
}
你也能夠使用add()方法來添加功能表項目,並且用findItem()方法擷取要用MenuItem APIs修改屬性的功能表項目。
如果你的應用程式依賴Android2.3.x或更低的版本,系統會在使用者首次開啟這個菜單時,調用onCreateOptionsMenu()方法來建立選項菜單。如果你的應用程式依賴Android3.0或更高的版本,系統會在啟動Activity時調用onCreateOptionsMenu()方法,以便把選項菜單顯示在操作欄(action bar)中。
處理click事件
當使用者選擇了選項菜單中的一個功能表項目(包括操作欄(action bar)中動作),系統會調用Activity的onOptionsItemSelected()方法。這個方法把選擇的功能表項目作為參數來傳遞。你能夠通過調用getItemId()方法來識別功能表項目,這個方法返回了對象功能表項目的唯一ID(這個ID是在菜單資源的android:id屬性中定義的,或者是傳遞給add方法的一個整數)。你能夠把這個ID與已知的功能表項目匹配,讓它執行對應的動作,如:
@Override
public boolean onOptionsItemSelected(MenuItem item) {
// Handle item selection
switch (item.getItemId()) {
case R.id.new_game:
newGame();
return true;
case R.id.help:
showHelp();
return true;
default:
return super.onOptionsItemSelected(item);
}
}
當你成功的處理了一個功能表項目時,就返回true。如果你沒有處理功能表項目,你應該調用父類的onOptionsItemSelected()方法實現(預設的實現返回false)。
如果你Activity包括Fragment,那麼系統會首先調用Activity的onOptionsItemSelected()方法,然後會調用每個Fragment的onOptionsItemSelected()方法(按照每個Fragment被添加的順序),直到其中的一個返回true,或所有Fragment的onOptionsItemSelected()方法都被調用。
提示:Android3.0使用android:onClick屬性添加了在XML檔案中給功能表項目定義on-click行為的能力。這個屬性值必須是Activity定義的使用菜單的一個方法名。這個方法必須是公用的,並且要接收一個單一的MenuItem對象參數---當系統調用這個方法時,會用它來傳遞被選擇的功能表項目。更多的資訊和樣本,請看“菜單資源”文檔。
提示:如果你的應用程式套件組合含了多個Activity,並且其中的一些Activity都提供了相同的選項菜單,可以考慮建立一個除onCreateOptionsMenu()和onOptionItemSelected()方法以外沒有任何其他實現的Activity類,然後,每個Activity都繼承這個Activity,這樣就實現了相同選項菜單的共用。這種方法,你能夠只管理一組處理菜單動作的代碼,並且每個子類都會繼承這個菜單行為。如果你想要給這個Activity子類添加功能表項目,重寫那個Activity的onCreateOptionsMenu()方法就可以了,在用menu.add()方法添加新的功能表項目時,要調用super.onCreateOptionsMenu(menu)方法,以便初始功能表項目被建立。你也能夠給獨立的功能表項目重寫其父類的行為。
在運行時改變功能表項目
系統調用onCreateOptionsMenu()方法以後,它會保留你組裝的這個菜單的一個執行個體。除非這個菜單對某些螢幕是無效的,否則系統不會再次調用onCreateOptionsMenu()方法。因此,你應該僅在建立初始菜單狀態時使用onCreateOptionsMenu()方法,並且在Activity的生命週期內不使它發生改變。
如果你想要基於Activity生命週期期間發生的事件來修改選項菜單,那麼你可以在onPrepareOptionsMenu()方法中來做這件事。這個方法把當前存在的Menu對象傳遞給你,以便你能夠修改它,如添加、刪除、或禁用功能表項目。(Fragment也提供一個onPrepareOptionsMenu()回調方法。)
在Android2.3.x和更低版本上,每次使用者開啟選項菜單(按下Menu按鈕)時,系統都會調用onPrepareOptionsMenu()方法。
在Android3.0和更高的版本上,當功能表項目在操作欄(action bar)中展現的時候,選項菜單被認為是始終開啟的。當一個事件發生,並且你要執行一個菜單更新的動作時,你必須調用invalidateOptionMenu()方法來請求系統調用onPrepareOptionsMenu()方法。
注意:你永遠都不會基於當前焦點中的View對象來改變選項菜單的項目。當在觸屏模式中,View對象不需要焦點,因此你永遠不會使用焦點作為修改選項菜單中功能表項目的基礎。如果想要給一個View對象提供一個上下文敏感的菜單,請使用操作功能表。