Android UI開發第二十四篇——Action Bar

 

Android UI開發第二十四篇——Action Bar 

標籤: ActionBarandroidfragmentmenuhtml

2012-10-31 16:11 143916人閱讀 評論(29) 收藏 舉報java

 分類:android

 

上圖中:api

  1. logo安全

  2. title網絡

  3. iconapp

目錄(?)[+]框架


             Action bar是一個標識應用程序和用戶位置的窗口功能,而且給用戶提供操做和導航模式。在大多數的狀況下,當你須要突出展示用戶行爲或全局導航的activity中使用action bar,由於action bar可以使應用程序給用戶提供一致的界面,而且系統可以很好根據不一樣的屏幕配置來適應操做欄的外觀。你可以用ActionBar的對象的API來控制操做欄的行爲和可見性,這些API被添加在Android3.0(API 級別 11)中。ide

      Action bar的主要目的是:
svg

        1.  提供一個用於識別應用程序的標示和用戶的位置的專用空間。

         這個空間的左邊是應用的圖標或logo,以及Activity的標題。可是,若是是像當前選擇的標籤這樣的標識當前View對象的導航標籤,你能夠選擇刪除Activity的標題。

        2.  在不一樣的應用程序之間提供一致的導航和視覺體驗。

        Action bar提供了用於Fragment間切換的內置導航標籤。它還提供了一個用於替換導航模式或優化當前視覺效果(如按照不一樣條件排序的列表)的下拉列表。

        3.  突出Activity的關鍵操做(如「搜索」、「建立」、「共享」等),而且在可預見的方法內給用戶提供快捷的訪問。

       對於關鍵的用戶操做,你可以經過把選項菜單項做爲操做項直接放到操做欄中,從而提供快捷的訪問。操做項目還能提供一個操做窗口,這個窗口給更直接的操做行爲提供一個嵌入的窗口部件。沒有改進成操做項的菜單項在溢出菜單中仍是有效的,用戶既可使用設備上的菜單按鈕(設備上有按鈕的時候),也可使用操做欄中的溢出菜單按鈕(當設備上不包含菜單按鈕時)來顯示這些操做項目。

       上面的總結一下:Action bar就是替換3.0之前的tittle bar和menu。

             

        圖1. Honeycomb Gallery應用中的操做欄,從左邊開始,依次是logo、導航選項標籤和操做項(在右邊插入的一個懸浮菜單按鈕)。

         Note: If you're looking for information about the contextual action bar for displaying contextual action items, see the Menu guide.

        Action Bar Design   For design guidelines, read Android Design's Action Bar guide.


添加Action Bar

       從Android3.0(API級別 11)開始,Action bar被包含在全部的使用Theme.Hole主題的Activity(或者是這些Activity的子類)中,當targetSdkVersion或minSdkVersion屬性被設置爲「11」或更大的數值是,這個主題是默認的主題一。如:

[html] view plain copy

 print?在CODE上查看代碼片派生到個人代碼片

  1. <manifest ... >  

  2.     <uses-sdk android:minSdkVersion="4"  

  3.               android:targetSdkVersion="11" />  

  4.     ...  

  5. </manifest>  


       在這個例子中,應用程序要求最小的API版本級別是4(Android 1.6),可是它還要求了目標API版本級別是11(Android 3.0)。這樣,當應用程序運行在Android3.0或更高的版本上時,系統就會給每一個Activity應用holographic  主題,這樣,每一個Activity就會包含Action bar。

        若是你想使用ActionBar API來進行添加導航模式和修改操做欄樣式的操做,你應該把minSdkVersion屬性設置爲「11」或更大的值。有一些方法可使你的應用支持更舊的Android版本,同時在API等級爲11或更高的API等級的機器的使你的應用支持一些Action bar apis。爲了保持後向兼容,請參考邊框內的內容(邊框內容以下)。

Remaining backward-compatible

If you want to provide an action bar in your application and remain compatible with versions of Android older than 3.0, you need to create the action bar in your activity's layout (because theActionBar class is not available on older versions).

To help you, the Action Bar Compatibility sample app provides an API layer and action bar layout that allows your app to use some of theActionBar APIs and also support older versions of Android by replacing the traditional title bar with a custom action bar layout.

刪除Action bar

      若是你不想要Action bar,把Activity的主題設置爲Theme.Holo.NoActionBar就能夠了,如:

[html] view plain copy

 print?在CODE上查看代碼片派生到個人代碼片

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

         或者使用Action bar的 hide()方法,以下:

