Android ActionBar完全解析,使用官方推薦的最佳導航欄(上)

轉載至:http://blog.csdn.net/guolin_blog/article/details/18234477


本篇文章主要內容來自於Android Doc,我翻譯之後又做了些加工,英文好的朋友也可以直接去讀原文。

http://developer.android.com/guide/topics/ui/actionbar.html


Action Bar是一種新増的導航欄功能,在android 3.0之後加入到系統的API當中,它標識了用戶當前操作界面的位置,並提供了額外的用戶動作、界面導航等功能。使用ActionBar的好處是,它可以給提供一種全局統一的UI界面,使得用戶在使用任何一款軟件時都懂得該如何操作,並且ActionBar還可以自動適應各種不同大小的屏幕。下面是一張使用ActionBar的界面截圖:




其中,[1]是ActionBar的圖標,[2]是兩個action按鈕,[3]是overflow按鈕。


由於Action Bar是在3.0以後的版本中加入的,如果想在2.x的版本里使用ActionBar的話則需要引入Support Library,不過3.0之前版本的市場佔有率已經非常小了,這裏簡單起見我們就不再考慮去做向下兼容,而是隻考慮4.0以上版本的用法。


添加和移除Action Bar


ActionBar的添加非常簡單,只需要在AndroidManifest.xml中指定Application或Activity的theme是Theme.Holo或其子類就可以了,而使用Eclipse創建的項目自動就會將Application的theme指定成Theme.Holo,所以ActionBar默認都是顯示出來的。新建一個空項目並運行,效果如下圖所示:




而如果想要移除ActionBar的話通常有兩種方式,一是將theme指定成Theme.Holo.NoActionBar,表示使用一個不包含ActionBar的主題,二是在Activity中調用以下方法:

  1. ActionBar actionBar = getActionBar();  
  2. actionBar.hide();  
ActionBar actionBar = getActionBar();
actionBar.hide();

現在重新運行一下程序,就可以看到ActionBar不再顯示了,如下圖所示:




修改Action Bar的圖標和標題


默認情況下,系統會使用<application>或者<activity>中icon屬性指定的圖片來作爲ActionBar的圖標,但是我們也可以改變這一默認行爲。如果我們想要使用另外一張圖片來作爲ActionBar的圖標,可以在<application>或者<activity>中通過logo屬性來進行指定。比如項目的res/drawable目錄下有一張weather.png圖片,就可以在AndroidManifest.xml中這樣指定:
  1. <activity  
  2.     android:name=“com.example.actionbartest.MainActivity”  
  3.     android:logo=“@drawable/weather” >  
  4. </activity>  
<activity
    android:name="com.example.actionbartest.MainActivity"
    android:logo="@drawable/weather" >
</activity>
現在重新運行一下程序,效果如下圖所示:



OK,ActionBar的圖標已經修改成功了,那麼標題中的內容該怎樣修改呢?其實也很簡單,使用label屬性來指定一個字符串就可以了,如下所示:
  1. <activity  
  2.     android:name=“com.example.actionbartest.MainActivity”  
  3.     android:label=“天氣”  
  4.     android:logo=“@drawable/weather” >  
  5. </activity>  
<activity
    android:name="com.example.actionbartest.MainActivity"
    android:label="天氣"
    android:logo="@drawable/weather" >
</activity>
現在重新運行一下程序,結果如下圖所示:



添加Action按鈕


ActionBar還可以根據應用程序當前的功能來提供與其相關的Action按鈕,這些按鈕都會以圖標或文字的形式直接顯示在ActionBar上。當然,如果按鈕過多,ActionBar上顯示不完,多出的一些按鈕可以隱藏在overflow裏面(最右邊的三個點就是overflow按鈕),點擊一下overflow按鈕就可以看到全部的Action按鈕了。

當Activity啓動的時候,系統會調用Activity的onCreateOptionsMenu()方法來取出所有的Action按鈕,我們只需要在這個方法中去加載一個menu資源,並把所有的Action按鈕都定義在資源文件裏面就可以了。

