Android ActionBar詳解

第4章 Action Bar

Action Bar是一個能用於確定應用程序和用戶的位置,並提供給用戶操作和導航模式的窗口功能。如果需要顯著地展示當前用戶的操作或導航,應該使用Action Bar,因爲Action Bar爲用戶提供了一個統一的跨應用程序和系統的接口,並且針對不同尺寸的屏幕優雅的處理了Action Bar的適配。你可以通過ActionBar API來控制它的行爲和可視性,這些API添加於Android 3.0(API級別爲11)。 Action Bar設計的目的是:

◆提供一個專門的空間來確定應用程序的標識和用戶的位置。

這是在應用程序圖標或者是左側的logo以及Activity的標題幫助下完成的。如果當前視圖的導航標籤被標識,例如當前選項卡選中,你可能會選擇刪除該Activity名稱。

◆提供統一的導航和視圖細化到不同的應用程序中。

Action Bar提供了內置選項卡導航來進行在fragments之間切換。它還提供了一個下拉列表中,可以來用來替代導航模式或用來完善當前視圖(比如按照不同的標準來排序列表)。

◆突出Activity的關鍵動作(如“搜索”、“創建”、“共享”,等等。),便於用戶一個可預測的訪問。

對於關鍵的用戶操作,你可以通過將item從選項菜單直接在操作欄定義爲action items來提高訪問速度。action items也可以提供一個“action view”,它用一個嵌入式widget來提供更多及時的動作行爲。沒有晉升爲成action items的菜單項在溢出菜單中還是有效的,用戶既可以使用設備上的菜單按鈕(設備上有按鈕的時候),也可以使用Action Bar中的溢出菜單按鈕(當設備上不包含菜單按鈕時)。如圖4-1所示:

 

圖4-1從左邊開始,依次爲logo,導航標籤與action item和最右邊的溢出菜單按鈕。

4.1 添加Action Bar

從Android3.0(API level 11)開始,Action Bar包括在所有Activity中使用的Theme.Holo主題(或是繼承Activity的一個子類),這是當targetSdkVersion或minSdkVersion屬性設置爲“11”或更高時程序默認的主題。如代碼清單4-1所示:

複製代碼
<manifest ... >

    <uses-sdk android:minSdkVersion="4"

              android:targetSdkVersion="11" />

    ...

</manifest>
複製代碼

 

代碼清單4-1

在這個例子中,應用程序設置的最低版本的API Level爲4(Android 1.6),但它目標API級別爲11(Android 3.0)。通過這樣設置,當應用程序運行在Android 3.0或更高版本上時,系統爲每個Activity應用Holo主題,因此,每一個Activity都包含Action Bar。如果你想使用Action Bar的API,比如添加導航模式和修改操作欄樣式,你應該設置minSdkVersion爲“11”或是更高的版本。如果你想你的應用程序支持舊版本的Android,有很多辦法可以讓低版本的ActionBar的API的在支持API級別爲11或更高的設備上,同時仍運行舊版本。

4.1.1移除Action Bar

如果你不想爲一個特定的Activity設置Action Bar,那麼你可以設置Activity主題爲Theme.Holo.NoActionBar。如代碼清單4-2所示:

<activity android:theme="@android:style/Theme.Holo.NoActionBar">

 

代碼清單4-2

您也能在運行時通過調用hide()隱藏Action Bar。如代碼清單4-3所示:

ActionBar actionBar = getActionBar();

actionBar.hide();

 

代碼清單4-3

當Action Bar隱藏時,系統會調整Activity的佈局來填充所有可用屏幕空間。當然你可以通過調用show()顯示Action Bar。 隱藏和刪除Action Bar可能會使Activity重新調整佈局。如果你的Activity經常隱藏和顯示Action Bar(如在Android的畫廊應用),你可能想用覆蓋(Overlay)模式。覆蓋模式佈局在Activity的上層,而不是在同一層下的Activity的頂部。這樣,你的佈局可以在Action Bar隱藏和重新出現時保持不變。要啓用覆蓋模式,創建Activity主題並且將android:windowActionBarOverlay屬性值設置爲true。注意:如果你有一個自定義的的Activity主題並且想在其中刪除Action Bar,然後把android:windowActionBar樣式屬性設置爲false。,那麼,由於你移除了Action Bar正在使用的主題,那麼getActionBar()方法將返回null,當你和系統調用此方法的時候就會出現問題。

4.2 添加Action Items

有時你可能想讓用戶從選項菜單(options menu)中直接訪問item。要做到這一點,你可以聲明該菜單項爲Action Bar中的一個“action item”。一個“action item”包括一個圖標和/或文字標題。如果一個菜單項不作爲一個“action item”,系統會將菜單項放置在溢出菜單。溢出菜單顯示設備菜單“按鈕(如果設備提供)或在操作欄中的按鈕(如果設備不提供”菜單“按鈕)。首次啓動Activity時,系統通過在activity調用onCreateOptionsMenu()方法來填充action bar和溢出菜單(overflow menu)。在菜單開發指南中討論的,它是在這個回調方法,你應該在inflate一個XML定義菜單項的菜單資源。如代碼清單4-4和圖4-2所示:

複製代碼
@Override