[java] view plain copy

 print?在CODE上查看代碼片派生到個人代碼片

  1. ActionBar actionBar = getActionBar();  

  2. actionBar.hide();  

       當Action bar隱藏時,系統會調整你的Activity來填充當前有效的屏幕空間。你可以使用show()方法來再次顯示操做欄。

      在隱藏和刪除Action bar時,要小心爲了適應被Action bar佔用的空間而致使的Activity的從新佈局。若是你的Activity有規律的隱藏和顯示Action bar,你可能想要使用覆蓋模式。覆蓋模式在Activity的頂部描畫操做欄,而不是在它們所擁有的屏幕的區域。這樣,在Action bar隱藏和從新顯示時,你的佈局保持不變。要使用覆蓋模式,就要給Activity建立一個主題,而且把android:windowActionBarOverlay屬性設置爲true。

       提示:若是你有一個刪除了Action bar的定製化的Activity主題,它把android:windowActionBar樣式屬性設置爲false。可是,若是你使用了刪除Action bar的一個主題,那麼,建立窗口將不容許Action bar再顯示,所以,你不能在之後給這個Activity添加Action bar---由於getActionBar()方法將返回null。


添加操做項

       有些時候,你可能想要讓用戶直接訪問選項菜單中的一個項目,所以你要把應該在Action bar中顯示的菜單項做爲一個操做項來聲明。操做項可以可以包含一個圖標或文本標題。若是一個菜單項不做爲一個操做項顯示,那麼系統就會把它放到懸浮菜單中。懸浮菜單既能夠經過設備的Menu按鈕來顯示,也能夠在Action bar中一個額外的按鈕來顯示。

       當Activity首次啓動時,系統會調用onCreateOptionsMenu()方法給你的Activity組裝Action bar和懸浮菜單。在這個回調方法中應該加載在XML文件中定義的菜單項資源,如:

[java] view plain copy

 print?在CODE上查看代碼片派生到個人代碼片

  1. @Override  

  2. public boolean onCreateOptionsMenu(Menu menu) {  

  3.     MenuInflater inflater = getMenuInflater();  

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

  5.     return true;  

  6. }  


             

         圖2. 帶有圖標和文本標題的兩個操做項,和懸浮菜單按鈕。

       在XML文件中,你可以經過給<item>元素聲明android:showAsAction=」ifRoom」屬性,請求把一個菜單項做爲一個操做項來顯示。用這種方式,只在有有效的空間時,菜單項才能顯示在Action bar中。若是沒有足夠的空間,這個菜單項會顯示在懸浮菜單中。

        若是你的菜單項支持標題和圖標---帶有android:title和android:icon屬性---那麼默認狀況下,操做項僅顯示圖標。若是你要顯示文本標題,就要給android:showAsAction屬性添加withText設置,如:

  

[html] view plain copy

 print?在CODE上查看代碼片派生到個人代碼片

  1. <?xml version="1.0" encoding="utf-8"?>  

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

  3.     <item android:id="@+id/menu_save"  

  4.           android:icon="@drawable/ic_menu_save"  

  5.           android:title="@string/menu_save"  

  6.           android:showAsAction="ifRoom|withText" />  

  7. </menu>  

提示:withText值示意Action bar要顯示文本標題。Action bar會盡量的顯示這個標題,可是,若是圖標有效而且受到Action bar空間的限制,文本標題有可能顯示不全。

當用戶選擇了一個操做項時,Activity會接收一個onOptionsItemSelected()的回調,要把android:id屬性支持的ID傳遞給這個方法。

給每一個菜單項定義android:title屬性是相當重要的,即便你沒有給操做項聲明標題。緣由以下:

1.  若是Action bar中沒有足夠的空間來顯示操做項,那麼菜單項就會顯示在懸浮菜單中,並僅顯示標題;

2.  屏幕閱讀器要給視障用戶朗讀菜單項標題;

3.  若是僅用圖標來顯示操做項,那麼,用戶可以長按這個項目,用操做項的標題來顯示提示信息。

注意:若是你添加源於Fragment對象的菜單項,那麼經過Fragment類的onCreateOptionsMenu onCreateOptionsMenu回調方法,當用戶選擇其中一個Fragment菜單項時,系統會對用那個Fragment對象對應的onOptionsItemSelected()方法。可是,Activity有機會首先處理這個事件,由於系統在調用對應的Fragment對象的onOptionsItemSelected()方法以前會調用Activity的相同的回調方法。

       你也可以聲明一個菜單項,讓它始終做爲操做項來顯示,而不是在空間不足時就放到懸浮菜單中。大多數狀況下,你不該該使用always屬性值來強制一個菜單項始終顯示在操做欄中,可是,當提供了一個不給懸浮菜單提供默認操做的操做窗口時,你就須要始終顯示一個菜單項。可是要警戒,太多的操做項會建立一個混亂的UI,而且會致使窄屏設備上的佈局問題。最好的方法是使用ifRoom屬性值,它容許系統在操做欄空間不足的時候,把菜單項移到懸浮菜單中。