那麼我們先來看下menu資源文件該如何定義,代碼如下所示:
  1. <menu xmlns:android=“http://schemas.android.com/apk/res/android”  
  2.     xmlns:tools=“http://schemas.android.com/tools”  
  3.     tools:context=“com.example.actionbartest.MainActivity” >  
  4.   
  5.     <item  
  6.         android:id=“@+id/action_compose”  
  7.         android:icon=“@drawable/ic_action_compose”  
  8.         android:showAsAction=“always”  
  9.         android:title=“@string/action_compose”/>  
  10.     <item  
  11.         android:id=“@+id/action_delete”  
  12.         android:icon=“@drawable/ic_action_delete”  
  13.         android:showAsAction=“always”  
  14.         android:title=“@string/action_delete”/>  
  15.     <item  
  16.         android:id=“@+id/action_settings”  
  17.         android:icon=“@drawable/ic_launcher”  
  18.         android:showAsAction=“never”  
  19.         android:title=“@string/action_settings”/>  
  20.   
  21. </menu>  
<menu xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    tools:context="com.example.actionbartest.MainActivity" >

    <item
        android:id="@+id/action_compose"
        android:icon="@drawable/ic_action_compose"
        android:showAsAction="always"
        android:title="@string/action_compose"/>
    <item
        android:id="@+id/action_delete"
        android:icon="@drawable/ic_action_delete"
        android:showAsAction="always"
        android:title="@string/action_delete"/>
    <item
        android:id="@+id/action_settings"
        android:icon="@drawable/ic_launcher"
        android:showAsAction="never"
        android:title="@string/action_settings"/>

</menu>
可以看到,這裏我們通過三個<item>標籤定義了三個Action按鈕。<item>標籤中又有一些屬性,其中id是該Action按鈕的唯一標識符,icon用於指定該按鈕的圖標,title用於指定該按鈕可能顯示的文字(在圖標能顯示的情況下,通常不會顯示文字),showAsAction則指定了該按鈕顯示的位置,主要有以下幾種值可選:always表示永遠顯示在ActionBar中,如果屏幕空間不夠則無法顯示,ifRoom表示屏幕空間夠的情況下顯示在ActionBar中,不夠的話就顯示在overflow中,never則表示永遠顯示在overflow中。
接着,重寫Activity的onCreateOptionsMenu()方法,代碼如下所示:
  1. @Override  
  2. public boolean onCreateOptionsMenu(Menu menu) {  
  3.     MenuInflater inflater = getMenuInflater();  
  4.     inflater.inflate(R.menu.main, menu);  
  5.     return super.onCreateOptionsMenu(menu);  
  6. }  
@Override
public boolean onCreateOptionsMenu(Menu menu) {
    MenuInflater inflater = getMenuInflater();
    inflater.inflate(R.menu.main, menu);
    return super.onCreateOptionsMenu(menu);
}
這部分代碼很簡單,僅僅是調用了MenuInflater的inflate()方法來加載menu資源就可以了。現在重新運行一下程序,結果如下圖所示:



可以看到,action_compose和action_delete這兩個按鈕已經在ActionBar中顯示出來了,而action_settings這個按鈕由於showAsAction屬性設置成了never,所以被隱藏到了overflow當中,只要點擊一下overflow按鈕就可以看到它了。

這裏我們注意到,顯示在ActionBar上的按鈕都只有一個圖標而已,我們在title中指定的文字並沒有顯示出來。沒錯,title中的內容通常情況下只會在overflow中顯示出來,ActionBar中由於屏幕空間有限,默認是不會顯示title內容的。但是出於以下幾種因素考慮,即使title中的內容無法顯示出來,我們也應該給每個item中都指定一個title屬性:
  • 當ActionBar中的剩餘空間不足的時候,如果Action按鈕指定的showAsAction屬性是ifRoom的話,該Action按鈕就會出現在overflow當中,此時就只有title能夠顯示了。
  • 如果Action按鈕在ActionBar中顯示,用戶可能通過長按該Action按鈕的方式來查看到title的內容。


響應Action按鈕的點擊事件


當用戶點擊Action按鈕的時候,系統會調用Activity的onOptionsItemSelected()方法,通過方法傳入的MenuItem參數,我們可以調用它的getItemId()方法和menu資源中的id進行比較,從而辨別出用戶點擊的是哪一個Action按鈕,比如:
  1. @Override  
  2. public boolean onOptionsItemSelected(MenuItem item) {  
  3.     switch (item.getItemId()) {  
  4.     case R.id.action_compose:  
  5.         Toast.makeText(this“Compose”, Toast.LENGTH_SHORT).show();  
  6.         return true;  
  7.     case R.id.action_delete:  
  8.         Toast.makeText(this“Delete”, Toast.LENGTH_SHORT).show();  
  9.         return true;  
  10.     case R.id.action_settings:  
  11.         Toast.makeText(this“Settings”, Toast.LENGTH_SHORT).show();  
  12.         return true;  
  13.     default:  
  14.         return super.onOptionsItemSelected(item);  
  15.     }  
  16. }  