public boolean onCreateOptionsMenu(Menu menu) {

    MenuInflater inflater = getMenuInflater();

    inflater.inflate(R.menu.main_activity, menu);

    return true;

}
複製代碼

 

代碼清單4-4

 

圖4-2 兩個兩個action item的圖標和文字標題,以及溢出菜單按鈕

在XML文件中,你可以通過聲明android:showAsAction="ifRoom" 讓菜單item成爲action item。通過這種方式,當有可用空間時,菜單項纔會出現在action item的快速訪問欄。如果沒有足夠的空間,該item將出現在溢出菜單。如果你的菜單項同時提供標題和圖標--同時具有Android:titile和android:icon屬性,action item默認只會顯示圖標。但如果你想顯示文字標題,必須添加“withText”到Android:showAsAction屬性中。如代碼清單4-5所示:

複製代碼
<?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/ic_menu_save"

          android:title="@string/menu_save"

          android:showAsAction="ifRoom|withText" />

</menu>
複製代碼

 

代碼清單4-5

注:“withText”值應用用於一個Action Bar的提示文本出現。但如果一個圖標無法使用或者空間受限,action bar的標題可能無法顯示。

當用戶選擇一個action  item,activity調用一個OptionsItemSelected()方法,通過android:id屬性獲取的ID值來接收在選項菜單中的所有item中相同的回調。 這一點很重要,你總是爲每個菜單項定義android:title,你不在顯示的action item中聲明標題的理由有三個:

◆如果在action bar中沒有足夠的空間提供給action item,該菜單項出現溢出“菜單中,而且只有標題顯示。

◆屏幕閱讀器爲視障用戶讀出菜單項的標題。

◆如果action item只有圖標,用戶可以長按item顯示的工具提示,顯示action item的標題。

Android的圖標始終是可選的。

你也可以定義一個item“always”爲action item,以避免當空間有限時被放到溢出菜單中去。但在大多數情況下,不應該設置“always”這個值來強制使一個item出現在action bar中。要注意的是過多的action item,會導致創建出來的UI雜亂不堪,並且在窄屏幕的設備上會出現佈局問題。最好使用“ifRoom”,在沒有足夠的空間時,應允許系統將它移動到溢出菜單。

4.2.1選項你的Action items

你應該應通過評估的幾個關鍵特性,仔細從選項菜單中選出action item。在一般情況下,每個action item,至少有以下需求之一:

1、常用性:用戶70%的時間需要訪問或需要連續多次使用。常用性例子:在短信息應用程序的“新信息”和Google Player中的“搜索(Search)”。

2、重要性:用戶能夠很容易地發現,或者如果不經常使用,在少數情況用戶確實需要它的時候,可以毫不費力地執行,這一點是很重要的。重要性例子:在 Wi-Fi設置“加入網絡”和在畫廊(Gallery)應用程序中“切換到相機”。

3、典型性:這是一個通常在類似的應用程序的action bar中提供的action,因此,用戶希望自己找到它。典型性例子:電子郵件應用中的“刷新”和電話本應用中的“新的聯繫人”。

如果你認爲四個以上菜單項可以合理的作爲action item,那麼你應該仔細考慮其相對等級的重要性,並儘量設置不超過四個的菜單項的action item(這樣設置“ifRoom”這個值,在一些空間有限的小屏幕上,系統把一些菜單項放到溢出菜單背面)。即使是寬屏幕上,你也不要創建一個雜亂的UI的action item,冗長得看起來像一個桌面工具欄,應該要使action item的數量保持到最低限度。 此外,下列行爲不應該出現行動項目中:類似設置,幫助,反饋,或查找,始終將這些放在溢出菜單中。

4.2.2使用分離(split)的Action Bar

當你的應用程序運行在Android 4.0系統(API Level 14)或更高時,還有一個額外的模式可稱action bar爲“split action bar”。當在一個狹窄的屏幕運行啓用split action bar時,會在屏幕的底部出現一個action bar顯示所有action item。split action bar用來分開action item,確保分配合理數量的空間來在一個狹窄的屏幕上顯示所有的action item,而空間留給頂端的導航和標題元素。 使用 split action bar,只需添加uiOptions=“splitActionBarWhenNarrow”,到你的<activity>或<application> manifest中。

要知道Android在各種不同的方式,根據當前的屏幕大小調整action bar的外觀。採用split action bar只是一個選項,您可以啓用允許action bar進一步爲不同的屏幕尺寸,優化用戶體驗。這樣做,你也可以讓action bar可以摺疊成主要的action bar的導航標籤(navigation tabs)。也就是說,如果你在你的action bar中使用的導航標籤,一旦action items狹窄的屏幕上分離,導航標籤可以融入的主要action bar,而不是被分隔成的“摺疊的action bar”。具體來說,如果你禁用action bar中的圖標和標題(setDisplayShowHomeEnabled(false)和setDisplayShowTitleEnabled(false)),然後將主要action bar的導航標籤相互重疊,如圖4-3中右邊的設備。

 

圖4-3 左側使用的導航標籤的split action bar與應右側禁用程序圖標和標題的效果對比。

4.3 使用應用程序圖標來導航

默認情況下,應用程序圖標顯示在action bar的左邊。你能夠把這個圖標當做action item來使用。應用程序應該在這個圖標上響應以下兩個操作之一:

返回應用程序的“主”Activity;

◆    返回“home”界面。

◆    嚮應用程序上層結構返回。

當用戶觸摸這個圖標時,系統會調用Activity帶有android.R.id.home ID的onOptionsItemSelected()方法。在這個響應中,你既可以啓動home屏幕,也可以返回你的應用程序結構化層次中用戶上一步操作的界面。

如果你要通過應用程序圖標的響應來返回home屏幕,那麼就應該在Intent對象中包含FLAG_ACTIVITY_CLEAR_TOP標識。用這個標誌,如果你要啓動的Activity在當前任務中已經存在,那麼,堆棧中這個Activity之上的所有的Activity都有被銷燬,並且把這個Activity顯示給用戶。添加這個標誌往往是重要的,因爲返回home屏幕相當與一個回退的動作,而不是創建。

例如,下例的onOptionsItemSelected()方法實現了返回應用程序的home屏幕的操作,如代碼清單4-6所示:

複製代碼
@Override

public boolean onOptionsItemSelected(MenuItem item) {

    switch (item.getItemId()) {

        case android.R.id.home:

            // 在action bar點擊app icon; 回到 home

            Intent intent = new Intent(this, HomeActivity.class);

            intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);

            startActivity(intent);

            return true;

        default:

            return super.onOptionsItemSelected(item);

    }

}
複製代碼

 

代碼清單4-6

在用戶從另一個應用程序進入當前Activity的情況下,你可能還想要添加FLAG_ACTIVITY_NEW_TASK標識。這個標識確保在用戶返回home或上級界面時,新的Activity不會被添加到當前的任務中,而是在屬於你自己的應用程序的任務中啓動。例如,如果用戶通過另一個應用程序調用的Intent對象啓動了你的應用程序中的一個Activity,那麼用戶選擇action bar圖標來返回home或上級界面時,FLAG_ACTIVITY_CLEAR_TOP標識會在屬於你的應用程序的任務中啓動這個Activity(不是當前任務)。系統既可以用這個新的Activity做根Activity來啓動一個新的任務,也可以把存在後臺的擁有這個Activity實例的一個既存任務帶到前臺來,並且目標Activity會接受onNewIntent()回調。因此,如果你的Activity要接收另一個應用程序的Intent對象,那麼通常應該給這個Intent對象添加FLAG_ACTIVITY_NEW_TASK標識,如代碼清單4-7所示:

intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_NEW_TASK);

 

代碼清單4-7

注意:如果你要使用應用圖標來返回主頁,要注意從Android4.0(API 級別 14)開始,必須通過調用setHomeButtonEnabled(true)方法確保這個圖標能夠作爲一個action item(在以前的版本,默認情況下,這個圖標就能夠作爲一個action item的)。

4.3.1應用程序向上導航

作爲傳統的回退導航(把用戶帶回任務歷史中的前一個窗口)的補充,你能夠讓action bar圖標提供向上導航的功能,它應用把用戶帶回到你的應用程序的上級界面。例如,當前界面時你的應用程序層次比較深的一個界面,點擊應用程序圖標應該返回返回上一級頁面(當前界面的父界面)。如圖4-4所示:

 

圖4-4 Email應用程序的標準圖標(左)和向上導航圖標(右)。系統會自動添加向上指示

例如,圖4-5演示了當用戶從一個應用程序導航到一個屬於不同應用程序的Activity時,“回退”按鈕的行爲。

 

圖4-5 在從People(或Contacts)應用程序進入Email應用程序之後,回退按鈕的行爲。

但是,如果在編輯完郵件之後,想要停留在Email應用程序中,那麼向上導航就允許你把用戶導航到Email應用程序中編輯郵件頁面的上級界面,而不是返回到前一個Activity。如圖4-6演示了這種場景,在這個場景中,用戶進入到Email應用程序後,不是按回退按鈕,而是點擊action bar圖標來向上導航。

 

圖4-6 在從從People應用進入Email應用後,向上導航的行爲。

要是應用程序圖標能夠向上導航,就要在你的ActionBar中調用

SetDisplayHomeAsUpEnabledtrue(true)方法,如代碼清單4-8所示:

複製代碼
protected void onCreate(Bundle savedInstanceState) {

    super.onCreate(savedInstanceState);

 

    setContentView(R.layout.main);

    ActionBar actionBar = getActionBar();

    actionBar.setDisplayHomeAsUpEnabled(true);

    ...

}
複製代碼

 

代碼清單4-8

當用戶觸摸這個圖標時,系統會調用帶有android.R.id.home ID的onOptionsItemSelected()方法。

請記住在Intent對象中使用FLAG_ACTIVITY_CLEAR_TOP標識,以便你不會這個父Activity存在的情況下,再創建一個新的實例。例如,如果你不使用FLAG_ACTIVITY_CLEAR_TOP標識,那麼向上導航後,再按回退按鈕,實際上會把用戶帶到應用程序的下級界面,這是很奇怪的。

注意:如果有很多用戶能夠到達應用程序中當前Activity的路徑,那麼,向上圖標應該沿着當前Activity的實際啓動路徑逐步的向後導航。

4.4 添加Action View

Action View是作爲action item按鈕的替代品顯示在action bar中的一個widget。例如,如果你有一個用於搜索的可選菜單項,你可以用SearchView widget來替代action ba的搜索按鈕,如圖4-7所示:

 