選擇操做項:

       經過評估一些關鍵的特性,你應該仔細的選擇選項菜單中的那些菜單項應該做爲操做項來顯示,一般,每一個操做項應該至少知足下列特性之一:

        1.  常用:用戶百分之七十以上的訪問都須要使用的操做,或者是要連續的屢次使用的操做。

        2.  重要:它是一個用戶可以很容易找到的操做,即便它不是常常性的操做,也須要用戶在須要的時候可以輕易的找到它,並執行。

             如,Wi-Fi設置中的添加網絡等。

        3.  典型:它是一些相似應用程序的操做欄中提供的典型操做,所以,用戶都指望在操做欄中可以找到它。

            如,電子郵件或社交應用程序中的「刷新」操做。

        若是你想要把四個以上的菜單項調整爲操做項,那麼你就應該認真考慮一下他們相對的重要性級別,而且嘗試不要超過四個以上的操做項設置(而且還有使用「ifRoom」屬性值的設置,容許系統在遇到空間受限的比較小的屏幕的時候,可以把靠後的操做項放到懸浮菜單中)。即便在一些寬屏設備上,空間充足,你也不該該建立不少操做項,這樣會擾亂UI的佈局,並且更像一個桌面工具欄,所以要保持最小數量的操做項。

       另外,如下操做應該永遠不要做爲操做項來顯示:設置、幫助、意見反饋、或相似的操做。要把它們始終保留在懸浮菜單中。

       注意:不是全部的設備都給檢索提供了專有的硬件按鈕,所以,若是是你應用程序中的一個重要功能,它應該始終做爲一個操做項來顯示(並且一般要把放到第一項的位置,尤爲是操做窗口中提供這個操做的時候)。

使用分離式操做欄

        當你的應用程序正在Android4.0(API 級別 14)或以上的版本上運行,那麼還有一種叫作「分隔操做欄」的額外模式對action bar有效。當你啓用分隔操做欄模式時,在屏幕的底部會顯示一個獨立的橫條,用於顯示Activity在窄屏設備(如豎屏手機)上運行時的全部操做項。

       把action bar分隔成獨立的操做項,確保在窄屏設備上有合適的空間來顯示全部的操做項,同時把導航條和標題元素留在頂部。

       要啓用分離式操做欄,只需簡單的在<application>或<activity>元素中添加uiOptions=」splitActionBarWhenNarrow」屬性設置就能夠了。

       要注意,Android會基於當前屏幕的尺寸用各類方式來調整操做欄的外觀。使用分離式操做欄只是你可以啓用的容許操做欄針對不一樣屏幕尺寸來進一步優化用戶體驗的選項之一。你還能夠容許操做欄把導航選項標籤摺疊到主操做欄中,若是你在操做欄中使用導航選項標籤,那麼一旦操做項在窄屏設備上被分離,這些導航選項標籤就可能填充到主操做欄中,而不是被分離到堆疊起來的操做欄。尤爲是若是你禁用了操做欄的圖標和標題(用setDisplayShowHomeEnabled(false)setDisplayShowTitleEnabled(false)方法),那麼導航選項標籤就會摺疊到主操做欄中,以下圖3中第二個設備的顯示:

                       

圖3. 左側是帶有導航選項標籤的分離式操做欄,右側是禁用了應用圖標和標題的分離式操做欄。

注意:儘管android:uiOptions屬性在Android4.0(API 級別 14)中才被添加,可是爲了保持跟Android的低版本的兼容性,即便你的minSdkVersion屬性值小於14,那麼你的應用程序也能夠安全的包含android:uiOptions屬性。在舊版本上運行時,由於系統不能理解這個屬性,因此只是簡單的忽略了這個XML屬性。在你的清單文件中包含這個屬性的惟一條件是,你必須在支持API級別14或更高以上版本的平臺上編譯你的應用程序。爲了保持兼容性,你不能在你的應用程序代碼中使用由minSdkVersion屬性聲明的版本所不支持的API,只有XML屬性才能被舊的平臺版本安全的忽略。

導航欄使用應用圖標

       默認狀況下,應用程序圖標顯示在操做欄的左邊。你可以把這個圖標當作操做項來使用。應用程序應該在這個圖標上響應如下兩個操做之一:

       1.  返回應用程序的「主」Activity;

       2.  嚮應用程序上級頁面導航。

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

       若是你要經過應用程序圖標的響應來返回主Activity,那麼就應該在Itent對象中包括FLAG_ACTIVITY_CLEAR_TOP標識。用這個標記,若是你要啓動的Activity在當前任務中已經存在,那麼,堆棧中這個Activity之上的全部的Activity都有被銷燬,而且把這個Activity顯示給用戶。添加這個標識每每是重要的,由於返回主Activity至關與一個回退的動做,所以一般不該該再建立一個新的主Activity的實例,不然,最終可能會在當前任務中產生一個很長的擁有多個主Activity的堆棧。

