星期二, 9月 27, 2011

Creating Menus

Android應用程式學習筆記

Creating Menus


菜單是在activity的使用者介面中蠻重要的部分,它提供使用者熟悉的方式去執行動作,Android提供一個簡單的架構讓你可以添加菜單到你的應用程式中。

有三種形式的應用程式菜單:

Options Menu
為Activity主要的菜單種類,當使用者按壓"MENU"按鍵時顯示菜單。你的應用程式運行在Android 3.0或更新版本,你可以將菜單項目放置到Action Bar中提? 快速存取的功能。
Context Menu
當使用者觸碰或按住已註冊提供context menu的view時顯示浮動的菜單項目列表。
Submenu
當使用者點選有巢狀菜單的菜單項目時顯示浮動的菜單項目列表。
接著就依種類學習Menus。


Creating a Menu Source


取代在你的應用程式程式碼中實現菜單,你應該在XML菜單資源中定義菜單以及所有的菜單項目,然後在應用程式程式碼中擴展菜單資源,使用菜單資源來定義你的菜單是較佳的方式,因為將菜單內容與應用程式程式碼分開,如此更能想像在XML中菜單的內容與結構。

建立菜單資源,先在你的專案的res/menu目錄下建立一個XML文件並用以下標籤建構菜單:

<menu>
此標籤用來定義一個菜單,它是菜單項目的容器,<menu>標籤必須是文件中的根節點且能保有一個或多個<item>與<group>標籤。
<item>
此標籤用來建立菜單項目,顯示在菜單中的項目,一個標籤對應一個菜單項目。標籤可以在包含一個巢狀<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" />
    <item android:id="@+id/help"
          android:icon="@drawable/ic_help"
          android:title="@string/help" />
</menu>

 此例包含兩個項目,每個項目包括屬性:

android:id
Id對於項目是有唯一性,它可以允許應用程式辨認是哪個項目被使用者所選到。
android:icon
引用圖片作為項目的圖標。
android:title
引用字串作為項目的標題。
有許多屬性是可以包括在<item>中, 包括可以讓Action Bar先是在項目中。更多資訊等之後會寫在Menu reference中。


Inflating a Menu Resource

從應用程式程式碼你可以使用MenuInflater.inflate()方法來擴展菜單資源(轉換xml資源成為可編成的)。例如在onCreateOptionMenu()回呼方法中擴展上述的game_menu.xml例子,並將菜單資源作為activity的菜單。


@Override
public boolean onCreateOptionsMenu(Menu menu) {
    MenuInflater inflater = getMenuInflater();
    inflater.inflate(R.menu.game_menu, menu);
    return true;
}

getMenuInflater()方法為activity回傳一個Inflater物件,有這個Inflater物件,你可以呼叫inflate()方法來擴展你的菜單資源成為Menu物件。在此例子中,定義菜單資源的game_menu.xml通過onCreateOptionMenu()方法擴展成為Menu(onCreateOptionMenu回呼方法會在下一段中討論)。


那接下來的內容就依照一種形式的菜單為一個區塊來討論,依序討論option menu、context menu、submenu。

Create an Option Menu

Option menu是應該放置你的activity的基本動作和必需的導航項目的地方(例如,用來開啟應用程式設定的按鈕)。有兩種不同方式可以訪問Option menu的項目:MENU按鈕和Action Bar(Android 3.0版以後)。

當裝置運行的是Android 2.3或更低版本,option menu顯示在屏幕的底層,如圖1。當打開菜單,第一個看見菜單的部分是圖標菜單,它有前六個菜單項目,如果你想增加超過六個菜單項目,amdroid放置第六個菜單項目來裝那些多出來的菜單項目,當使用者觸碰"More"項目。