圖4-7摺疊(上)和展開(下)的搜索視窗的操作欄

要在菜單資源中的一個item聲明一個action view,你既可以使用android:actionLayout屬性也android:actionViewClass屬性來分別指定一個佈局資源或要使用的可視構件類。如代碼清單4-9所示:

複製代碼
<?xml version="1.0" encoding="utf-8"?>

<menu xmlns:android="http://schemas.android.com/apk/res/android">

    <item android:id="@+id/menu_search"

          android:title="@string/menu_search"

          android:icon="@drawable/ic_menu_search"

          android:showAsAction="ifRoom|collapseActionView"

          android:actionViewClass="android.widget.SearchView" />

</menu>
複製代碼

 

代碼清單4-9

android:showAsAction屬性也可包含“collapseActionView”屬性值,這個值是可選的,並且聲明瞭這個action view應該被摺疊到一個按鈕中,當用戶選擇這個按鈕時,這個action view展開。否則,這個action view在默認的情況下是可見的,並且即便在用戶不用的時候,也要佔據action bar的有效空間。如果需要給action view添加一些事件,那麼就需要在onCreateOptionsMenu()回調期間做點事。你能夠通過調用帶有菜單項ID的findItem()方法來獲取菜單項,然後再調用getActionView()獲取該元素。例如,使用以下方法獲取上例中的搜索視窗widget,如代碼清單4-10所示:

複製代碼
@Override

public boolean onCreateOptionsMenu(Menu menu) {

    getMenuInflater().inflate(R.menu.options, menu);

    SearchView searchView = (SearchView) menu.findItem(R.id.menu_search).getActionView();

    // 配置搜索信息並添加事件監聽器

    ...

    return super.onCreateOptionsMenu(menu);

}
複製代碼

 

代碼清單4-10

4.4.1處理可摺疊的action views

Action views讓你在不改變Activity或Fragment的情況下,就可以給用戶提供快捷的訪問和豐富的操作。但是,默認情況下讓action views可見可能不太合適。要保證action bar的空間(尤其是在小屏幕設備上運行時),你能夠把action view摺疊進一個action item按鈕中。當用戶選擇這個按鈕時,action view就在action bar中顯示。被摺疊的時候,如果你定義了android:showAsAction=“ifRoom”屬性,那麼系統可能會把這個項目放到溢出菜單中,但是當用戶選項了這個菜單項,它依然會顯示在action bar中。通過給android:showAsAction屬性添加“collapseActionView”屬性值,你能夠讓action view可以摺疊起來。

因爲在用戶選擇這個item時,系統會展開這個action view,所以你不需要在onOptionsItemSelected()回調方法中響應這個菜單項。在用戶選擇這個菜單項時,系統會仍然會調用onOptionsItemSelected()方法,但是除非你在方法中返回了true(指示你已經替代系統處理了這個事件),否則系統會始終展開這個action view。

當用戶選擇了action bar中的“向上”圖標或按下了回退按鈕時,系統也會把action view摺疊起來。如果需要,你能夠在代碼中通過在expandActionView()和collapseActionView()方法來展開或摺疊action view。

注意:儘管把操作視窗摺疊起來是可選的,但是,如果包含了SearchView對象,建議你始終把這個視窗摺疊起來,只有在需要的時候,由用戶選擇後才把它給展開。在提供了專用的“搜索”按鈕的設備上也要小心了,如果用戶按下了“搜索”按鈕,那麼也應該把這個搜索action view給展開,簡單的重寫Activity的onKeyUp()回調方法,監聽KEYCODE_SEARCH類型的按鍵事件,然後調用expandActionView()方法即可。

如果你需要根據操作視窗的可見性來更新你的Activity,那麼你可以定義一個OnActionExpandListener事件,並且用setOnActionExpandListener()方法來註冊這個事件,然後就能夠在操作視窗展開和摺疊時接受這個回調方法了,如代碼清單4-11所示:

複製代碼
@Override

public boolean onCreateOptionsMenu(Menu menu) {

    getMenuInflater().inflate(R.menu.options, menu);

    MenuItem menuItem = menu.findItem(R.id.actionItem);

    ...

 

    menuItem.setOnActionExpandListener(new OnActionExpandListener() {

        @Override

        public boolean onMenuItemActionCollapse(MenuItem item) {

            return true;          }

 

        @Override

        public boolean onMenuItemActionExpand(MenuItem item) {

            return true; 

        }

    });

}
複製代碼

 

代碼清單4-11

4.5 添加Action Provider

與action view類似,Action Provider(由ActionProvider類定義的)用一個定製的佈局代替一個action item,它還需要對所有這些item行爲的控制。當你在action bar中給一個菜單項聲明一個action item時,它不僅要一個定製的佈局來控制這個菜單項的外觀,而且當它顯示在溢出菜單中時,還要處理它的默認事件。無論是在action bar中還是在溢出菜單中,它都能夠提供一個子菜單。