例如,下例的onOptionsItemSelected()方法實現了返回應用程序的主Activity的操做:

[java] view plain copy

 print?在CODE上查看代碼片派生到個人代碼片

  1. @Override  

  2. public boolean onOptionsItemSelected(MenuItem item) {  

  3.     switch (item.getItemId()) {  

  4.         case android.R.id.home:  

  5.             // app icon in action bar clicked; go home  

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

  7.             intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);  

  8.             startActivity(intent);  

  9.             return true;  

  10.         default:  

  11.             return super.onOptionsItemSelected(item);  

  12.     }  

  13. }  

       在用戶從另外一個應用程序進入當前Activity的狀況下,你可能還想要添加FLAG_ACTIVITY_NEW_TASK標識。這個標識確保在用戶返回主頁或上級頁面時,新的Activity不會被添加到當前的任務中,而是在屬於你本身的應用程序的任務中啓動。例如,若是用戶經過被另外一個應用程序調用的Intent對象啓動了你的應用程序中的一個Activity,那麼選擇操做欄圖標來返回主頁或上級頁面時,FLAG_ACTIVITY_CLEAR_TOP標識會在屬於你的應用程序的任務中啓動這個Activity(不是當前任務)。系統既能夠用這個新的Activity作根Activity來啓動一個新的任務,也能夠把存在後臺的擁有這個Activity實例的一個既存任務帶到前臺來,而且目標Activity會接受onNewIntent()回調。所以,若是你的Activity要接收另外一個應用程序的Intent對象,那麼一般應該給這個Intent對象添加FLAG_ACTIVITY_NEW_TASK標識,如:

[java] view plain copy

 print?在CODE上查看代碼片派生到個人代碼片

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


注意:若是你要使用應用圖標來返回主頁,要注意從Android4.0(API 級別 14)開始,必須經過調用setHomeButtonEnabled(true)方法確保這個圖標可以做爲一個操做項(在之前的版本,默認狀況下,這個圖標就可以做爲一個操做項)。

嚮應用程序上級頁面導航

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

          

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

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

            

       可是,若是在編輯完郵件以後,想要停留在Email應用程序中,那麼向上導航就容許你把用戶導航到Email應用程序中編輯郵件頁面的上級頁面,而不是返回到前一個Activity。圖6演示了這種場景,在這個場景中,用戶進入到Email應用程序後,不是按回退按鈕,而是按操做欄圖標來向上導航。

       

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

         要是應用程序圖標可以向上導航,就要在你的ActionBar中調用SetDisplayHomeAsUpEnabledtrue(true)方法。

[java] view plain copy

 print?在CODE上查看代碼片派生到個人代碼片

  1. protected void onCreate(Bundle savedInstanceState) {  

  2.     super.onCreate(savedInstanceState);  

  3.   

  4.     setContentView(R.layout.main);  

  5.     ActionBar actionBar = getActionBar();  

  6.     actionBar.setDisplayHomeAsUpEnabled(true);  

  7.     ...  

  8. }  


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

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

注意:若是有不少用戶可以到達應用程序中當前Activity的路徑,那麼,向上圖標應該沿着當前Activity的實際啓動路徑逐步的向會導航。

添加操做視窗

       操做視窗是做爲操做項目按鈕的替代品顯示在操做欄中的一個可視構件。例如,若是你有一個用於搜索的可選菜單項,你能夠用SearchView類來替代操做欄上的搜索按鈕,如圖7所示:

             

       圖7. 摺疊(上)和展開(下)的搜索視窗的操做欄

       要個菜單資源中的一個項目聲明一個操做視窗,你既可使用android:actionLayout屬性也android:actionViewClass屬性來分別指定一個佈局資源或要使用的可視構件類。例如:

[html] view plain copy

 print?在CODE上查看代碼片派生到個人代碼片

  1. <?xml version="1.0" encoding="utf-8"?>  

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

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

  4.           android:title="@string/menu_search"  

  5.           android:icon="@drawable/ic_menu_search"  

  6.           android:showAsAction="ifRoom|collapseActionView"  

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

  8. </menu>  

        android:showAsAction屬性也可包含「collapseActionView」屬性值,這個值是可選的,而且聲明瞭這個操做視窗應該被摺疊到一個按鈕中,當用戶選擇這個按鈕時,這個操做視窗展開。不然,這個操做視窗在默認的狀況下是可見的,而且即使在用於不適用的時候,也要佔據操做欄的有效空間。

       若是須要給操做視窗添加一些事件,那麼就須要在onCreateOptionsMenu()回調執行期間作這件事。你可以經過調用帶有菜單項ID的findItem()方法來獲取菜單項,而後再調用getActionView()方操做視窗中的元素。例如,使用如下方法獲取上例中的搜索視窗構件。

