Android開發之ActionBar與DrawerLayout
ActionBar位於Activity的頂部,可用來顯示activity的標題、Icon、Actions和一些用於互動的View。它也可被用於應用的導航。
ActionBar 是在Android 3.0(API 11)中加入到SK中的,想在低版本中使用ActionBar給專案匯入Support Library v7包即可。
使用ActionBar
開發API11以下的程式,首先必須在AndroidManifest.xml中指定Application或Activity的theme是Theme.Holo或其子類,否則將無法使用ActionBar。
如:
<application
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:theme="@style/Theme.AppCompat.Light"
android:name=".BaseApplication"
>
2.1 建立Actions
Actions即ActionBar中的每個互動項,通常在XML檔案中指定(位於res/menu)。在menu資原始檔中定義Action的方法如下:
<menu xmlns:android ="http://schemas.android.com/apk/res/android"
xmlns:wangxiapp="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
tools:context=".MainActivity">
<item android:id="@+id/action_search"
android:icon="@mipmap/ic_action_search" //搜尋圖示的圖片
android:title ="research"
android:orderInCategory="100" //此item在ActionBar的位置。當有多個item時越大越在後面
wangxiapp:showAsAction="ifRoom"
/>
</menu>
showAsAction屬性用來定義每個Action是如何顯示的,always表示永遠顯示在ActionBar中,如果螢幕空間不夠則無法顯示,ifRoom表示螢幕空間夠的情況下顯示在ActionBar中.
在Activity中建立ctionBar的Action程式碼位於onCreateOptionsMenu()中,下面一段程式碼展示了建立過程:
@Override
public boolean onCreateOptionsMenu(Menu menu) {
MenuInflater inflater = getMenuInflater();
inflater.inflate(R.menu.mainmenu, menu); //第一個引數設定ActionBar最左邊的圖片
return true;
}
有的時候由於一些特殊原因,最左邊的圖片,即應用的圖示不顯示,此時需要一些設定。在MainActivity中新增如下程式碼:
actionBar = getSupportActionBar();
actionBar.setLogo(R.mipmap.ic_launcher);
actionBar.setDisplayUseLogoEnabled(true);
actionBar.setDisplayShowHomeEnabled(true);
執行效果如圖:
現在我們看到了設定的圖片,但沒有看的我們在item中設定的title。原因是:
如果你的menu既提供了title又提供了icon屬性,那麼預設顯示icon,如果你想要顯示文字title,就新增”withText”屬性,如下:
1 <item yourapp:showAsAction="ifRoom|withText" ... />
備註:“withText”屬性是給action bar的一個暗示,告訴它應該顯示文字title,如果可以的話,就顯示,但是當icon是可用的並且action bar的空間受到限制的時候,就不一定會顯示了。
你應該為每一個item宣告title屬性,即使你不宣告title要顯示,因為:
1)如果沒有足夠的空間顯示所有的action item,那顯示在overflow中的Item就只會顯示title,此時圖片會變成豎著的三個點,點選時就會顯示title;
2)視覺受損者會讀取title;
3)如果action item只顯示icon,那麼當用戶長按item的時候,會顯示一個小的提示視窗顯示action的title;
icon是可選的,但是推薦使用。
開發者可以使用”always”宣告一個Item永遠作為action button顯示,但是開發者不應該用它迫使item用這種方式顯示,在空間狹小的裝置上,這會引起佈局問題。最好的是使用”ifRoom”。這使得系統可以根據空間做出調整。只有當Item非常重要,關係到關鍵特徵的時候,才可以使用”always”。
當點選右邊搜尋圖片時設定監聽:程式碼如下:
//佈局做如下修改
<menu xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:wangxiapp="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
tools:context=".MainActivity">
<item android:id="@+id/action_search"
android:icon="@mipmap/ic_action_search"
android:title="@string/action_settings"
android:orderInCategory="100"
wangxiapp:showAsAction="ifRoom"
wangxiapp:actionViewClass="android.support.v7.widget.SearchView"
/>
</menu>
//Activty如下操作
@Override
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.menu_main, menu);
//獲取SearchView
SearchView searchView = (SearchView) menu.findItem(R.id.action_search).getActionView();
//設定搜尋的監聽
searchView.setOnQueryTextListener(new SearchView.OnQueryTextListener() {
//當搜尋提交的時候
@Override
public boolean onQueryTextSubmit(String query) {
ToastUtil.showToast(UiUtil.getContext(), query);
return true;
}
//當搜尋文字改變的時候
@Override
public boolean onQueryTextChange(String newText) {
ToastUtil.showToast(UiUtil.getContext(), newText);
return true;
}
});
return true;
}
如果一個Action被單擊,對於activity中的onOptionsItemSelected()將被呼叫。該函式的傳入引數是一個MenuItem。通過判斷該MenuItem的Id,即可確認是哪個Action被單擊。現在我們通過這個事件來處理通過點選ActionBar的箭頭來返回上一個Activity
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
android.support.v7.app.ActionBar actionBar = getSupportActionBar();
actionBar.setLogo(R.mipmap.ic_launcher);
//顯示返回主介面的箭頭
actionBar.setDisplayUseLogoEnabled(true);
actionBar.setDisplayShowHomeEnabled(true);
actionBar.setDisplayHomeAsUpEnabled(true);
}
//ActionBar的點選監聽
@Override
public boolean onOptionsItemSelected(MenuItem item) {
//ActionBar的唯一id android.R.id.home
if (item.getItemId()==android.R.id.home){
finish();
}
return true;
}
這樣就可以在其他Activity中通過點選ActionBar來完成返回上個Activity。其實onOptionsItemSelected()這個可以在其他Activity中省略的。在清單檔案中為該Activity設定(即可以完成點選Activty返回上個介面):
<activity android:name=".DetailActivity"
android:parentActivityName=".MainActivity"
>
<meta-data
android:name="android.support.PARENT_ACTIVITY"
android:value=".MainActivity"
/>
</activity>
3 .實現ActionBar Tab標籤
1 在Drawable 目錄下 寫了一個標籤的狀態選擇器
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<!-- STATES WHEN BUTTON IS NOT PRESSED -->
<!-- Non focused states -->
<item android:state_focused="false" android:state_selected="false"
android:state_pressed="false"
android:drawable="@mipmap/tab_unselected" />
<item android:state_focused="false" android:state_selected="true"
android:state_pressed="false"
android:drawable="@mipmap/tab_selected" />
<!-- Focused states (such as when focused with a d-pad or mouse hover) -->
<item android:state_focused="true" android:state_selected="false"
android:state_pressed="false"
android:drawable="@mipmap/tab_unselected_focused" />
<item android:state_focused="true" android:state_selected="true"
android:state_pressed="false"
android:drawable="@mipmap/tab_selected_focused" />
<!-- STATES WHEN BUTTON IS PRESSED -->
<!-- Non focused states -->
<item android:state_focused="false" android:state_selected="false"
android:state_pressed="true"
android:drawable="@mipmap/tab_unselected_pressed" />
<item android:state_focused="false" android:state_selected="true"
android:state_pressed="true"
android:drawable="@mipmap/tab_selected_pressed" />
<!-- Focused states (such as when focused with a d-pad or mouse hover) -->
<item android:state_focused="true" android:state_selected="false"
android:state_pressed="true"
android:drawable="@mipmap/tab_unselected_pressed" />
<item android:state_focused="true" android:state_selected="true"
android:state_pressed="true"
android:drawable="@mipmap/tab_selected_pressed" />
</selector>
2 實現自定義主題 (在values下建立resources)
<?xml version="1.0" encoding="utf-8"?>
<resources>
<!-- the theme applied to the application or activity -->
<style name="CustomActionBarTheme"
parent="@style/Theme.AppCompat.Light">
<item name="android:actionBarTabStyle">@style/MyActionBarTabs</item>
<!-- Support library compatibility -->
<item name="actionBarTabStyle">@style/MyActionBarTabs</item>
</style>
<!-- ActionBar tabs styles -->
<style name="MyActionBarTabs"
parent="@style/Widget.AppCompat.ActionBar.TabView">
<!-- tab indicator -->
<item name="android:background">@drawable/actionbar_tab_indicator</item>
<!-- Support library compatibility -->
<item name="background">@drawable/actionbar_tab_indicator</item>
</style>
</resources>
3.在Activity中設定:
ActionBar actionBar = getSupportActionBar();
actionBar.setNavigationMode(ActionBar.NAVIGATION_MODE_TABS);
ActionBar.Tab tab1 = actionBar.newTab().setText("標籤一").setTabListener(new MyTabListener());
actionBar.addTab(tab1);
ActionBar.Tab tab2 = actionBar.newTab().setText("標籤二").setTabListener(new MyTabListener());
actionBar.addTab(tab2);
ActionBar.Tab tab3 = actionBar.newTab().setText("標籤三").setTabListener(new MyTabListener());
actionBar.addTab(tab3);
ActionBar.Tab tab4 = actionBar.newTab().setText("標籤四").setTabListener(new MyTabListener());
actionBar.addTab(tab4);
DrawerLayout (抽屜效果):
<android.support.v4.widget.DrawerLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity"
android:id="@+id/dl">
<LinearLayout
//這裡的LinearLayout是一開始是看見的主佈局
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_centerHorizontal="true"
android:layout_centerVertical="true"
/>
<FrameLayout
//這個佈局就是抽屜,即通過測拉才可以顯示的佈局
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@drawable/bg_tab"
//抽屜在左邊
android:layout_gravity="left">
</FrameLayout>
</android.support.v4.widget.DrawerLayout>
給抽屜設定監聽:
ActionBarDrawerToggle :
控制抽屜的開關, 顯示在actionBar 上面 (即通過點選就可以開啟和關閉抽屜):
ActionBar actionBar = getSupportActionBar();
//設定顯示ActionBar的點選圖示沒,如下圖的最左邊的圖示
actionBar.setDisplayHomeAsUpEnabled(true);
actionBar.setHomeButtonEnabled(true);
DrawerLayout drawerLayout = (DrawerLayout) findViewById(R.id.drawerLayout);
actionBarDrawerToggle = new ActionBarDrawerToggle(MainActivity.this, drawerLayout, R.string.app_name, R.string.app_name){
// 建立時就可以設定抽屜的監聽。關閉監聽
@Override
public void onDrawerClosed(View drawerView) {
super.onDrawerClosed(drawerView);
ToastUtil.showToast(MainActivity.this,"close");
}
//開啟監聽
@Override
public void onDrawerOpened(View drawerView) {
super.onDrawerOpened(drawerView);
ToastUtil.showToast(MainActivity.this, "open");
}
};
// 讓開關和Actionbar建立關係
actionBarDrawerToggle.syncState();
//設定監聽
drawerLayout.setDrawerListener(actionBarDrawerToggle);
/** 處理actionBar選單條目的點選事件 */
public boolean onOptionsItemSelected(MenuItem item) {
if (item.getItemId() == R.id.action_search) {
Toast.makeText(getApplicationContext(), "搜尋", 0).show();
}
//返回值很重要
return drawerToggle.onOptionsItemSelected(item)|super.onOptionsItemSelected(item);
}