例如,ActionProvider的擴展類ShareActionProvider,它通過在action bar中顯示一個有效的共享目標列表來方便共享操作。與使用傳統的調用ACTION_SEND類型Intent對象的action item不同,你能夠聲明一個ShareActionProvider對象來處理一個action item。這種action provider會保留一個帶有處理ACTION_SEND類型Intent對象的應用程序的下拉列表,即使這個菜單項顯示在溢出菜單中。所以當你使用像這樣的Action Provider時,你不必處理有關這個菜單項的用戶事件。

要給一個操作項聲明一個操作提供器,就要在菜單資源中對應的<item>元素中定義android:actionProviderClass屬性,提供器要使用完整的類名。如代碼清單4-12所示:

複製代碼
<?xml version="1.0" encoding="utf-8"?>

<menu xmlns:android="http://schemas.android.com/apk/res/android">

    <item android:id="@+id/menu_share"

          android:title="@string/share"

          android:showAsAction="ifRoom"

          android:actionProviderClass="android.widget.ShareActionProvider" />

    ...

</menu>
複製代碼

 

代碼清單4-12

在這個例子中,用ShareActionProvider類作爲action provider,在這裏,action provider需要菜單項的控制,並處理它們在action bar中的外觀和行爲以及在溢出菜單中的行爲。你必須依然給這個菜單項提供一個用於溢出菜單的文本標題。

儘管action provider提供了它在溢出菜單中顯示時所能執行的默認操作,但是Activity(或Fragment)也能夠通過處理來自onOptionsItemSelected()回調方法的點擊事件來重寫這個默認操作。如果你不在這個回調方法中處理點擊事件,那麼action provider會接收onPerformDefaultAction()回調來處理事件。但是,如果action provider提供了一個子菜單,那麼Activity將不會接收onOptionsItemSelected()回調,因爲子菜單的顯示替代了選擇時調用的默認菜單行爲。

4.5.1使用ShareActionProvider類

如果你想要在action bar中提供一個“共享”操作,以充分利用安裝在設備上的其他應用程序(如,把一張圖片共享給短短信或社交應用程序使用),那麼使用ShareActionProvider類是一個有效的方法,而不是添加一個調用ACTION_SEND類型Intent對象的action item。當你給一個action item使用ShareActionProvider類時,它會呈現一個帶有能夠處理ACTION_SEND類型Intent對象的應用程序的下拉列表(如圖4-8所示)。

 

圖4-8 Gallery應用截屏,用ShareActionProvider對象展開顯示共享目標。

創建子菜單的所有邏輯,包括共享目標的封裝、點擊事件的處理(包在溢出菜單中的項目顯示)等,都在ShareActionProvider類中實現了---你需要編寫的唯一的代碼是給對應的菜單項聲明action provider,並指定共享的Intent對象。

默認情況,ShareActionProvider對象會基於用戶的使用頻率來保留共享目標的排列順序。使用頻率高的目標應用程序會顯示在下來列表的上面,並且最常用的目標會作爲默認共享目標直接顯示在action bar。默認情況下,排序信息被保存在由DEFAULT_SHARE_HISTORY_FILE_NAME指定名稱的私有文件中。如果你只使用一種操作類型ShareActionProvider類或它的一個子類,那麼你應該繼續使用這個默認的歷史文件,而不需要做任何事情。但是,如果你使用了不同類型的多個操作的ShareActionProvider類或它的一個子類,那麼爲了保持它們自己的歷史,每種ShareActionProvider類都應該指定它們自己的歷史文件。給每種ShareActionProvider類指定不同的歷史文件,就要調用setShareHistoryFileName()方法,並且提供一個XML文件的名字(如,custom_share_history.xml)

注意:儘管ShareActionProvider類是基於使用頻率來排列共享目標的,但是這種行爲是可擴展的,並且ShareActionProvider類的擴展能夠基於歷史文件執行不同的行爲和排序。

要添加ShareActionProvider對象,只需簡單的給android.actionProviderClass屬性設定android.widget.ShareActionProvider屬性值就可以了。唯一要做的事情是定義你要用於共享的Intent對象,你必須先調用getActionProvider()方法來獲取跟菜單項匹配的ShareActionProvider對象,然後調用setShareIntent()方法。

如果對於共享的Intent對象的格式依賴於被選擇的菜單項,或其他在Activity生存週期內改變的變量,那麼你應該把ShareActionProvider對象保存在一個成員屬性裏,並在需要的時候調用setShareIntent()方法來更新它。如代碼清單4-13所示:

複製代碼
private ShareActionProvider mShareActionProvider;

...

 

@Override

public boolean onCreateOptionsMenu(Menu menu) {

    mShareActionProvider = (ShareActionProvider) menu.findItem(R.id.menu_share).getActionProvider();

    mShareActionProvider.setShareIntent(getDefaultShareIntent());

 

    return true;

}
複製代碼

 

代碼清單4-13

上例中ShareActionProvider對象處理所有的跟這個菜單項有關的用戶交互,並且不需要處理來自onOptionsItemSelected()回調方法的點擊事件。

4.5.2創建自定義的Action Provider

當你想要創建一個有動態行爲和在溢出菜單中有默認圖標的action view時,,繼承ActionProvider類來定義這些行爲是一個比好的的方案。創建自己的action provider,提供一個有組織的可重用的組件,而不是在Fragment或Activity的代碼中處理各種action item的變換和行爲。要創建自己的action provider,只需簡單的繼承ActionProvider類,並且實現合適的回調方法。你應該實現以下重要的回調方法:

ActionProvider()

這個構造器把應用程序的Context對象傳遞個操作提供器,你應該把它保存在一個成員變量中,以便其他的回調方法使用。

OnCreateActionView()

這是你給菜單項定義action view的地方。使用從構造器中接收的Context對象,獲取一個LayoutInflater對象的實例,並且用XML資源來填充action view,然後註冊事件監聽器。如代碼清單4-14所示:

複製代碼
public View onCreateActionView() {

    LayoutInflater layoutInflater = LayoutInflater.from(mContext);

    View view = layoutInflater.inflate(R.layout.action_provider, null);

    ImageButton button = (ImageButton) view.findViewById(R.id.button);

    button.setOnClickListener(new View.OnClickListener() {

        @Override

        public void onClick(View v) {

            // Do something...

        }

    });

    return view;

}
複製代碼

 

代碼清單4-14

onPerformDefaultAction()

在選中溢出菜單中的菜單時,系統會調用這個方法,並且action provider應該這對這個選中的菜單項執行默認的操作。但是,如果你的action provider提供了一個子菜單,即使是溢出菜單中一個菜單項的子菜單,那麼也要通過onPrepareSubMenu()回調方法來顯示子菜單。這樣onPerformDefaultAction()在子菜單顯示時就不會被調用。注意:實現了onOptionsItemSelected()回調方法的Activity或Frament對象能夠通過處理item-selected事件(並且返回true)來覆蓋action provider的默認行爲,這種情況下,系統不會調用onPerformDefaultAction()回調方法。

4.6 添加導航標籤

當你想要在一個Activity中提供導航標籤時,使用action bar的選項標籤是一個非常好的選擇(而不是使用TabWidget類),因爲系統會調整action bar選項標籤來適應不同尺寸的屏幕的需要---在屏幕足夠寬的時候,導航選項標籤會被放到主action bar中;當屏幕太窄的時候,選項標籤會被放到一個分離的橫條中,如圖4-9和圖4-10所示。

 

圖4-9 android3.0下Gallery應用程序中的操作欄選項標籤的截圖

圖4-10 在窄屏設備上被堆放在操作欄中的選項標籤的截屏

