Android ActionBar開發技巧

一. 什麼是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的使用。

下載Demo請猛戳


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