[java] view plain copy

 print?在CODE上查看代碼片派生到個人代碼片

  1. @Override  

  2. public boolean onCreateOptionsMenu(Menu menu) {  

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

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

  5.     // Configure the search info and add any event listeners  

  6.     ...  

  7.     return super.onCreateOptionsMenu(menu);  

  8. }  

處理可摺疊的操做視窗

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

        由於在用戶選擇這個項目時,系統會展開這個操做視窗,因此你沒必要要在onOptionsItemSelected()回調方法中響應這個菜單項。在用戶選擇這個菜單項時,系統會依然調用onOptionsItemSelected()方法,可是除非你在方法中返回了true(指示你已經替代系統處理了這個事件),不然系統會始終展開這個操做視窗。

       當用戶選擇了操做欄中的「向上」圖標或按下了回退按鈕時,系統也會把操做視窗摺疊起來。

若是須要,你可以在代碼中經過在expandActionView()和collapseActionView()方法來展開或摺疊操做視窗。

       注意:儘管把操做視窗摺疊起來是可選的,可是,若是包含了SearchView對象,咱們推薦你始終把這個視窗摺疊起來,只有在須要的時候,由用戶選擇後才把它給展開。在提供了專用的「搜索」按鈕的設備上也要當心了,若是用戶按下了「搜索」按鈕,那麼也應該把這個搜索視窗給展開,簡單的重寫Activity的onKeyUp()回調方法,監聽KEYCODE_SEARCH類型的按鍵事件,而後調用expandActionView()方法,就能夠把操做視窗給展開。

若是你須要根據操做視窗的可見性來更新你的Activity,那麼你能夠定義一個OnActionExpandListener事件,而且用setOnActionExpandListener()方法來註冊這個事件,而後就可以在操做視窗展開和摺疊時接受這個回調方法了,如:

[java] view plain copy

 print?在CODE上查看代碼片派生到個人代碼片

  1. @Override  

  2. public boolean onCreateOptionsMenu(Menu menu) {  

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

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

  5.     ...  

  6.   

  7.     menuItem.setOnActionExpandListener(new OnActionExpandListener() {  

  8.         @Override  

  9.         public boolean onMenuItemActionCollapse(MenuItem item) {  

  10.             // Do something when collapsed  

  11.             return true;  // Return true to collapse action view  

  12.         }  

  13.   

  14.         @Override  

  15.         public boolean onMenuItemActionExpand(MenuItem item) {  

  16.             // Do something when expanded  

  17.             return true;  // Return true to expand action view  

  18.         }  

  19.     });  

  20. }  


添加一個操做提供器

       與操做視窗相似,操做提供器(由ActionProvider類定義的)用一個定製的佈局代替一個操做項目,它還須要對全部這些項目行爲的控制。當你在操做欄中給一個菜單項聲明一個操做項目時,它不只要一個定製的佈局來控制這個菜單項的外觀,並且當它在顯示在溢出菜單中時,還要處理它的默認事件。不管是在操做欄中仍是在溢出菜單中,它都可以提供一個子菜單。

       例如,ActionProvider的擴展類ShareActionProvider,它經過在操做欄中顯示一個有效的共享目標列表來方便共享操做。與使用傳統的調用ACTION_SEND類型Intent對象的操做項不一樣,你可以聲明一個ShareActionProvider對象來處理一個操做項。這種操做提供器會保留一個帶有處理ACTION_SEND類型Intent對象的應用程序的下拉列表,即便這個菜單項顯示在溢出菜單中。所以,當你使用像這樣的操做提供器時,你沒必要處理有關這個菜單項的用戶事件。

要給一個操做項聲明一個操做提供器,就要在菜單資源中對應的<item>元素中定義android:actionProviderClass屬性,提供器要使用完整的類名。例如:

[html] view plain copy

 print?在CODE上查看代碼片派生到個人代碼片

  1. <?xml version="1.0" encoding="utf-8"?>  

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

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

  4.           android:title="@string/share"  

  5.           android:showAsAction="ifRoom"  

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

  7.     ...  

  8. </menu>  


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

儘管操做提供器提供了它在溢出菜單中顯示時所能執行的默認操做,可是Activity(或Fragment)也可以經過處理來自onOptionsItemSelected()回調方法的點擊事件來重寫這個默認操做。若是你不在這個回調方法中處理點擊事件,那麼操做提供器會接收onPerformDefaultAction()回調來處理事件。可是,若是操做提供器提供了一個子菜單,那麼Activity將不會接收onOptionsItemSelected()回調,由於子菜單的顯示替代了選擇時調用的默認菜單行爲。

