轉載至: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中調用以下方法:
- ActionBar actionBar = getActionBar();
- actionBar.hide();
ActionBar actionBar = getActionBar();
actionBar.hide();
現在重新運行一下程序,就可以看到ActionBar不再顯示了,如下圖所示:
修改Action Bar的圖標和標題
- <activity
- android:name=“com.example.actionbartest.MainActivity”
- android:logo=“@drawable/weather” >
- </activity>
<activity
android:name="com.example.actionbartest.MainActivity"
android:logo="@drawable/weather" >
</activity>
現在重新運行一下程序,效果如下圖所示:- <activity
- android:name=“com.example.actionbartest.MainActivity”
- android:label=“天氣”
- android:logo=“@drawable/weather” >
- </activity>
<activity
android:name="com.example.actionbartest.MainActivity"
android:label="天氣"
android:logo="@drawable/weather" >
</activity>
添加Action按鈕
- <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>
<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中。- @Override
- public boolean onCreateOptionsMenu(Menu menu) {
- MenuInflater inflater = getMenuInflater();
- inflater.inflate(R.menu.main, menu);
- return super.onCreateOptionsMenu(menu);
- }
@Override
public boolean onCreateOptionsMenu(Menu menu) {
MenuInflater inflater = getMenuInflater();
inflater.inflate(R.menu.main, menu);
return super.onCreateOptionsMenu(menu);
}
這部分代碼很簡單,僅僅是調用了MenuInflater的inflate()方法來加載menu資源就可以了。現在重新運行一下程序,結果如下圖所示:- 當ActionBar中的剩餘空間不足的時候,如果Action按鈕指定的showAsAction屬性是ifRoom的話,該Action按鈕就會出現在overflow當中,此時就只有title能夠顯示了。
- 如果Action按鈕在ActionBar中顯示,用戶可能通過長按該Action按鈕的方式來查看到title的內容。
響應Action按鈕的點擊事件
- @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);
- }
- }
@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圖標進行導航
- @Override
- protected void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- setTitle(”天氣”);
- setContentView(R.layout.activity_main);
- ActionBar actionBar = getActionBar();
- actionBar.setDisplayHomeAsUpEnabled(true);
- }
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setTitle("天氣");
setContentView(R.layout.activity_main);
ActionBar actionBar = getActionBar();
actionBar.setDisplayHomeAsUpEnabled(true);
}
現在重新運行一下程序,結果如下圖所示:- @Override
- public boolean onOptionsItemSelected(MenuItem item) {
- switch (item.getItemId()) {
- case android.R.id.home:
- finish();
- return true;
- ……
- }
- }
@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()方法也就是加在這裏的了。- <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>
<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這個屬性來進行指定,如下所示:- <activity
- android:name=“com.example.actionbartest.MainActivity”
- android:logo=“@drawable/weather”
- android:parentActivityName=“com.example.actionbartest.LaunchActivity” >
- </activity>
<activity
android:name="com.example.actionbartest.MainActivity"
android:logo="@drawable/weather"
android:parentActivityName="com.example.actionbartest.LaunchActivity" >
</activity>
第三步則需要對android.R.id.home這個事件進行一些特殊處理,如下所示:- @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;
- ……
- }
- }
@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。添加Action View
- <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>
<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按鈕。- @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);
- }
@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 。- @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);
- }
@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按鈕不顯示的情況
- @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();
- }
- }
@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,現在重新運行一下代碼,結果如下圖所示:讓Overflow中的選項顯示圖標
- @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);
- }
@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就可以了。