@Override
public boolean onOptionsItemSelected(MenuItem item) {
    switch (item.getItemId()) {
    case R.id.action_compose:
        Toast.makeText(this, "Compose", Toast.LENGTH_SHORT).show();
        return true;
    case R.id.action_delete:
        Toast.makeText(this, "Delete", Toast.LENGTH_SHORT).show();
        return true;
    case R.id.action_settings:
        Toast.makeText(this, "Settings", Toast.LENGTH_SHORT).show();
        return true;
    default:
        return super.onOptionsItemSelected(item);
    }
}
可以看到,我們讓每個Action按鈕被點擊的時候都彈出一個Toast,現在重新運行一下代碼,結果如下圖所示:




通過Action Bar圖標進行導航


啓用ActionBar圖標導航的功能,可以允許用戶根據當前應用的位置來在不同界面之間切換。比如,A界面展示了一個列表,點擊某一項之後進入了B界面,這時B界面就應該啓用ActionBar圖標導航功能,這樣就可以回到A界面。

我們可以通過調用setDisplayHomeAsUpEnabled()方法來啓用ActionBar圖標導航功能,比如:
  1. @Override  
  2. protected void onCreate(Bundle savedInstanceState) {  
  3.     super.onCreate(savedInstanceState);  
  4.     setTitle(”天氣”);  
  5.     setContentView(R.layout.activity_main);  
  6.     ActionBar actionBar = getActionBar();  
  7.     actionBar.setDisplayHomeAsUpEnabled(true);  
  8. }  
@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setTitle("天氣");
    setContentView(R.layout.activity_main);
    ActionBar actionBar = getActionBar();
    actionBar.setDisplayHomeAsUpEnabled(true);
}
現在重新運行一下程序,結果如下圖所示:



可以看到,在ActionBar圖標的左側出現了一個向左的箭頭,通常情況下這都表示返回的意思,因此最簡單的實現就是在它的點擊事件裏面加入finish()方法就可以了,如下所示:
  1. @Override  
  2. public boolean onOptionsItemSelected(MenuItem item) {  
  3.     switch (item.getItemId()) {  
  4.     case android.R.id.home:  
  5.         finish();  
  6.         return true;  
  7.     ……  
  8.     }  
  9. }  
   @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        switch (item.getItemId()) {
        case android.R.id.home:
            finish();
            return true;
        ……
        }
    }
當點擊ActionBar圖標的時候,系統同樣會調用onOptionsItemSelected()方法,並且此時的itemId是android.R.id.home,所以finish()方法也就是加在這裏的了。
現在看上去,ActionBar導航和Back鍵的功能貌似是一樣的。沒錯,如果我們只是簡單地finish了一下,ActionBar導航和Back鍵的功能是完全一樣的,但ActionBar導航的設計初衷並不是這樣的,它和Back鍵的功能還是有一些區別的,舉個例子吧。



上圖中的Conversation List是收件箱的主界面,現在我們點擊第一封郵件會進入到Conversation1 details界面,然後點擊下一封郵件會進入到Conversation 2 details界面,再點擊下一封郵箱會進入到Conversation3 details界面。好的,這個時候如果我們按下Back鍵,應該會回到Conversation 2 details界面,再按一次Back鍵應該回到Conversation1 details界面,再按一次Back鍵纔會回到Conversation List。而ActionBar導航則不應該表現出這種行爲,無論我們當前在哪一個Conversation details界面,點擊一下導航按鈕都應該回到Conversation List界面纔對。

這就是ActionBar導航和Back鍵在設計上的區別,那麼該怎樣才能實現這樣的功能呢?其實並不複雜,實現標準的ActionBar導航功能只需三步走。

第一步我們已經實現了,就是調用setDisplayHomeAsUpEnabled()方法,並傳入true。

第二步需要在AndroidManifest.xml中配置父Activity,如下所示:
  1. <activity  
  2.     android:name=“com.example.actionbartest.MainActivity”  
  3.     android:logo=“@drawable/weather” >  
  4.     <meta-data  
  5.         android:name=“android.support.PARENT_ACTIVITY”  
  6.         android:value=“com.example.actionbartest.LaunchActivity” />  
  7. </activity>  
<activity
    android:name="com.example.actionbartest.MainActivity"
    android:logo="@drawable/weather" >
    <meta-data
        android:name="android.support.PARENT_ACTIVITY"
        android:value="com.example.actionbartest.LaunchActivity" />