使用ShareActionProvider類

       若是你想要在操做欄中提供一個「共享」操做,以充分利用安裝在設備上的其餘應用程序(如,把一張圖片共享給消息或社交應用程序使用),那麼使用ShareActionProvider類是一個有效的方法,而不是添加一個調用ACTION_SEND類型Intent對象的操做項。當你給一個操做項使用ShareActionProvider類時,它會呈現一個帶有可以處理ACTION_SEND類型Intent對象的應用程序的下拉列表(如圖8所示)。

                

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

        建立子菜單的全部邏輯,包括共享目標的封裝、點擊事件的處理(包在溢出菜單中的項目顯示)等,都在ShareActionProvider類中實現了---你須要編寫的惟一的代碼是給對應的菜單項聲明操做提供器,並指定共享的Intent對象。

        默認狀況,ShareActionProvider對象會基於用戶的使用頻率來保留共享目標的排列順序。使用頻率高的目標應用程序會顯示在下來列表的上面,而且最經常使用的目標會做爲默認共享目標直接顯示在操做欄。默認狀況下,排序信息被保存在由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()方法來更新它。如:

[java] view plain copy

 print?在CODE上查看代碼片派生到個人代碼片

  1. private ShareActionProvider mShareActionProvider;  

  2. ...  

  3.   

  4. @Override  

  5. public boolean onCreateOptionsMenu(Menu menu) {  

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

  7.   

  8.     // If you use more than one ShareActionProvider, each for a different action,  

  9.     // use the following line to specify a unique history file for each one.  

  10.     // mShareActionProvider.setShareHistoryFileName("custom_share_history.xml");  

  11.   

  12.     // Set the default share intent  

  13.     mShareActionProvider.setShareIntent(getDefaultShareIntent());  

  14.   

  15.     return true;  

  16. }  

  17. // When you need to update the share intent somewhere else in the app, call  

  18. // mShareActionProvider.setShareIntent()  

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

建立一個自定義的操做提供器

       當你想要建立一個有動態行爲和在懸浮菜單中有默認圖標的操做視窗時,繼承ActionProvider類來定義這些行爲是一個比好的的方案。建立本身的操做提供器,提供一個有組織的可重用的組件,而不是在Fragment或Activity的代碼中處理各類操做項的變換和行爲。

       要建立本身的操做提供器,只需簡單的繼承ActionProvider類,而且實現合適的回調方法。你應該實現如下重要的回調方法:

ActionProvider()

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

OnCreateActionView()

        這是你給菜單項定義操做視窗的地方。使用從構造器中接收的Context對象,獲取一個LayoutInflater對象的實例,而且用XML資源來填充操做視窗,而後註冊事件監聽器。如:

[java] view plain copy

 print?在CODE上查看代碼片派生到個人代碼片

  1. public View onCreateActionView() {  

  2.     // Inflate the action view to be shown on the action bar.  

  3.     LayoutInflater layoutInflater = LayoutInflater.from(mContext);  

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

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

  6.     button.setOnClickListener(new View.OnClickListener() {  

  7.         @Override  

  8.         public void onClick(View v) {  

  9.             // Do something...  

  10.         }  

  11.     });  

  12.     return view;  

  13. }  


onPerformDefaultAction()
         
在選中懸浮菜單中的菜單時,系統會調用這個方法,而且操做提供器應該這對這個選中的菜單項執行默認的操做。

       可是,若是你的操做提供器提供了一個子菜單,即便是懸浮菜單中一個菜單項的子菜單,那麼也要經過onPrepareSubMenu()回調方法來顯示子菜單。這樣onPerformDefaultAction()在子菜單顯示時就不會被調用。

       注意:實現了onOptionsItemSelected()回調方法的Activity或Frament對象可以經過處理item-selected事件(而且返回true)來覆蓋操做提供器的默認行爲,這種狀況下,系統不會調用onPerformDefaultAction()回調方法。

添加導航選項標籤

       當你想要在一個Activity中提供導航選擇標籤時,使用操做欄的選項標籤是一個很是好的選擇(而不是使用TabWidget類),由於系統會調整操做欄選項標籤來適應不一樣尺寸的屏幕的須要---在屏幕足夠寬的時候,導航選項標籤會被放到主操做欄中;當屏幕太窄的時候,選項標籤會被放到一個分離的橫條中,如圖9和圖10所示。

      

          圖9. Honeycomb Gallery應用程序中的操做欄選項標籤的截圖

      

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

       要使用選項標籤在Fragmengt之間切換,你必須在每次選擇一個選項標籤時執行一個Fragment事務。若是你不熟悉如何使用FragmentTransaction對象來改變Fragment,請閱讀Fragment開發指南。

       首先,你的佈局必須包含一個用於放置跟每一個Fragment對象關聯的選項標籤的ViewGroup對象。而且要確保這個ViewGroup對象有一個資源ID,以便你可以在選項標籤的切換代碼中可以引用它。另外,若是選項標籤的內容填充在Activity的佈局中(不包括操做欄),那麼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接口的一種實現,在這個實現中,每一個選項標籤都使用了它本身的監聽器實例:

[java] view plain copy

 print?在CODE上查看代碼片派生到個人代碼片

  1. public static class TabListener<T extends Fragment> implements ActionBar.TabListener {  

  2.     private Fragment mFragment;  

  3.     private final Activity mActivity;  

  4.     private final String mTag;  

  5.     private final Class<T> mClass;  

  6.   

  7.     /** Constructor used each time a new tab is created. 

  8.       * @param activity  The host Activity, used to instantiate the fragment 

  9.       * @param tag  The identifier tag for the fragment 

  10.       * @param clz  The fragment's Class, used to instantiate the fragment 

  11.       */  

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

  13.         mActivity = activity;  

  14.         mTag = tag;  

  15.         mClass = clz;  

  16.     }  

  17.   

  18.     /* The following are each of the ActionBar.TabListener callbacks */  

  19.   

  20.     public void onTabSelected(Tab tab, FragmentTransaction ft) {  

  21.         // Check if the fragment is already initialized  

  22.         if (mFragment == null) {  

  23.             // If not, instantiate and add it to the activity  

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

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

  26.         } else {  

  27.             // If it exists, simply attach it in order to show it  

  28.             ft.attach(mFragment);  

  29.         }  

  30.     }  

  31.   

  32.     public void onTabUnselected(Tab tab, FragmentTransaction ft) {  

  33.         if (mFragment != null) {  

  34.             // Detach the fragment, because another one is being attached  

  35.             ft.detach(mFragment);  

  36.         }  

  37.     }  

  38.   

  39.     public void onTabReselected(Tab tab, FragmentTransaction ft) {  

  40.         // User selected the already selected tab. Usually do nothing.  

  41.     }  

  42. }  


       警告:針對每一個回調中的Fragment事務,你都沒必要調用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的標題。

       例如,下面的代碼使用上面定義的監聽器在操做欄中添加了兩個選項標籤。