圖1.屏幕底部為Option menu
在Android 3.0及更高的版本,Option menu的項目是被放置在Action Bar,它出現在activity的頂部取代傳統的標題欄。預設的情況下,所有Option menu的項目被放置在溢出來的菜單中,使用者可以觸碰Action Bar右側的菜單圖標開啟菜單。然而,你可以將選擇菜單項目直接放在Action Bar中作為"Action items",如圖2。

 圖2.這是一個電子郵件應用程式的Action Bar,有兩個來自option menu的action item與更多菜單

當android系統第一次建立Options menu,系統會呼叫你的activity的onCreateOptionMenu()方法,在你的activity中複寫此方法並且將菜單資源放置到傳遞到此方法的Menu物件中。

@Override
public boolean onCreateOptionsMenu(Menu menu) {
    MenuInflater inflater = getMenuInflater();
    inflater.inflate(R.menu.game_menu, menu);
    return true;
}

你可以使用add()方法增加item到Menu中。


Responding to user action

 當用戶選擇來自Option menu的菜單項目時,系統會呼叫你的activity中的onOptionsItemSelected()方法,此方法會傳入用戶選擇的菜單項目,你可以呼叫getItemId方法,它會回傳項目的ID,你可以比對ID來知道哪個item被擁護選擇並執行相對應的動作。

@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);
    }
}

此例子中,getItemId()用來查詢被選擇的項目的ID,switch的判斷式是用來將ID與在菜單資源的菜單項目的ID做比較。當siwtch成功處理菜單項目後,它會回傳true值表示item selection已經處理了。否則,default程式碼用super類呼叫原本的onOptionsMenuSelected()方法。

此外,Android 3.0為你增加了一項能力就是在菜單資源的xml檔案中定義on-click行為,使用android:onClick屬性,所擬你不需要實現onOptionsMenuSelected()方法。使用android:onClick屬性,你可以指定一個方法給被用戶選擇的菜單項目。


Changing menu item at runtime

一旦activity建立後,onCreateOptionsMenu()方法只會被呼叫一次,系統保留並重複使用在此方法定義的Menu物件直到activity被銷毀。如果想要在建立後的任何時間改變菜單,可以複寫onPrepareOptionsMenu()方法,如此就能根據應用程式目前的狀態新增、刪除、禁用或啟用菜單項目。

在Android 2.3或更低版本,系統呼叫onPrepareOptionsMenu()方法。

在Andoird 3.0或更高版本,當你想改變菜單時你可以呼叫invalidateOptionsMenu()方法,系統將會呼叫onParepareOptionsMenu()方法來更新菜單。


Creating a Context Menu

Context menu概念與當用戶使用電腦"右鍵"的菜單相似,你應該使用context menu提供用戶在使用者介面上訪問屬於特定項目的動作,在Android平台上,當用戶長按項目時顯示context menu。

你可以在任何試圖中建立context menu,雖然context menu大部分使用在ListView的項目上,當用戶長按ListView上的項目時且列表有被註冊要提供context menu,列表項目藉著動畫背景顏色來發出context menu是可用的信號-它會在打開context menu之前從橘色轉成白色。

為了讓View物件能提供context menu,你必須將context menu註冊在View物件上,呼叫registerContextMenu()方法並將想註冊context menu的View傳到此方法。當此View接收到長按事件時,它就顯示context menu。

複寫activity的contexte menu回呼方法來定義context menu的外觀與行為:onCreateContextMenu()和onContextItemSelected()。

例子,使用context_menu.xml資源的onCreateContextMenu()方法。

@Override
public void onCreateContextMenu(ContextMenu menu, View v,
                                ContextMenuInfo menuInfo) {
  super.onCreateContextMenu(menu, v, menuInfo);
  MenuInflater inflater = getMenuInflater();
  inflater.inflate(R.menu.context_menu, menu);
}

MenuInflater用來擴展來自menu resource的context menu(你也可以使用add()方法來增加菜單項目),回呼方法的參數包括給用戶選擇的view物件及ContextMenu.ContextMenuInfo提供項目被選擇時的其他資訊。你也可以用這些參數決定哪個context menu應該被建立,但是在此例子,所有對於activity的context menu都是相同的。