要使用選項標籤在Fragmengt之間切換,你必須在每次選擇一個選項標籤時執行一個Fragment事務處理。如果你不熟悉如何使用FragmentTransaction對象來改變Fragment,請閱讀先前Fragment章節。首先,你的佈局必須包含一個用於放置跟每個Fragment對象關聯的選項標籤的ViewGroup對象。並且要確保這個ViewGroup對象有一個資源ID,以便你能夠在選項標籤的切換代碼中能夠引用它。另外,如果選項標籤的內容填充在Activity的佈局中(不包括action bar),那麼Activity不需要任何佈局(你甚至不需要調用setContentView()方法)。相反,你能夠把每個Fragment對象放到默認的根ViewGroup對象中,你能夠用android.R.id.content ID來引用這個ViewGroup對象(在Fragment執行事務期間,你能夠在下面的示例代碼中看到如何使用這個ID的。

決定了Fragment對象在佈局中的顯示位置後,添加選項標籤的基本過程如下:

1.實現ActionBar.TabListener接口。這個接口中回調方法會響應選項標籤上的用戶事件,以便你能夠切換Fragment對象;

2.對於每個要添加的選項標籤,都要實例化一個ActionBar.Tab對象,並且調用setTabListener()方法設置ActionBar.Tab對象的事件監聽器。還可以用setText()或setIcon()方法來設置選項標籤的標題或圖標。

3.通過調用addTab()方法,把每個選項標籤添加到操作欄。

在查看ActionBar.TabListener接口時,注意到回調方法只提供了被選擇的ActionBar.Tab對象和執行Fragment事務處理的FragmentTransaction對象---沒有說明任何有關切換什麼Fragment。因此。你必須定義自己的每個ActionBar.Tab之間的關聯,以及ActionBar.Tab所代表的適合的Fragment對象(爲了執行合適的Fragment事務處理)。依賴你的設計,會有幾種不同的方法來定義這種關聯。在下面的例子中,ActionBar.TabListener接口的實現提供了一個構造器,這樣每個新的選項標籤都會使用它自己的監聽器實例。每個監聽器實例都定義了幾個在對應Fragment對象上執行事務處理時必須的幾個成員變量。例如,以下示例是ActionBar.TabListener接口的一種實現,在這個實現中,每個選項標籤都使用了它自己的監聽器實例,如代碼清單4-15所示:

複製代碼
public static class TabListener<T extends Fragment> implements ActionBar.TabListener {

    private Fragment mFragment;

    private final Activity mActivity;

    private final String mTag;

    private final Class<T> mClass;

    public TabListener(Activity activity, String tag, Class<T> clz) {

        mActivity = activity;

        mTag = tag;

        mClass = clz;

    }

 

    public void onTabSelected(Tab tab, FragmentTransaction ft) {   

        if (mFragment == null) {

            mFragment = Fragment.instantiate(mActivity, mClass.getName());

            ft.add(android.R.id.content, mFragment, mTag);

        } else {

            ft.attach(mFragment);

        }

    }

 

    public void onTabUnselected(Tab tab, FragmentTransaction ft) {

        if (mFragment != null) {

            ft.detach(mFragment);

        }

    }

 

    public void onTabReselected(Tab tab, FragmentTransaction ft) {

    }

}
複製代碼

 

代碼清單4-15

注意:針對每個回調中的Fragment事務處理,你都不必調用FragmentTransaction.commit()方法---系統會調用這個方法,並且如果你自己調用了這個方法,有可能會拋出一個異常。你也不能把這些Fragment事務處理添加到後臺堆棧中。在這個例子中,當對應的選項標籤被選擇時,監聽器只是簡單的把一個Fragment對象附加(attach()方法)到Activity佈局上---或者,如果沒有實例化,就會創建這個Fragment對象,並且把它添加(add()方法)到佈局中(android.R.id.content ViewGroup的一個子類),當這個選項標籤解除選擇時,對應的Fragment對象也會被解除與佈局的依附關係。

ActionBar.TabListener的實現做了大量的工作,剩下的事情就是創建每個ActionBar.Tab對象並把它添加到ActionBar對象中,另外,你必須調用setNavigationMode(NAVIGATION_MODE_TABS)方法來讓選項標籤可見。如果選項標籤的標題實際指示了當前的View對象,你也可以通過調用setDisplayShowTitleEnabled(false)方法來禁用Activity的標題。

例如,下面的代碼使用上面定義的監聽器在action bar中添加了兩個選項標籤。如代碼清單4-16所示:

複製代碼
@Override

protected void onCreate(Bundle savedInstanceState) {

    super.onCreate(savedInstanceState);

    ActionBar actionBar = getActionBar();

    actionBar.setNavigationMode(ActionBar.NAVIGATION_MODE_TABS);

    actionBar.setDisplayShowTitleEnabled(false);

 

    Tab tab = actionBar.newTab()

            .setText(R.string.artist)

            .setTabListener(new TabListener<ArtistFragment>(

                    this, "artist", ArtistFragment.class));

    actionBar.addTab(tab);

 

    tab = actionBar.newTab()

        .setText(R.string.album)

        .setTabListener(new TabListener<AlbumFragment>(

                this, "album", AlbumFragment.class));

    actionBar.addTab(tab);

}
複製代碼

 

代碼清單4-16

如果Activity終止了,那麼你應該保存當前選擇的選項標籤的狀態,以便當用戶再次返回時,你能夠打開合適的選項標籤。在保存狀態的時刻,你能夠用getSelectedNavigationIndex()方法查詢當前的被選擇的選項標籤。這個方法返回被選擇的選項標籤的索引位置。

注意:在某些情況下,Android系統會把action bar選項標籤作爲一個下拉列表來顯示,以便確保操作欄的最優化顯示。並且保存每個Fragment所必須的狀態是至關重要的,因爲當用戶用選項標籤在Fragment對象間切換時,它會查看Fragment在離開時樣子。

4.7 添加下拉式導航

作爲Activity內部的另一種導航(或過濾)模式,操作欄提供了內置的下拉列表。下拉列表能夠提供Activity中內容的不同排序模式。

啓用下拉式導航的基本過程如下:

1. 創建一個給下拉提供可選項目的列表,以及描畫列表項目時所使用的佈局;

2. 實現ActionBar.OnNavigationListener回調,在這個回調中定義當用戶選擇列表中一個項目時所發生的行爲;

3. 用setNavigationMode()方法該操作欄啓用導航模式,如代碼清單4-17所示:

ActionBar actionBar = getActionBar();

actionBar.setNavigationMode(ActionBar.NAVIGATION_MODE_LIST);

 

代碼清單4-17

注意: 你應該在activity的onCreate()方法中執行以上代碼

4. 用setListNavigationCallbacks()方法給下拉列表設置回調方法,如代碼清單4-18所示:

actionBar.setListNavigationCallbacks(mSpinnerAdapter, mNavigationCallback);

 

代碼清單4-18

這個方法需要獲得SpinnerAdapter和ActionBar.OnNavigationListener對象。

以上是基本的設置。當然實現了SpinnerAdapter和ActionBar.OnNavigationListener就已經完成了大部分工作。有許多方法能實現這些定義下拉列表的功能並且實現,這已經超出了本章的範圍,就不贅述了。

4.8 Action Bar的樣式(Sytle)

如果你對應用程序中的可視構件進行了定製化的設計,那麼你可能也會要對action bar做一些重新設計,以便跟應用程序的設計匹配。要這樣做的話,需要使用Android的樣式與主題框架中的一些特殊的樣式屬性來重新設置操作欄的樣式。

注意:改變外觀的背景圖片依賴與當前按鈕的狀態(選擇、按下、解除選擇),因此需要使用state list drawable。還要確保使用NinePatch類型的drawable資源,以便允許圖片的拉伸。NinePatch類型的圖片應該比40像素高30像素寬的圖片要小(mdpi下)。

4.8.1普通的外觀

android:windowActionBarOverlay

這個屬性聲明瞭操作欄是否應該覆蓋Activity佈局,而不是相對Activity的佈局位置的偏移。這個屬性的默認值是false。通常,在屏幕上,action bar需要它自己的空間,並且把剩下的空間用來填充Activity的佈局。當action bar是覆蓋模式時,Activity會使用所有的有效空間,系統會在Activity的上面繪製action bar。如果你想要在action bar隱藏和顯示時,佈局中的內容保持固定的尺寸好位置,那麼這種覆蓋模式是有用的。你也可能只是爲了顯示效果來使用它,因爲你可以給action bar設置半透明的背景,以便用戶依然能夠看到action bar背後的Activity佈局。

注意:默認情況下,Holo主題會用半透明背景來繪製action bar。但是,你能夠用自己的樣式來修改它,並且默認的情況下,DeviceDefault主題在不同的設備上可能使用不透明的背景。

覆蓋模式被啓用時,Activity佈局不會感知到action bar覆蓋在它的上面,因此,在action bar覆蓋的區域,最好不要放置一些重要的信息或UI組件。適當的情況下,你能夠引用平臺的actionBarSize值來決定操作欄的高度,例如,在XML佈局文件中引用這個值,如代碼清單4-19所示:

<SomeView

    ...

    android:layout_marginTop="?android:attr/actionBarSize" /> 

 

代碼清單4-19

你還能夠用getHeight()方法在運行時獲取action bar的高度。如果在Activity生存週期的早期調用這個方法,那麼在調用時所反映的action bar的高度可能不包括被堆放的action bar(因爲導航選項標籤)。要看如何在運行時判斷action bar總的高度,請看simple中Honeycomb Gallery的TitlesFragment類

4.8.2 Action Items

android:actionButtonStyle

給操作項按鈕定義樣式資源。

android:actionBarItemBackground

給每個操作項的背景定義可描畫資源(被添加在API Level 14中)。

android:itemBackground

給每個溢出菜單項的背景定義可描畫資源。

android:actionBarDivider

給操作項之間的分隔線定義可描畫資源(被添加在API Level 14中)

android:actionMenuTextColor

給顯示在操作項中文本定義顏色。

android:actionMenuTextAppearance

給顯示在操作項中文本定義樣式資源。

android:actionBarWidgetThem

給作爲操作視窗被填充到操作欄中的可視構件定義主題資源(被添加在API Level 14中)。

4.8.3導航標籤

android:actionBarTabStyle

給操作欄中的選項標籤定義樣式資源。

android:actionBarTabBarStyle

給顯示在導航選項標籤下方的細條定義樣式資源。

android:actionBarTabTextStyle

給導航選項標籤中的文本定義樣式資源。

4.8.4下拉列表

android:actionDropDownStyle

給下拉導航列表定義樣式(如背景和文本樣式)。如,下例XML文件中給action bar定義了一些定製的樣式,如代碼清單4-20所示:

複製代碼
<?xml version="1.0" encoding="utf-8"?>

<resources>

    <!--應用程序或activity應用的主題-->

    <style name="CustomActivityTheme" parent="@android:style/Theme.Holo">

        <item name="android:actionBarTabTextStyle">@style/CustomTabTextStyle</item>

        <item name="android:actionBarDivider">@drawable/ab_divider</item>

        <item name="android:actionBarItemBackground">@drawable/ab_item_background</item>

    </style>

 

    <!--  action bar標籤文本樣式-->

    <style name="CustomTabTextStyle" parent="@android:style/TextAppearance.Holo">

        <item name="android:textColor">#2456c2</item>

    </style>

</resources>
複製代碼

 

代碼清單4-20

注意:一定要在<style>標籤中聲明一個父主題,這樣定製的主題可以繼承所有沒有明確聲明的樣式。在修改action bar樣式時,使用父主題是至關重要的,它會讓你能夠簡單的覆寫你想要改變的action bar樣式,而不影響你不想修改的樣式(如文本的外觀或操作項的邊緣)。

你能夠在清單文件中把定製的主題應用到整個應用程序或一個單獨的Activity對象,如代碼清單4-21所示:

<application android:theme="@style/CustomActivityTheme" ... />

 

代碼清單4-21

4.8.5高級樣式

如果需要比上述屬性更高級的樣式,可以在Activity的主題中包含android:actionBarStyle和android:actionBarSplitStyle屬性。這兩個屬性的每一個都指定了另一種能夠給action bar定義各種屬性的樣式,包括帶有android:background、android:backgroundSplit、android:backgroundStacked屬性的不同背景。如果要覆蓋這些action bar樣式,就要確保定義一個像Widget.Holo.ActionBar這樣的父action bar的樣式。

例如,如果要改變操作欄背景,你可以使用下列樣式,如代碼清單4-22所示:

複製代碼
<?xml version="1.0" encoding="utf-8"?>

<resources>

    <!-- 應用程序或activity應用的主題 -->

    <style name="CustomActivityTheme" parent="@android:style/Theme.Holo">

        <item name="android:actionBarStyle">@style/MyActionBar</item>

         </style>

 

    <!-- action bar backgrounds 樣式-->

    <style name="MyActionBar" parent="@android:style/Widget.Holo.ActionBar">

        <item name="android:background">@drawable/ab_background</item>

        <item name="android:backgroundStacked">@drawable/ab_background</item>

        <item name="android:backgroundSplit">@drawable/ab_split_background</item>

    </style>

</resources>
複製代碼

 轉自:http://www.cnblogs.com/tianjian/archive/2012/11/27/2791728.html

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