android menu詳解

前言

今天看了pro android 3中menu這一章,對Android的整個menu體系有了進一步的瞭解,故整理下筆記與大家分享。

PS:強烈推薦《Pro Android 3》,是我至今爲止看到的最好的一本android書,中文版出到《精通Android 2》。

理解Android的菜單

菜單是許多應用程序不可或缺的一部分,Android中更是如此,所有搭載Android系統的手機甚至都要有一個"Menu"鍵,由此可見菜單在Android程序中的特殊性。Android SDK提供的菜單有如下幾種:

  1. 選項菜單:最常規的菜單,android中把它叫做option menu
  2. 子菜單:android中點擊子菜單將彈出懸浮窗口顯示子菜單項。子菜單不支持嵌套,即子菜單中不能再包括其他子菜單。
  3. 上下文菜單:android中長按視圖控件後出現的菜單,windows點擊右鍵彈出的菜單即上下文菜單
  4. 圖標菜單:這個比較簡單,就是帶icon的菜單項,需要注意的是子菜單項、上下文菜單項、擴展菜單項均無法顯示圖標
  5. 選擇菜單(alternative menu):用的比較少,以後單獨介紹,本文先跳過(其實是我還沒弄明白啦o(≧v≦)o~~)
  6. 擴展菜單:選項菜單最多隻能顯示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中提供了兩個回調方法,用於創建菜單項和響應菜單項的點擊。

 

Android菜單詳解(二)——創建並響應選項菜單

上一篇《Android菜單詳解(一)——理解android中的menu》簡單介紹了一下Android的菜單,今天讓我們看一下如何通過代碼創建和響應最常用的選項菜單(options menu)。

創建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(MenuItemitem)回調方法的說明是"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中並不是所謂的菜單項都能加上圖標,以下菜單項都是不可以的(這並不意味着程序會報錯,而是運行時圖標得不到顯示):

除此以外,帶Icon的菜單項不能加上覆選框(check mark)。總之,雖然精美的圖標能給我們的應用增色不少,但是濫用圖標也是會適得其反的,Android SDK給圖標菜單加的這些限制也算是有效的防止我們濫用圖標了吧。

結語

本篇介紹了Android中的子菜單和給菜單項加Icon時需要注意的幾點,下一篇《Android菜單詳解(四)——使用上下文菜單ContextMenu》將介紹上下文菜單Context Menu的使用。

 

 

 

Android菜單詳解(四)——使用上下文菜單ContextMenu

之前在《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(ContextMenu menu, View v, ContextMenu.ContextMenuInfo menuInfo)方法,該方法很像生成Options Menu的onCreateOptionsMenu(Menu menu)方法。兩者的不同在於,onCreateOptionsMenu只在用戶第一次按“Menu”鍵時被調用,而onCreateContextMenu會在用戶每一次長按View時被調用,而且View必須已經註冊了上下文菜單。

另一個值得注意的就是上圖中的ContextMenuInfo,該類的對象被傳入onCreateContextMenu(ContextMenu menu, View v, ContextMenu.ContextMenuInfo menuInfo)方法,那麼它有什麼用呢?有時候,視圖元素需要向上下文菜單傳遞一些信息,比如該View對應DB記錄的ID等,這就要使用ContextMenuInfo。需要傳遞額外信息的View需要重寫getContextMenuInfo()方法,返回一個帶有數據的ContextMenuInfo實現類對象。

介紹了這麼多,下面給出一個demo演示如何創建和響應上下文菜單:

1.在activity的onCreate(...)方法中爲一個view註冊上下文菜單

2.在onCreateContextMenuInfo(...)中生成上下文菜單。

3.在onContextItemSelected(...)中響應上下文菜單項。

Demo:使用上下文菜單

1)註冊上下文菜單

複製代碼
/**
 * 上下文菜單演示Demo
 * 
 * @author CodingMyWorld 2011-8-27 下午03:22:39
 */
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<String> adapter =new ArrayAdapter<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文件來加載和響應菜單,我們需要做這幾步:

  1. 在/res目錄下創建menu文件夾
  2. 在menu目錄下使用與menu相關的元素定義xml文件,文件名是隨意的,android會自動爲其生成資源ID。例如:R.menu.mainmenu對應menu目錄的mainmenu.xml資源文件
  3. 使用xml文件的資源ID,將xml文件中定義的菜單項添加到menu對象中
  4. 響應菜單項時,使用每個菜單項對應的資源ID