</activity>
可以看到,這裏通過meta-data標籤指定了MainActivity的父Activity是LaunchActivity,在Android 4.1版本之後,也可以直接使用android:parentActivityName這個屬性來進行指定,如下所示:
  1. <activity  
  2.     android:name=“com.example.actionbartest.MainActivity”  
  3.     android:logo=“@drawable/weather”  
  4.     android:parentActivityName=“com.example.actionbartest.LaunchActivity” >  
  5. </activity>  
<activity
    android:name="com.example.actionbartest.MainActivity"
    android:logo="@drawable/weather"
    android:parentActivityName="com.example.actionbartest.LaunchActivity" >
</activity>
第三步則需要對android.R.id.home這個事件進行一些特殊處理,如下所示:
  1. @Override  
  2. public boolean onOptionsItemSelected(MenuItem item) {  
  3.     switch (item.getItemId()) {  
  4.     case android.R.id.home:  
  5.         Intent upIntent = NavUtils.getParentActivityIntent(this);  
  6.         if (NavUtils.shouldUpRecreateTask(this, upIntent)) {  
  7.             TaskStackBuilder.create(this)  
  8.                     .addNextIntentWithParentStack(upIntent)  
  9.                     .startActivities();  
  10.         } else {  
  11.             upIntent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);  
  12.             NavUtils.navigateUpTo(this, upIntent);  
  13.         }  
  14.         return true;  
  15.         ……  
  16.     }  
  17. }  
@Override
public boolean onOptionsItemSelected(MenuItem item) {
    switch (item.getItemId()) {
    case android.R.id.home:
        Intent upIntent = NavUtils.getParentActivityIntent(this);
        if (NavUtils.shouldUpRecreateTask(this, upIntent)) {
            TaskStackBuilder.create(this)
                    .addNextIntentWithParentStack(upIntent)
                    .startActivities();
        } else {
            upIntent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
            NavUtils.navigateUpTo(this, upIntent);
        }
        return true;
        ......
    }
}
其中,調用NavUtils.getParentActivityIntent()方法可以獲取到跳轉至父Activity的Intent,然後如果父Activity和當前Activity是在同一個Task中的,則直接調用navigateUpTo()方法進行跳轉,如果不是在同一個Task中的,則需要藉助TaskStackBuilder來創建一個新的Task。

這樣,就按照標準的規範成功實現ActionBar導航的功能了。

添加Action View


ActionView是一種可以在ActionBar中替換Action按鈕的控件,它可以允許用戶在不切換界面的情況下通過ActionBar完成一些較爲豐富的操作。比如說,你需要完成一個搜索功能,就可以將SeachView這個控件添加到ActionBar中。

爲了聲明一個ActionView,我們可以在menu資源中通過actionViewClass屬性來指定一個控件,例如可以使用如下方式添加SearchView:
  1. <menu xmlns:android=“http://schemas.android.com/apk/res/android” >  
  2.   
  3.     <item  
  4.         android:id=“@+id/action_search”  
  5.         android:icon=“@drawable/ic_action_search”  
  6.         android:actionViewClass=“android.widget.SearchView”  
  7.         android:showAsAction=“ifRoom|collapseActionView”  
  8.         android:title=“@string/action_search” />  
  9.     ……  
  10.   
  11. </menu>  
<menu xmlns:android="http://schemas.android.com/apk/res/android" >

    <item
        android:id="@+id/action_search"
        android:icon="@drawable/ic_action_search"
        android:actionViewClass="android.widget.SearchView"
        android:showAsAction="ifRoom|collapseActionView"
        android:title="@string/action_search" />
    ......

</menu>
注意在showAsAction屬性中我們還聲明瞭一個collapseActionView,這個值表示該控件可以被合併成一個Action按鈕。
現在重新運行一下程序,效果如下圖所示:



OK,果然有一個搜索樣式的Action按鈕出現了,現在點擊一下這個搜索按鈕,效果如下圖所示:



可以看到,這時SearchView就會展開佔滿整個ActionBar,而其它的Action按鈕由於將showAsAction屬性設置成了ifRoom,此時都會隱藏到overflow當中。

如果你還希望在代碼中對SearchView的屬性進行配置(比如添加監聽事件等),完全沒有問題,只需要在onCreateOptionsMenu()方法中獲取該ActionView的實例就可以了,代碼如下所示:
  1. @Override  
  2. public boolean onCreateOptionsMenu(Menu menu) {  
  3.     MenuInflater inflater = getMenuInflater();  
  4.     inflater.inflate(R.menu.main, menu);  
  5.     MenuItem searchItem = menu.findItem(R.id.action_search);  
  6.     SearchView searchView = (SearchView) searchItem.getActionView();  
  7.     // 配置SearchView的屬性  
  8.     ……  
  9.     return super.onCreateOptionsMenu(menu);  
  10. }  