[java] view plain copy

 print?在CODE上查看代碼片派生到個人代碼片

  1. @Override  

  2. protected void onCreate(Bundle savedInstanceState) {  

  3.     super.onCreate(savedInstanceState);  

  4.     // Notice that setContentView() is not used, because we use the root  

  5.     // android.R.id.content as the container for each fragment  

  6.   

  7.     // setup action bar for tabs  

  8.     ActionBar actionBar = getActionBar();  

  9.     actionBar.setNavigationMode(ActionBar.NAVIGATION_MODE_TABS);  

  10.     actionBar.setDisplayShowTitleEnabled(false);  

  11.   

  12.     Tab tab = actionBar.newTab()  

  13.             .setText(R.string.artist)  

  14.             .setTabListener(new TabListener<ArtistFragment>(  

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

  16.     actionBar.addTab(tab);  

  17.   

  18.     tab = actionBar.newTab()  

  19.         .setText(R.string.album)  

  20.         .setTabListener(new TabListener<AlbumFragment>(  

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

  22.     actionBar.addTab(tab);  

  23. }  


        注意:以上有關ActionBar.TabListener的實現,只是幾種可能的技術之一。在API Demos應用中你可以看到更多的這種樣式。

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

       警告:保存每一個Fragment所必須的狀態是相當重要的,由於當用戶用選項標籤在Fragment對象間切換時,它會查看Fragment在離開時樣子。

       注意:在某些狀況下,Android系統會把操做欄選項標籤做爲一個下拉列表來顯示,以便確保操做欄的最優化顯示。

添加下拉式導航

       做爲Activity內部的另外一種導航(或過濾)模式,操做欄提供了內置的下拉列表。下拉列表可以提供Activity中內容的不一樣排序模式。

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

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

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

         3.  用setNavigationMode()方法該操做欄啓用導航模式,如:

[java] view plain copy

 print?在CODE上查看代碼片派生到個人代碼片

  1. ActionBar actionBar = getActionBar();  

  2. actionBar.setNavigationMode(ActionBar.NAVIGATION_MODE_LIST);  

        4.  用setListNavigationCallbacks()方法給下拉列表設置回調方法,如:

[java] view plain copy

 print?在CODE上查看代碼片派生到個人代碼片

  1. actionBar.setListNavigationCallbacks(mSpinnerAdapter, mNavigationCallback);  

這個方法須要SpinnerAdapter和ActionBar.OnNavigationListener對象。下面是 SpinnerAdapter and ActionBar.OnNavigationListener 的例子。

 Example SpinnerAdapter and OnNavigationListener

設置操做欄的樣式

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

       注意:改變外觀的背景圖片依賴與當前按鈕的狀態(選擇、按下、解除選擇),所以你使用的可描畫的資源必須是一個可描畫的狀態列表。

       警告:對於你提供的全部可描畫的背景,要確保使用NinePatch類型可描畫資源,以便容許圖片的拉伸。NinePatch類型的圖片應該比40像素高30像素寬的圖片要小。


普通的外觀

android:windowActionBarOverlay

      這個屬性聲明瞭操做欄是否應該覆蓋Activity佈局,而不是相對Activity的佈局位置的偏移。這個屬性的默認值是false。

      一般,在屏幕上,操做欄須要它本身的空間,而且把剩下的空間用來填充Activity的佈局。當操做欄四覆蓋模式時,Activity會使用全部的有效空間,系統會在Activity的上面描畫操做欄。若是你想要在操做欄隱藏和顯示時,佈局中的內容保持固定的尺寸好位置,那麼這種覆蓋模式是有用的。你也可能只是爲了顯示效果來使用它,由於你能夠給操做欄設置半透明的背景,以便用戶依然可以看到操做欄背後的Activity佈局。

       注意:默認狀況下,Holo主題會用半透明背景來描畫操做欄。可是,你可以用本身的樣式來修改它,而且默認的狀況下,DeviceDefault主題在不一樣的設備上可能使用不透明的背景。

       覆蓋模式被啓用時,Activity佈局不會感知到操做欄覆蓋在它的上面,所以,在操做欄覆蓋的區域,最好不要放置一些重要的信息或UI組件。若是適合,你可以引用平臺的actionBarSize值來決定操做欄的高度,例如,在XML佈局文件中引用這個值。

[html] view plain copy

 print?在CODE上查看代碼片派生到個人代碼片

  1. <SomeView  

  2.     ...  

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


       你還可以用getHeight()方法在運行時獲取操做欄的高度。若是在Activity生存週期的早期調用這個方法,那麼在調用時所反映的操做欄的高度可能不包括被堆放的操做欄(由於導航選項標籤)。要看如何在運行時判斷操做欄總的高度(包括被堆放的操做欄),請看Honeycomb Gallery示例應用中的TitlesFragment類。

操做項元素

  • android:actionButtonStyle

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

  • android:actionBarItemBackground

  •  給每一個操做項的背景定義可描畫資源(被添加在API 級別 14中)。

  • android:itemBackground

  •  給每一個懸浮菜單項的背景定義可描畫資源。

  • android:actionBarDivider

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

  • android:actionMenuTextColor

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

  • android:actionMenuTextAppearance

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

  • android:actionBarWidgetTheme

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

  • 導航選項標籤

  • android:actionBarTabStyle

  •  給操做欄中的選項標籤訂義樣式資源。

  • android:actionBarTabBarStyle

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

  • android:actionBarTabTextStyle

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

  • 下拉列表

  • android:actionDropDownStyle

  •  給下拉導航列表定義樣式(如背景和文本樣式)。

  • 如,下例XML文件中給操做欄定義了一些定製的樣式:

    [html] view plain copy

  •  

  • print ? 在CODE上查看代碼片 派生到個人代碼片
    1. <?xml version="1.0" encoding="utf-8"?>  

    2. <resources>  

    3.     <!-- the theme applied to the application or activity -->  

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

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

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

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

    8.     </style>  

    9.   

    10.     <!-- style for the action bar tab text -->  

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

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

    13.     </style>  

    14. </resources>  


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

          你可以在清單文件中把定製的主題應用到整個應用程序或一個單獨的Activity對象,如:

    [html] view plain copy

  •  

  • print ? 在CODE上查看代碼片 派生到個人代碼片
    1. <application android:theme="@style/CustomActivityTheme" ... />  


    高級樣式

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

    例如,若是要改變操做欄背景,你可使用下列樣式:

    [html] view plain copy

  •  

  • print ? 在CODE上查看代碼片 派生到個人代碼片
    1. <?xml version="1.0" encoding="utf-8"?>  

    2. <resources>  

    3.     <!-- the theme applied to the application or activity -->  

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

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

    6.         <!-- other activity and action bar styles here -->  

    7.     </style>  

    8.   

    9.     <!-- style for the action bar backgrounds -->  

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

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

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

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

    14.     </style>  

    15. </resources>

相關文章
相關標籤/搜索