下面就使用xml的方式完成《Android菜單詳解(二)——創建並響應選項菜單》中的options menu。

定義菜單資源文件

在res目錄下創建menu文件夾,在menu下創建一個xml資源文件,我這裏叫做mainmenu.xml

編寫mainmenu.xml如下:

複製代碼
<?xml version="1.0" encoding="utf-8"?>
<menu
  xmlns:android="http://schemas.android.com/apk/res/android">
  <!-- group1 -->
  <group android:id="@+id/group1">
      <item android:id="@+id/mi1"
          android:title="item1"/>
      <item android:id="@+id/mi2"
          android:title="item2"/>
  </group>
  <!-- group 2 -->
  <group android:id="@+id/group2">
      <item android:id="@+id/mi3"
          android:title="item3"/>
      <item android:id="@+id/mi4"
          android:title="item4"/>
  </group>
  
</menu>
複製代碼

這裏簡單的添加了4個菜單項,並將其分爲2組。item元素的android:title值可以引用values中的string資源。

使用MenuInflater添加菜單項

inflater在android中建立了從資源文件到對象的橋樑,MenuInflater即把菜單xml資源轉換爲對象並添加到menu對象中,它可以通過activity的getMenuInflater()得到。我們在MainActivity中重寫onCreateOptionsMenu(...)方法。

@Override
publicboolean onCreateOptionsMenu(Menu menu) {
    MenuInflater inflater = getMenuInflater();
    inflater.inflate(R.menu.mainmenu, menu);
    returntrue;
}

響應菜單項

最後重寫onOptionsItemSeleted(...)方法。

複製代碼
@Override
publicboolean onOptionsItemSelected(MenuItem item) {
    switch(item.getItemId()) {
    case R.id.mi1:
        // do sth
break;
    case R.id.mi2:
        // do sth
break;
    case R.id.mi3:
        // do sth
break;
    case R.id.mi4:
        // do sth
break;
    }
    returntrue;
}
複製代碼

這一步最大的體現了使用XML生成菜單的好處。android不僅爲我們定義的xml文件生成了資源ID,同樣可以爲group,menu item來自動生成ID(就像爲佈局中定義的view生成id那樣)。這樣菜單項ID的創建與管理就不用我們操心了,全部交給android去做吧!

至此,我們完成了一個簡單的“使用XML生成菜單”的demo,並從中體會到了使用資源文件的好處,因此這是android中創建菜單的推薦方式。實際上,我們在代碼中對菜單項或分組的操作都能在xml文件中完成,下面就簡單介紹一些比較常用的功能。(谷歌提供的API demos中有最全面的示例)

更多菜單資源文件的功能

1.資源文件實現子菜單

子菜單通過在item元素中嵌套menu來實現。

複製代碼
<item android:title="系統設置">
    <menu>
        <item android:id="@+id/mi_display_setting"
            android:title="顯示設置"/>
        <item android:id="@+id/mi_network_setting"
            android:title="網絡設置"/>
        <!-- 別的菜單項 -->
    </menu>
</item>
複製代碼

2.爲菜單項添加圖標

<item android:id="@+id/mi_exit"
    android:title="退出"
    android:icon="@drawable/exit"/>

3.設置菜單項的可選出現

使用android:checkableBehavior設置一組菜單項的可選策略,可選值爲:none, all, single

<group android:id="..."
    android:checkableBehavior="all">
    <!-- 菜單項 -->
</group>

使用android:checked設置特定菜單項

<item android:id="..."
    android:title="sometitle"
    android:checked="true"/>

4.設置菜單項可用/不可用

<item android:id="..."
    android:title="sometitle"
    android:enabled="false"/>

5.設置菜單項可見/不可見

<item android:id="..."
    android:title="sometitle"
    android:visible="false"/>

結語

本篇是Android菜單詳解系列的最後一篇,本系列詳細介紹了android中各種常用菜單的使用技巧和注意事項,希望能幫助大家更好的理解,也期待與各位交流開發中的心得:)

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章