標籤:
轉載)Android菜單詳解——理解android中的Menu (2012-11-25 18:52:30)
轉載▼
| 標籤: 雜談 |
分類: android開發知識(轉載) |
原文參考:http://www.cnblogs.com/qingblog/archive/2012/06/08/2541709.html
Android菜單詳解——理解android中的Menu前言
今天看了pro android 3中menu這一章,對Android的整個menu體系有了進一步的瞭解,故整理下筆記與大家分享。
PS:強烈推薦《Pro Android 3》,是我至今為止看到的最好的一本android書,中文版出到《精通Android 2》。
理解Android的菜單
菜單是許多應用程式不可或缺的一部分,Android中更是如此,所有搭載Android系統的手機甚至都要有一個"Menu"鍵,由此可見菜單在Android程式中的特殊性。Android SDK提供的菜單有如下幾種:
- 選項菜單:最常規的菜單,android中把它叫做option menu
- 子功能表:android中點擊子功能表將彈出懸浮視窗顯示子功能表項。子功能表不支援嵌套,即子功能表中不能再包括其他子功能表。
- 操作功能表:android中長按視圖控制項後出現的菜單,windows點擊右鍵彈出的菜單即操作功能表
- 表徵圖菜單:這個比較簡單,就是帶icon的功能表項目,需要注意的是子功能表項、操作功能表項目、擴充功能表項目均無法顯示表徵圖。
- 選擇菜單(alternative menu):用的比較少,以後單獨介紹,本文先跳過(其實是我還沒弄明白啦o(≧v≦)o~~)
- 擴充菜單:選項菜單最多隻能顯示6個功能表項目,超過6個時,第6個功能表項目會被系統替換為一個叫“更多”的子功能表,原來顯示不下的功能表項目都作為“更多”菜單的子功能表項。如:
第6個功能表項目自動變為“更多” 點擊“更多”顯示其他功能表項目
Android3.0又引入了一個叫action bar的東西,本文不做講解,大家自己google。
android.view.Menu介面代表一個菜單,android用它來管理各種功能表項目。注意我們一般不自己建立menu,因為每個Activity預設都內建了一個,我們要做的是為它加功能表項目和響應功能表項目的點擊事件。android.view.MenuItem代表每個功能表項目,android.view.SubMenu代表子功能表。其三者的關係可以用來表示
上面說過,每個activity包含一個菜單,一個菜單又能包含多個功能表項目和多個子功能表,子功能表其實也是菜單(因為它實現了Menu介面),因此子功能表也可以包含多個功能表項目。SubMenu繼承了Menu的addSubMenu()方法,但調用時會拋出執行階段錯誤。OnCreateOptionsMenu()和OnOptionsMenuSelected()是activity中提供了兩個回調方法,用於建立功能表項目和響應功能表項目的點擊。
建立options menu
之前提到,Android的activity已經為我們提前建立好了android.view.Menu對象,並提供了回調方法onCreateOptionsMenu(Menu menu)供我們初始化菜單的內容。該方法只會在選項菜單第一次顯示的時候被執行,如果你需要動態改變選項菜單的內容,請使用 onPrepareOptionsMenu(Menu)。
@Override
publicboolean onCreateOptionsMenu(Menu menu) {
// 調用父類方法來加入系統功能表
// 雖然目前android還沒有系統功能表,但是為了相容到以後的版本,最好加上
super.onCreateOptionsMenu(menu);
// 添加功能表項目(多種方式)
// 1.直接指定標題
menu.add("功能表項目1");
// 2.通過資源指定標題
menu.add(R.string.menuitem2);
// 3.顯示指定功能表項目的組號、ID、排序號、標題
menu.add(
1, //組號
Menu.FIRST, //唯一的ID號
Menu.FIRST, //排序號
"功能表項目3"); //標題
// 如果希望顯示菜單,請返回true
returntrue;
}
上面的代碼示範了添加功能表項目的3種方法,下面解釋下第三種方法add(int groupId, int itemId, int order,CharSequence title)。其中,第一個參數是組號,android中你可以給菜單分組,以便快速地操作同一組的菜單。第二個參數指定每個功能表項目的唯一ID號,你可以自己指定,也可以讓系統來自動分配,在響應菜單時你需要通過ID號來判斷哪個菜單被點擊了。因此常規的做法是定義一些ID常量,但在android中有更好的方法,就是通過資源檔來引用,這個之後介紹。第三個參數代表功能表項目顯示順序的編號,編號小的顯示在前面。
給功能表項目分組
@Override
publicboolean onCreateOptionsMenu(Menu menu) {
super.onCreateOptionsMenu(menu);
// 添加4個功能表項目,分成2組
int group1 =1;
int gourp2 =2;
menu.add(group1, 1, 1, "item 1");
menu.add(group1, 2, 2, "item 2");
menu.add(gourp2, 3, 3, "item 3");
menu.add(gourp2, 4, 4, "item 4");
// 顯示菜單
returntrue;
}
你可以向上面這樣給功能表項目分組,分組之後就能使用menu中提供的方法對組進行操作了,如下:
menu.removeGroup(group1); //刪除一組菜單
menu.setGroupVisible(gourp2, visible); //設定一組菜單是否可見
menu.setGroupEnabled(gourp2, enabled); //設定一組菜單是否可點
menu.setGroupCheckable(gourp2, checkable, exclusive); //設定一組菜單的勾選情況
響應功能表項目
android提供了多種響應功能表項目的方式,下面一一介紹
1、通過onOptionsItemSelected方法
使用的最多方法是重寫activity類的 onOptionsItemSelected(MenuItem)回調方法,每當有功能表項目被點擊時,android就會調用該方法,並傳入被點擊功能表項目。
@Override
publicboolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
//響應每個功能表項目(通過功能表項目的ID)
case1:
// do something here
break;
case2:
// do something here
break;
case3:
// do something here
break;
case4:
// do something here
break;
default:
//對沒有處理的事件,交給父類來處理
returnsuper.onOptionsItemSelected(item);
}
//返回true表示處理完功能表項目的事件,不需要將該事件繼續傳播下去了
returntrue;
}
以上代碼可作為使用onOptionsItemSelected方法響應菜單的模板來使用,這裡為了方便起見將菜單ID寫入程式碼在程式裡,你可以使用常量或資源ID來使代碼更健壯。
2.使用監聽器
雖然第一種方法是推薦使用的方法,android還是提供了類似java swing的監聽器方式來響應菜單。使用監聽器的方式分為兩步:
//第一步:建立監聽器類
class MyMenuItemClickListener implements OnMenuItemClickListener {
@Override
publicboolean onMenuItemClick(MenuItem item) {
// do something here...
returntrue; //finish handling
}
}
//第二步:為功能表項目註冊監聽器
menuItem.setOnMenuItemClickListener(new MyMenuItemClickListener());
android文檔對onMenuItemClick(MenuItem item)回調方法的說明是"Called when a menu item has been invoked. This is the first code that is executed; if it returns true, no other callbacks will be executed." 可見該方法先於onOptionsItemSelected執行。
3.使用Intent響應菜單
第3種方式是直接在MenuItem上調用setIntent(Intent intent)方法,這樣android會自動在該菜單被點擊時調用startActivity(Intent)。但是個人認為與其這樣還不如直接在onOptionsItemSelected的case裏手動調用startActivity(Intent)來的直觀。
Android菜單詳解(三)——SubMenu和IconMenu
我們在上一篇介紹了如何在Android中建立和響應選項菜單,今天我們將探索子功能表和表徵圖菜單。
子功能表Sub Menu
子功能表提供了一種自然的組織功能表項目的方式,它被大量地運用在windows和其他OS的GUI設計中。Android同樣支援子功能表,你可以通過addSubMenu(int groupId, int itemId, int order, int titleRes)方法非常方便的建立和響應子功能表。
@Override
publicboolean onCreateOptionsMenu(Menu menu) {
int base = Menu.FIRST;
// 一個menu可以包括多個子功能表
SubMenu subMenu = menu.addSubMenu(base, base+1, Menu.NONE, "系統設定");
// 子功能表可以包括多個功能表項目
MenuItem menuitem1 = subMenu.add(base, base+1, base+1, "顯示設定");
subMenu.add(base, base+2, base+2, "網路設定");
subMenu.add(base, base+3, base+3, "進階設定");
subMenu.add(base, base+4, base+4, "安全設定");
// 子功能表項不支援顯示表徵圖,這樣做是沒意義的,儘管不會報錯!
menuitem1.setIcon(R.drawable.displaysettings);
//但是子功能表本身是支援表徵圖的
subMenu.setIcon(R.drawable.settings);
// 顯示菜單請返回true
returntrue;
}
上面的代碼示範了如何建立子功能表,其功能表項目的響應其實就是普通功能表項目的響應,上一篇已經作了詳細介紹,這裡不再贅述。Android中可以為子功能表添加表徵圖,但是不會顯示其功能表項目的表徵圖,這一點需要留意。除了代碼中的setIcon(int iconRes)方法,還有一個setHeaderIcon(int iconRes)方法可以添加子功能表項欄目的標題表徵圖,效果如上面第三張圖。
最後需要強調的是,Menu可以包含多個SubMenu,SubMenu可以包含多個MenuItem(這三者之間的關係見Android菜單詳解(一)——理解Android中的Menu),但是SubMenu不能包含SubMenu,及子功能表不能嵌套!!!下面的代碼能通過編譯,但會在運行時出錯。
subMenu.addSubMenu("又一個子功能表");表徵圖菜單Icon Menu
Android支援在菜單上顯示各種各樣的表徵圖,這一點我們在上面建立子功能表時已經用到了。表徵圖菜單嚴格上說並不算是一種菜單的新類型,它的使用也很簡單,之所以單獨設一節是為了說明使用Icon的一些限制。Android中並不是所謂的功能表項目都能加標,以下功能表項目都是不可以的(這並不意味著程式會報錯,而是運行時表徵圖得不到顯示):
- 擴充的功能表項目。如果不理解什麼是擴充的菜單,可以參考Android菜單詳解(一)——理解Android中的Menu
- 子功能表的功能表項目
- 操作功能表的功能表項目
除此以外,帶Icon的功能表項目不能加上複選框(check mark)。總之,雖然精美的表徵圖能給我們的應用增色不少,但是濫用表徵圖也是會適得其反的,Android SDK給表徵圖菜單加的這些限制也算是有效防止我們濫用表徵圖了吧。
結語
本篇介紹了Android中的子功能表和給功能表項目加Icon時需要注意的幾點,下一篇《Android菜單詳解(四)——使用操作功能表ContextMenu》將介紹操作功能表Context Menu的使用。
之前在《Android菜單詳解(二)——建立並響應選項菜單》和《Android菜單詳解(三)——SubMenu和IconMenu》中詳細講解了選項菜單,子功能表和表徵圖菜單。今天接著細說另一種被廣泛使用的菜單——操作功能表Context Menu。
ContextMenu簡介
在Windows中,我們已經習慣了在檔案上單擊右鍵來執行“開啟”、“重名名”、“剪下”、“刪除”等操作,這個右鍵彈出的菜單就是操作功能表。你可能會笑道:“哈哈,你不會連快速鍵都不會用吧?”。咳咳,這個。。。舉個例子嘛。沒錯,windows中快速鍵能協助我們提高操作的效率,但是android中這招可不管用嘍,注意:android的操作功能表項目是不能用快速鍵的。因為手機的操作方式與使用滑鼠的PC操作方式不同,android是通過長按某個視圖元素來彈出操作功能表的(PS:現在大多數智能機是全觸屏的,沒有物理鍵盤,更沒有使用快速鍵的需要了,這項革新要歸功於喬布斯在07發布的革命手機iPhone,老喬退休了,向他致敬!)。除此之外,甚至連表徵圖和子功能表都無法用在Android的操作功能表項目中。那麼,Android的操作功能表到底如何使用?見
,操作功能表繼承了android.view.Menu,因此我們可以像操作Options Menu那樣給操作功能表增加功能表項目。操作功能表與Options Menu最大的不同在於,Options Menu的擁有者是Activity,而操作功能表的擁有者是Activity中的View。每個Activity有且只有一個Options Menu,它為整個Activity服務。而一個Activity往往有多個View,並不是每個View都有操作功能表,這就需要我們顯示地通過registerForContextMenu(View view)來指定。
儘管操作功能表的擁有者是View,產生操作功能表卻是通過Activity中的onCreateContextMenu(ContextMenumenu, View v, ContextMenu.ContextMenuInfo menuInfo)方法,該方法很像產生Options Menu的onCreateOptionsMenu(Menu menu)方法。兩者的不同在於,onCreateOptionsMenu只在使用者第一次按“Menu”鍵時被調用,而onCreateContextMenu會在使用者每一次長按View時被調用,而且View必須已經註冊了操作功能表。
另一個值得注意的就是中的ContextMenuInfo,該類的對象被傳入onCreateContextMenu(ContextMenumenu, View v, ContextMenu.ContextMenuInfo menuInfo)方法,那麼它有什麼用呢?有時候,視圖元素需要向操作功能表傳遞一些資訊,比如該View對應DB記錄的ID等,這就要使用ContextMenuInfo。需要傳遞額外資訊的View需要重寫getContextMenuInfo()方法,返回一個帶有資料的ContextMenuInfo實作類別對象。
介紹了這麼多,下面給出一個demo示範如何建立和響應操作功能表:
1.在activity的onCreate(...)方法中為一個view註冊操作功能表
2.在onCreateContextMenuInfo(...)中產生操作功能表。
3.在onContextItemSelected(...)中響應操作功能表項目。
Demo:使用操作功能表
1)註冊操作功能表
publicclass SampleContextMenuActivity extends ListActivity {
privatestaticfinal String TAG ="SampleContextMenuActivity";
@Override
protectedvoid onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// 顯示列表
simpleShowList();
// 為所有清單項目註冊操作功能表
this.registerForContextMenu(getListView());
}
privatevoid simpleShowList() {
// list item
String[] files =new String[] {
"檔案1",
"檔案2",
"檔案3",
"檔案4"
};
// simple array adapter
ArrayAdapter<</SPAN>String> adapter =new ArrayAdapter<</SPAN>String>(
this,
android.R.layout.simple_list_item_1,
files);
// set adapter
this.setListAdapter(adapter);
Log.v(TAG, "show simple list");
}
}
2)產生操作功能表
在activity中重寫方法。
@Override
publicvoid onCreateContextMenu(ContextMenu menu, View v,
ContextMenuInfo menuInfo) {
Log.v(TAG, "populate context menu");
// set context menu title
menu.setHeaderTitle("檔案操作");
// add context menu item
menu.add(0, 1, Menu.NONE, "發送");
menu.add(0, 2, Menu.NONE, "標記為重要");
menu.add(0, 3, Menu.NONE, "重新命名");
menu.add(0, 4, Menu.NONE, "刪除");
}
3)響應操作功能表項目
與響應options menu類似,唯一的不同是可以通過menu info獲得額外的資訊。
@Override
publicboolean onContextItemSelected(MenuItem item) {
// 得到當前被選中的item資訊
AdapterContextMenuInfo menuInfo = (AdapterContextMenuInfo) item.getMenuInfo();
Log.v(TAG, "context item seleted ID="+ menuInfo.id);
switch(item.getItemId()) {
case1:
// do something
break;
case2:
// do something
break;
case3:
// do something
break;
case4:
// do something
break;
default:
returnsuper.onContextItemSelected(item);
}
returntrue;
}
運行程式,多次喚出操作功能表,注意LogCat的輸出,onCreateContextMenu每一次都被調用了。
結語
至此,我們介紹完了android中的各種常用菜單,但是目前為止我們都是通過寫入程式碼來增加功能表項目的,android為此提供了一種更便利的方式,將在下一節“使用XML產生菜單”中介紹。
Android菜單詳解(五)——使用XML產生菜單
回顧前面的幾篇,我們都是直接在代碼中添加功能表項目,給功能表項目分組等,這是比較傳統的做法,它存在著一些不足。比如說,為了響應每個功能表項目,我們需要用常量來儲存每個功能表項目的ID等。為此,Android提供了一種更好的方式,就是把menu也定義為應用程式的資源,通過android對資源的本地支援,使我們可以更方便地實現菜單的建立與響應。這一篇就介紹如何使用XML檔案來載入和響應菜單,我們需要做這幾步:
- 在/res目錄下建立menu檔案夾
- 在menu目錄下使用與menu相關的元素定義xml檔案,檔案名稱是隨意的,android會自動為其產生資源ID。例如:R.menu.mainmenu對應menu目錄的mainmenu.xml資源檔
- 使用xml檔案的資源ID,將xml檔案中定義的功能表項目添加到menu對象中
- 響應功能表項目時,使用每個功能表項目對應的資源ID
下面就使用xml的方式完成《Android菜單詳解(二)——建立並響應選項菜單》中的options menu。
定義菜單資源檔
在res目錄下建立menu檔案夾,在menu下建立一個xml資源檔,我這裡叫做mainmenu.xml
Android菜單詳解——理解android中的Menu