一. 什麼是ActionBar,優點和缺點?
Action Bar是一種新増的導航欄功能,在Android 3.0之後加入到系統的API當中,它標識了用戶當前操作界面的位置,並提供了額外的用戶動作、界面導航等功能。使用ActionBar的好處是,它可以給提供一種全局統一的UI界面,使得用戶在使用任何一款軟件時都懂得該如何操作,並且ActionBar還可以自動適應各種不同大小的屏幕。目前在實際開發中,很多項目都會用到ActionBar,本篇文章參考http://blog.csdn.net/guolin_blog/article/details/18234477並增加了自己的內容,Thank you !
二. 如何使用ActionBar
1. 添加ActionBar
在AndroidManifest.xml中指定Application或Activity的theme是Theme.Holo或其子類
2. 刪除ActionBar
第一種方法:將theme指定成Theme.Holo.NoActionBar
第二種方法:調用以下代碼去設置
ActionBar actionBar = getActionBar();
actionBar.hide();
3. 圖標修改
在清單文件中指定Activity的login屬性:android:logo="@drawable/xxx"4. 標題修改
在清單文件中指定Activity的label屬性:android:label="xxx"
5. 添加Action按鈕
當Activity啓動的時候,系統會調用Activity的onCreateOptionsMenu()方法來取出所有的Action按鈕
①.佈局文件添加:在res/menu/xxx.xml中設置
<item
android:id="@+id/action_compose"
android:icon="@drawable/ic_action_compose"
android:showAsAction="always"
android:title="@string/action_compose"/>
②重寫onCreateOptionsMenu方法
public boolean onCreateOptionsMenu(Menu menu) {
MenuInflater inflater = getMenuInflater();
inflater.inflate(R.menu.main, menu);
return super.onCreateOptionsMenu(menu);
}
注意:當ActionBar中的剩餘空間不足的時候,如果Action按鈕指定的showAsAction屬性是ifRoom的話,該Action按鈕就會出現在overflow當中,此時就只有title能夠顯示了。如果Action按鈕在ActionBar中顯示,用戶可能通過長按該Action按鈕的方式來查看到title的內容。
6. 處理點擊事件
重寫onOptionsItemSelected方法 調用item.getItemId() 去處理
三. 如何使用ActionBar實現導航
ActionBar導航和Back鍵的區別:ActionBar中捕捉Home鍵調用finish方法,效果類似於Back鍵,但違背了最初的設計
三步設置ActionBar導航:
①. 調用setDisplayHomeAsUpEnabled(true),顯示Home按鈕
②. 在清單文件中配置父Activity
<meta-data
android:name="android.support.PARENT_ACTIVITY"
android:value="com.example.actionbartest.LaunchActivity" />
注:android4.1之後可以直接通過parentActivityName屬性來指定
③. 捕捉Home按鈕的點擊事件進行處理
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;
四. 添加Action View
ActionView是一種可以在ActionBar中替換Action按鈕的控件,它可以允許用戶在不切換界面的情況下通過ActionBar完成一些較爲豐富的操作,爲了聲明一個ActionView,我們可以在menu資源中通過actionViewClass屬性來指定一個控件,例如可以使用如下方式添加SearchView:
<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" />
如果你還希望在代碼中對SearchView的屬性進行配置(比如添加監聽事件等),完全沒有問題,只需要在onCreateOptionsMenu()方法中獲取該ActionView的實例就可以了,代碼如下所示:@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);
}
除此之外,有些程序可能還希望在ActionView展開和合並的時候顯示不同的界面,其實我們只需要去註冊一個ActionView的監聽器就能實現這樣的功能了,代碼如下所示:@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按鈕不顯示
overflow按鈕的顯示情況和手機的硬件情況是有關係的,如果手機沒有物理Menu鍵的話,overflow按鈕就可以顯示,如果有物理Menu鍵的話,overflow按鈕就不會顯示出來,在ViewConfiguration這個類中有一個叫做sHasPermanentMenuKey的靜態變量,系統就是根據這個變量的值來判斷手機有沒有物理Menu鍵的。當然這是一個內部變量,我們無法直接訪問它,但是可以通過反射的方式修改它的值,讓它永遠爲false就可以了,代碼如下所示:@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();
}
}
六. 讓Overflow顯示圖標
Google認爲隱藏在overflow中的Action按鈕都應該只顯示文字,如果想顯示圖標,可以用反射的方法改變MenuBuilder這個類的setOptionalIconsVisible變量的值@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);
}
七. 改變Overflow的圖標
<item
android:id="@+id/action_search"
android:actionViewClass="android.widget.SearchView"
android:icon="@drawable/actionbar_search_icon"
android:showAsAction="ifRoom|collapseActionView"
android:title="@string/action_search"/>
<item
android:id="@+id/overflow_menus"
android:actionProviderClass="@android:style/Widget.Holo.ActionButton.Overflow"
android:orderInCategory="100"
android:showAsAction="always"
android:title="@string/action_search">
<menu>
<item
android:id="@+id/action_plus"
android:actionProviderClass="com.example.wechatsample.PlusActionProvider"
android:icon="@drawable/actionbar_add_icon"
android:showAsAction="ifRoom"
android:title="@string/action_plus"/>
<item
android:id="@+id/action_album"
android:icon="@drawable/ofm_photo_icon"
android:title="@string/action_album"/>
<item
android:id="@+id/action_collection"
android:icon="@drawable/ofm_collect_icon"
android:title="@string/action_collection"/>
<item
android:id="@+id/action_card"
android:icon="@drawable/ofm_card_icon"
android:title="@string/action_card"/>
<item
android:id="@+id/action_settings"
android:icon="@drawable/ofm_setting_icon"
android:title="@string/action_settings"/>
<item
android:id="@+id/action_feed"
android:icon="@drawable/ofm_feedback_icon"
android:title="@string/action_feed"/>
</menu>
</item>
將要在Overflow內部顯示的item用一個menu包裹起來,在onCreateOptionsMenu方法中調用menu.getItem(1).setIcon(R.drawable.actionbar_add_icon);
七. 自定義ActionBar
ActionBar actionBar = ((ActionBarActivity) getActivity()).getSupportActionBar();
actionBar.setDisplayOptions(ActionBar.DISPLAY_SHOW_CUSTOM);
View titleView = View.inflate(mContext, R.layout.title_mapmain, null);
titleView.setBackgroundColor(Color.WHITE);
LayoutParams params = new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT);
actionBar.setCustomView(titleView,params)
八. 添加Action Provider
和Action View有點類似,Action Provider也可以將一個Action按鈕替換成一個自定義的佈局。但不同的是,Action Provider能夠完全控制事件的所有行爲,並且還可以在點擊的時候顯示子菜單。
如何在一個Menu的Item中添加子菜單呢?
①.定義類繼承ActionProvider,在menu.xml的item中通過actionProviderClass屬性來引用所定義的類。
②.重寫onPrepareSubMenu方法調用SubMenu的clear , add , setIcon ,setOnMenuItemClickListener方法來完成對子菜單的操作
③.重寫hasSubMenu方法返回true
具體案例請參考文章最後提供的Demo。
九. 添加導航Tabs
Android官方更加推薦使用ActionBar中提供的Tabs功能,因爲它更加的智能,可以自動適配各種屏幕的大小如何使用ActionBar提供的Tab功能?
①. 實現ActionBar.TabListener接口,這個接口提供了Tab事件的各種回調,比如當用戶點擊了一個Tab時,你就可以進行切換Tab的操作。②. 爲每一個你想添加的Tab創建一個ActionBar.Tab的實例,並且調用setTabListener()方法來設置ActionBar.TabListener。除此之外,還需要調用setText()方法來給當前Tab設置標題。③. 最後調用ActionBar的addTab()方法將創建好的Tab添加到ActionBar中。
十. 自定義ActionBar樣式
1. 使用主題
Theme.Holo,這是一個深色系的主題。Theme.Holo.Light,這是一個淺色系的主題。
2. 自定義背景
如果想要修改ActionBar的背景,我們可以通過創建一個自定義主題並重寫actionBarStyle屬性來實現。這個屬性可以指向另外一個樣式,然後我們在這個樣式中重寫background這個屬性就可以指定一個drawable資源或顏色,從而實現自定義背景的功能。在style.xml中添加
<resources>
<style name="CustomActionBarTheme" parent="@android:style/Theme.Holo.Light">
<item name="android:actionBarStyle">@style/MyActionBar</item>
</style>
<style name="MyActionBar" parent="@android:style/Widget.Holo.Light.ActionBar">
<item name="android:background">#f4842d</item> 重寫了background屬性,並給它指定了一個背景色
<item name="android:backgroundStacked">#d27026</item> 重寫了backgroundStacked屬性,這個屬性就是用於指定Tabs背景色的
</style>
</resources>
然後在AndroidManifest.xml的Activity標籤中聲明android:theme="@style/CustomActionBarTheme"
3. 自定義文字顏色
修改ActionBar標題顏色爲白色
<style name="MyActionBar" parent="@android:style/Widget.Holo.Light.ActionBar">
<item name="android:titleTextStyle">@style/MyActionBarTitleText</item>
</style>
<style name="MyActionBarTitleText" parent="@android:style/TextAppearance.Holo.Widget.ActionBar.Title">
<item name="android:textColor">#fff</item>
</style>
修改tab字體顏色
<style name="CustomActionBarTheme" parent="@android:style/Theme.Holo.Light">
<item name="android:actionBarStyle">@style/MyActionBar</item>
<item name="android:actionBarTabTextStyle">@style/MyActionBarTabText</item>
</style>
<style name="MyActionBarTabText"
parent="@android:style/Widget.Holo.ActionBar.TabText">
<item name="android:textColor">#fff</item>
</style>
4. 自定義Tab Indicator
爲了可以明確分辨出我們當前選中的是哪一個Tab項,通常情況下都會在選中Tab的下面加上一條橫線作爲標識,這被稱作Tab Indicator
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:state_selected="false"
android:state_pressed="false"
android:drawable="@drawable/tab_unselected" />
<item android:state_selected="true"
android:state_pressed="false"
android:drawable="@drawable/tab_selected" />
<item android:state_selected="false"
android:state_pressed="true"
android:drawable="@drawable/tab_unselected_pressed" />
<item android:state_selected="true"
android:state_pressed="true"
android:drawable="@drawable/tab_selected_pressed" />
</selector>
這裏先是重寫了actionBarTabStyle這個屬性,並將它指向了另一個自定義樣式MyActionBarTabs,接着在這個樣式中重寫background屬性,然後指向我們剛纔創建的actionbar_tab_indicator即可。<resources>
<style name="CustomActionBarTheme" parent="@android:style/Theme.Holo.Light">
......
<item name="android:actionBarTabStyle">@style/MyActionBarTabs</item>
</style>
<style name="MyActionBarTabs" parent="@android:style/Widget.Holo.ActionBar.TabView">
<item name="android:background">@drawable/actionbar_tab_indicator</item>
</style>
</resources>
最後在Actionbar使用的過程中還需要知道下面幾個小知識點:
setHomeButtonEnabled:這個小於4.0版本的默認值爲true的。但是在4.0及其以上是false,該方法的作用:決定左上角的圖標是否可以點擊
// 給左上角圖標的左邊加上一個返回的圖標 。對應ActionBar.DISPLAY_HOME_AS_UP
actionBar.setDisplayHomeAsUpEnabled(true)
//使左上角圖標是否顯示,如果設成false,則沒有程序圖標,僅僅就個標題,否則,顯示應用程序圖標,對應id爲android.R.id.home,對應ActionBar.DISPLAY_SHOW_HOME
actionBar.setDisplayShowHomeEnabled(true)
//使自定義的普通View能在title欄顯示,即actionBar.setCustomView能起作用,對應ActionBar.DISPLAY_SHOW_CUSTOM
actionBar.setDisplayShowCustomEnabled(true)
//對應ActionBar.DISPLAY_SHOW_TITLE。
actionBar.setDisplayShowTitleEnabled(true)
其中setHomeButtonEnabled和setDisplayShowHomeEnabled共同起作用,如果setHomeButtonEnabled設成false,即使setDisplayShowHomeEnabled設成true,圖標也不能點擊
下面給出3個Demo,讓你徹底玩轉ActionBar的使用。