@Override
public boolean onCreateOptionsMenu(Menu menu) {
    MenuInflater inflater = getMenuInflater();
    inflater.inflate(R.menu.main, menu);
    MenuItem searchItem = menu.findItem(R.id.action_search);
    SearchView searchView = (SearchView) searchItem.getActionView();
    // 配置SearchView的屬性
    ......
    return super.onCreateOptionsMenu(menu);
}
在得到了SearchView的實例之後,就可以任意地配置它的各種屬性了。關於SearchView的更多詳細用法,可以參考官方文檔 http://developer.android.com/guide/topics/search/search-dialog.html 。

除此之外,有些程序可能還希望在ActionView展開和合並的時候顯示不同的界面,其實我們只需要去註冊一個ActionView的監聽器就能實現這樣的功能了,代碼如下所示:
  1. @Override  
  2. public boolean onCreateOptionsMenu(Menu menu) {  
  3.     MenuInflater inflater = getMenuInflater();  
  4.     inflater.inflate(R.menu.main, menu);  
  5.     MenuItem searchItem = menu.findItem(R.id.action_search);  
  6.     searchItem.setOnActionExpandListener(new OnActionExpandListener() {  
  7.         @Override  
  8.         public boolean onMenuItemActionExpand(MenuItem item) {  
  9.             Log.d(”TAG”“on expand”);  
  10.             return true;  
  11.         }  
  12.           
  13.         @Override  
  14.         public boolean onMenuItemActionCollapse(MenuItem item) {  
  15.             Log.d(”TAG”“on collapse”);  
  16.             return true;  
  17.         }  
  18.     });  
  19.     return super.onCreateOptionsMenu(menu);  
  20. }  
@Override
public boolean onCreateOptionsMenu(Menu menu) {
    MenuInflater inflater = getMenuInflater();
    inflater.inflate(R.menu.main, menu);
    MenuItem searchItem = menu.findItem(R.id.action_search);
    searchItem.setOnActionExpandListener(new OnActionExpandListener() {
        @Override
        public boolean onMenuItemActionExpand(MenuItem item) {
            Log.d("TAG", "on expand");
            return true;
        }

        @Override
        public boolean onMenuItemActionCollapse(MenuItem item) {
            Log.d("TAG", "on collapse");
            return true;
        }
    });
    return super.onCreateOptionsMenu(menu);
}
可以看到,調用MenuItem的setOnActionExpandListener()方法就可以註冊一個監聽器了,當SearchView展開的時候就會回調onMenuItemActionExpand()方法,當SearchView合併的時候就會調用onMenuItemActionCollapse()方法,我們在這兩個方法中進行相應的UI操作就可以了。

Overflow按鈕不顯示的情況


雖然現在我們已經掌握了不少ActionBar的用法,但是當你真正去使用它的時候還是可能會遇到各種各樣的問題,比如很多人都會碰到overflow按鈕不顯示的情況。明明是同樣的一份代碼,overflow按鈕在有些手機上會顯示,而在有些手機上偏偏就不顯示,這是爲什麼呢?後來我總結了一下,overflow按鈕的顯示情況和手機的硬件情況是有關係的,如果手機沒有物理Menu鍵的話,overflow按鈕就可以顯示,如果有物理Menu鍵的話,overflow按鈕就不會顯示出來。比如我們啓動一個有Menu鍵的模擬器,然後將代碼運行到該模擬器上,結果如下圖所示:



可以看到,ActionBar最右邊的overflow按鈕不見了!那麼此時我們如何查看隱藏在overflow中的Action按鈕呢?其實非常簡單,按一下Menu鍵,隱藏的內容就會從底部出來了,如下圖所示:



看到這裏相信不少朋友都想吐槽一下了,這顯然是一種非常蛋疼的設計,在不同手機上竟然顯示了不同的界面,而且操作方法也完全不一樣,這樣會給用戶一種非常不習慣的感覺。話說Google爲什麼要把ActionBar的overflow設計成這樣我也不太理解,但是我們還是有辦法改變這一默認行爲的。