接著當用戶選擇了context menu中的項目,系統呼叫onContextItemSelected()方法,以下有一例子來演示可以如何處理選擇項目。

@Override
public boolean onContextItemSelected(MenuItem item) {
  AdapterContextMenuInfo info = (AdapterContextMenuInfo) item.getMenuInfo();
  switch (item.getItemId()) {
  case R.id.edit:
    editNote(info.id);
    return true;
  case R.id.delete:
    deleteNote(info.id);
    return true;
  default:
    return super.onContextItemSelected(item);
  }
}

此方法的程式碼結構與上述的例子相似,getItemId()查詢被選擇到的ID而switch判斷式比對在材單資源裡的項目的ID。

在此例中,被選擇的項目是來自ListView的項目。執行被選擇項目的動作,應用程式需要知道被寫責的項目ID,應用程式呼叫getMenuInfo()方法來得到ID,它會回傳AdapterView.AdapterContextMenuInfo物件,該物件包括ID。


Creating Submenus

Submenu是用戶可以選擇其他菜單的項目來打開的菜單。你可以在任何菜單中增加子菜單,子菜單是用來將應用程式有許多功能分類成幾個主題。

當建立菜單資源時,可以增加<menu>標籤作為一個子項目,比如:

<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android">
    <item android:id="@+id/file"
          android:icon="@drawable/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>

當用戶選擇了一個子菜單的項目,父菜單的on-item-selected方法會接收到事件。例如,上述的菜單應用在Option menu上,那當子菜單的項目被選擇時呼叫onOptionsItemSelected()方法。

你也可以呼叫addSubmenu()方法動態的增加子菜單在以存在的菜單中,它會回傳一個子菜單物件,你可以使用add()方法來增加子菜單的項目。


Other Menu Feature

這裡有一些其他屬性你可以應在大部分的菜單。

Menu groups

Menu group是菜單項目的集合,有group,你可以做:
  • 用setGroupVisible()方法顯示或隱藏所有項目。
  • 用setGroupEnabled()方法啟用或禁用所有項目。
  • 用setGroupCheckable()方法所有項目是否為checkable。
你可以在菜單資源中<group>標籤裡面增加巢狀<item>來建立group,或用add()方法指定group ID。

以下是包含一個group的菜單資源。

<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android">
    <item android:id="@+id/item1"
          android:icon="@drawable/item1"
          android:title="@string/item1" />
    <!-- menu group -->
    <group android:id="@+id/group1">
        <item android:id="@+id/groupItem1"
              android:title="@string/groupItem1" />
        <item android:id="@+id/groupItem2"
              android:title="@string/groupItem2" />
    </group>
</menu>



Cheackable menu items

一個可以作為開關項目的介面的菜單,獨立選項可以使用複選框(checkbox),或互相排斥選項的group可以使用單選按鈕(radio button)。

你可以在<item>標籤中使用android:checkable屬性來定義個別項目checkable屬性,或者在<group>標籤中用android:checkableBehavior屬性來定義整個group的行為。

例子,all items in this menu group are checkable with a radio button。

<?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屬性可以接受數值有:
  • single-Group中只有一個項目可以檢查(radio button)。
  • all-所有項目都可以檢查(checkbox)。
  • none-沒有可檢查的項目。

 你可以先用android:checked屬性的預設值,然後在程式碼鐘用setChecked()方法修改。

當可檢查的項目被選到時,系統會呼叫各自的select-item回呼方法(比如,onOptionsItemSelected()方法),在這裡你須設定複選框的狀態,因為複選框或單選按紐都不法自動改變狀態,你可以用isCheck()方法查詢項目的狀態並用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保留項目被檢查的狀態以便當用戶打開菜單後,你可以設定以檢查狀態為可見的。


Shortcut Keys

Dynamic adding menu intents

Allowing your activity to be added other menus

沒有留言:

張貼留言