ActionBar和ToolBar
Action Bar是Android 3.0引入的導(dǎo)航欄功能,然而到5.0的時候,又推出了ToolBar,實際上這兩個可以理解為同一個東西,ToolBar是對ActionBar的升級,使用起來也基本是一樣的。只是因為ActionBar在實際使用過程中的各種問題,才推出了ToolBar來接替ActionBar。ActionBar通常翻譯為操作欄,而到了ToolBar則翻譯為工具欄,這里我們統(tǒng)稱為工具欄。
添加和隱藏工具欄
在Toolbar引入之前,添加ActionBar是通過Theme來實現(xiàn)的,在Manifest文件中指定Application或者Activity的Theme為Theme.Holo或者它的子類,運行以后ActionBar會自動添加進(jìn)來。移除ActionBar也可以通過指定theme的方式,設(shè)置為Theme.Holo.NoActionBar?;蛘呤褂脛討B(tài)方式,先獲取到ActionBar,然后設(shè)置隱藏
ActionBar actionBar = getActionBar();
actionBar.hide();
ToolBar的引入之后,Android已經(jīng)不推薦我們這么操作了。應(yīng)該采用ToolBar的方式來管理工具欄
為了能更好的向下兼容,官方推薦我們使用 v7 appcompat 來添加和管理ToolBar。添加ToolBar的步驟如下:
按照支持庫設(shè)置中所述向您的項目添加 v7 appcompat 支持庫。
確保 Activity 可以擴(kuò)展 AppCompatActivity:
public class MyActivity extends AppCompatActivity {
// ...
}
注:請為您應(yīng)用中每個使用 Toolbar 作為應(yīng)用欄的 Activity 進(jìn)行此更改。
- 在應(yīng)用清單中,將 <application> 元素設(shè)置為使用 appcompat 的其中一個 NoActionBar 主題。使用這些主題中的一個可以防止應(yīng)用使用原生 ActionBar 類提供應(yīng)用欄。例如:
<application
android:theme="@style/Theme.AppCompat.Light.NoActionBar"
/>
到這里為止,所做的工作是確保Activity中不包含默認(rèn)的ActionBar,否則會引起崩潰。如果想保留theme,而這個theme又是包含ActionBar的,可以在Activity中調(diào)用requestWindowFeature(Window.FEATURE_NO_TITLE);,如果是繼承在AppCompatActivity,調(diào)用supportRequestWindowFeature(Window.FEATURE_NO_TITLE),這樣就可以去掉theme中自帶的ActionBar了
- 向 Activity 的布局添加一個 Toolbar。例如,以下布局代碼可以添加一個 Toolbar 并賦予其浮動在 Activity 之上的外觀:
< android.support.v7.widget.Toolbar
android:id="@+id/my_toolbar"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
android:background="?attr/colorPrimary"
android:elevation="4dp"
android:theme="@style/ThemeOverlay.AppCompat.ActionBar"
app:popupTheme="@style/ThemeOverlay.AppCompat.Light"/>
Material Design 規(guī)范建議應(yīng)用欄具有 4 dp 的仰角。
將工具欄定位在 Activity 布局的頂部,因為您要使用它作為應(yīng)用欄。
- 在 Activity 的 onCreate() 方法中,調(diào)用 Activity 的 setSupportActionBar() 方法,然后傳遞 Activity 的工具欄。該方法會將工具欄設(shè)置為 Activity 的應(yīng)用欄。
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_my);
Toolbar myToolbar = (Toolbar) findViewById(R.id.my_toolbar);
setSupportActionBar(myToolbar);
ActionBar actionBar = getSupportActionBar();
actionBar.hide();
}
設(shè)置好ToolBar之后,如果想對他進(jìn)行操作,再使用getSupportActionBar獲取到ActionBar對象,就可以按照ActionBar的操作方式來管理工具欄了
可以看出來,ToolBar可以作為一個UI單元,可以很方便的對每個Activity進(jìn)行單獨設(shè)定管理,不再像ActionBar一樣,只能通過主題來管理。當(dāng)然,如果對工具欄要求不高,仍然可以使用主題來指定ActionBar,但是要注意,如果你的Activity繼承自AppCompatActivity,使用的主題應(yīng)該是Theme.AppCompat.,如果直接繼承自Activity,用Theme.AppCompat.是不起作用的!
管理工具欄
一個完整的工具欄主要組成部分如下:

現(xiàn)在我們來依次看一下各個部分是怎樣設(shè)置的
-
Navigation
這是工具欄的層級導(dǎo)航功能,類似于按下Back鍵,但是,與Back鍵不同,這里需要我們指定返回的Activity。在Manifest文件里設(shè)置:
<activity
android:name=".model.fragment.LandViewActivity"http://包含ToolBar的當(dāng)前Activity
android:parentActivityName=".SplashActivity"http://按下導(dǎo)航鍵返回的目標(biāo)Activity
>
<!-- Parent activity meta-data to support 4.0 and lower -->
<meta-data
android:name="android.support.PARENT_ACTIVITY"
android:value=".SplashActivity" />
</activity>
這樣,層級導(dǎo)航的功能設(shè)置就完成了。當(dāng)然還需要設(shè)置Navigation,如果不想使用默認(rèn)的導(dǎo)航圖標(biāo),也可以自己在layout文件中指定:
app:navigationIcon="@drawable/ic_action_nav"
注意:使用ToolBar的時候,如果在Layout文件中沒有設(shè)置NavigationIcon,工具欄是不會顯示Navigation按鍵的。如果不想自定義圖標(biāo),可以在獲取到ActionBar對象之后,設(shè)置actionBar.setDisplayHomeAsUpEnabled(true)來啟用Navigation功能,這樣就可以使用系統(tǒng)自帶的圖標(biāo)了。如果我們使用是ActionBar主題,Navigation功能默認(rèn)是啟用的,設(shè)置parentActivity就可以了
Navigation返回的Activity并不是返回棧里存在的實例,而是重新創(chuàng)建的Activity,也就是說,之前Activity存在的狀態(tài),從Navigation返回之后,并不會保存下來
-
Logo和Title
這兩項的設(shè)置非常簡單,可以在layout文件中設(shè)置,也可以在代碼中對ActionBar對象進(jìn)行設(shè)置,就不再介紹了。
-
Menu
在工具欄上可以設(shè)置多個按鈕,Menu就是由這些按鈕組成的。
要在工具欄上添加按鍵,需要先指定Menu文件,menu文件需要定義在res/menu文件夾下(toolbar_menu.xml):
<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto">
<item
android:id="@+id/add_item"
android:icon="@drawable/ic_action_new"
android:title="Add"
app:showAsAction="ifRoom|withText"
/>
<item
android:id="@+id/remo_item"
android:icon="@drawable/ic_action_remove"
android:title="Remove"
app:showAsAction="ifRoom|withText"
/>
<item
android:id="@+id/more_item"
android:icon="@drawable/ic_action_more"
android:title="Remove"
app:showAsAction="never"
/>
</menu>
注意,因為例子中使用是v7支持庫,需要使用app命名空間。如果不使用支持庫可以直接使用android。app:showAsAction指定了按鍵的顯示方式。因為工具欄空間相對有限,我們可指定按鍵的顯示方式,never表示總在overflow menu中顯示,always表示總在工具欄顯示,ifRoom表示空間足夠則顯示在工具欄上,withText表示空間足夠的時候顯示Title,也可以用組合的方式:ifRoom|withTitle
Menu定義好之后,在Activity中添加并引用它:
@Override
public boolean onCreateOptionsMenu(Menu menu) {
MenuInflater inflater = getMenuInflater();
inflater.inflate(R.menu.toobar_menu,menu);
return super.onCreateOptionsMenu(menu);
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()){
case R.id.add_item:
Toast.makeText(this,"Add button clicked",Toast.LENGTH_SHORT).show();
break;
case R.id.remo_item:
Toast.makeText(this,"Add button clicked",Toast.LENGTH_SHORT).show();
break;
case R.id.more_item:
Toast.makeText(this,"Add button clicked",Toast.LENGTH_SHORT).show();
break;
default:
break;
}
return super.onOptionsItemSelected(item);
}
這里是在Activity中直接加載menu,如果是Fragment中使用,會有所不同。Fragment中必須設(shè)置setHasOptionsMenu(true),它用來通知FragmentManager,當(dāng)前Fragment需要調(diào)用onCreateOptionsMenu方法。
-
Navigation和Menu的關(guān)系
實際上Navigation也屬于menu,它的id是android.R.id.home,可以在onOptionsItemSelected中對它進(jìn)行監(jiān)聽
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;
......
}
}
調(diào)用NavUtils.getParentActivityIntent()方法可以獲取到跳轉(zhuǎn)至父Activity的Intent,然后如果父Activity和當(dāng)前Activity是在同一個Task中的,則直接調(diào)用navigateUpTo()方法進(jìn)行跳轉(zhuǎn),如果不是在同一個Task中的,則需要借助TaskStackBuilder來創(chuàng)建一個新的Task。
OverFlow按鈕顯示圖標(biāo)
overflow中的按鈕默認(rèn)是不顯示圖標(biāo)的,它由MenuBuilder這個類的setOptionalIconsVisible方法來決定,如果我們在overflow被展開的時候給這個方法傳入true,那么里面的每一個Action按鈕對應(yīng)的圖標(biāo)就都會顯示出來了。
@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);
}