實際上,在ViewConfiguration這個類中有一個叫做sHasPermanentMenuKey的靜態變量,系統就是根據這個變量的值來判斷手機有沒有物理Menu鍵的。當然這是一個內部變量,我們無法直接訪問它,但是可以通過反射的方式修改它的值,讓它永遠爲false就可以了,代碼如下所示:
  1. @Override  
  2. protected void onCreate(Bundle savedInstanceState) {  
  3.     ……  
  4.     setOverflowShowingAlways();  
  5. }  
  6.   
  7. private void setOverflowShowingAlways() {  
  8.     try {  
  9.         ViewConfiguration config = ViewConfiguration.get(this);  
  10.         Field menuKeyField = ViewConfiguration.class.getDeclaredField(“sHasPermanentMenuKey”);  
  11.         menuKeyField.setAccessible(true);  
  12.         menuKeyField.setBoolean(config, false);  
  13.     } catch (Exception e) {  
  14.         e.printStackTrace();  
  15.     }  
  16. }  
@Override
protected void onCreate(Bundle savedInstanceState) {
    ......
    setOverflowShowingAlways();
}

private void setOverflowShowingAlways() {
    try {
        ViewConfiguration config = ViewConfiguration.get(this);
        Field menuKeyField = ViewConfiguration.class.getDeclaredField("sHasPermanentMenuKey");
        menuKeyField.setAccessible(true);
        menuKeyField.setBoolean(config, false);
    } catch (Exception e) {
        e.printStackTrace();
    }
}
這裏我們在onCreate()方法的最後調用了setOverflowShowingAlways()方法,而這個方法的內部就是使用反射的方式將sHasPermanentMenuKey的值設置成false,現在重新運行一下代碼,結果如下圖所示:



可以看到,即使是在有Menu鍵的手機上,也能讓overflow按鈕顯示出來了,這樣就可以大大增加我們軟件界面和操作的統一性。

讓Overflow中的選項顯示圖標


如果你點擊一下overflow按鈕去查看隱藏的Action按鈕,你會發現這部分Action按鈕都是隻顯示文字不顯示圖標的,如下圖所示:



這是官方的默認效果,Google認爲隱藏在overflow中的Action按鈕都應該只顯示文字。當然,如果你認爲這樣不夠美觀,希望在overflow中的Action按鈕也可以顯示圖標,我們仍然可以想辦法來改變這一默認行爲。

其實,overflow中的Action按鈕應不應該顯示圖標,是由MenuBuilder這個類的setOptionalIconsVisible方法來決定的,如果我們在overflow被展開的時候給這個方法傳入true,那麼裏面的每一個Action按鈕對應的圖標就都會顯示出來了。調用的方法當然仍然是用反射了,代碼如下所示:
  1. @Override  
  2. public boolean onMenuOpened(int featureId, Menu menu) {  
  3.     if (featureId == Window.FEATURE_ACTION_BAR && menu != null) {  
  4.         if (menu.getClass().getSimpleName().equals(“MenuBuilder”)) {  
  5.             try {  
  6.                 Method m = menu.getClass().getDeclaredMethod(”setOptionalIconsVisible”, Boolean.TYPE);  
  7.                 m.setAccessible(true);  
  8.                 m.invoke(menu, true);  
  9.             } catch (Exception e) {  
  10.             }  
  11.         }  
  12.     }  
  13.     return super.onMenuOpened(featureId, menu);  
  14. }  
@Override
public boolean onMenuOpened(int featureId, Menu menu) {
    if (featureId == Window.FEATURE_ACTION_BAR && menu != null) {
        if (menu.getClass().getSimpleName().equals("MenuBuilder")) {
            try {
                Method m = menu.getClass().getDeclaredMethod("setOptionalIconsVisible", Boolean.TYPE);
                m.setAccessible(true);
                m.invoke(menu, true);
            } catch (Exception e) {
            }
        }
    }
    return super.onMenuOpened(featureId, menu);
}
可以看到,這裏我們重寫了一個onMenuOpened()方法,當overflow被展開的時候就會回調這個方法,接着在這個方法的內部通過返回反射的方法將MenuBuilder的setOptionalIconsVisible變量設置爲true就可以了。

現在重新運行一下代碼,結果如下圖所示:



好了,目前爲止我們已經把ActionBar的基礎知識介紹完了,那麼今天的講解就到這裏,下篇文章中我會帶領大家一起更深入地瞭解ActionBar,感興趣的朋友請繼續閱讀 Android ActionBar完全解析,使用官方推薦的最佳導航欄(下)
發佈了35 篇原創文章 · 獲贊 53 · 訪問量 11萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章