Navigation Drawer "導覽抽屜",啊~就是隱藏式側選單啦。官方說法是,一個從螢幕左邊轉換而來的面板,用來顯示 App 主要的導覽選項。
顯示 navigation drawer 有兩種方法,從螢幕左邊往右滑,或觸碰 ActionBar 上的 app icon。navigation drawer 會從 ActionBar 下方展開,蓋在原本畫面之上,如下圖:
圖片來源:http://developer.android.com/design/media/navigation_drawer_overview.png
要關閉 navigation drawer,有以下幾種方式:
- 觸碰 navigation drawer 之外的畫面
- 在螢幕上往左滑
- 觸碰 ActionBar 的 app icon
- 按下 Back 按鈕
關於 Navigation Drawer
使用 Navigation Drawer 的時機
1. 超過 3 個頂層(top-level)的畫面
也就是你有超過 3 個主要功能,它們都處於同一階層的時候才用。2. 在較低階層時橫跨導覽
例如:你從A頁面一路進入到A1 -> A2 -> A3,接著你想從 A3 直接跳到 D1。 圖片來源:http://developer.android.com/design/media/navigation_drawer_cross_nav.png
3. 深度的導覽分支
例如:你從A頁面一路進入到A1 -> A2 -> A3,接著你想從 A3 直接跳回到最上層的 A。 圖片來源:http://developer.android.com/design/media/navigation_drawer_quick_to_top.png
做為導覽樞紐
Navigation Drawer 直接反射了你 App 的結構,可以讓使用者更容易以 navigation drawer 為樞紐,在各階層的畫面中快速的切換。Navigation Drawer 的內容
Navigation Drawer 以清單方式呈現,可以有 標題、圖示及計數器,也可以合併相關的項目,成為一個下拉式選單。Navigation Drawer 和 ActionBar
為了避免使用者產生迷惑,原本在 ActionBar 上顯示的該頁標題及 Action 選單按鈕,應該在使用者開啟 navigation drawer 時改變為 App 名稱及 Action overflow,而 overflow 中只顯示「設定」或「幫助」等項目。Style
官方文件中對 Navigation Drawer 的風格有些標準的設計規則。例如:Navigation Drawer 的寬度應該在 240 dp 到 320 dp 之間,每個項目的高度不小於 48 dp。建立 Navigation Drawer
Layout
要建立 Navigation Drawer 必須使用 Support Library 中的 DrawerLayout,以 DrawerLayout 物件當作根畫面(root view)的 layout,在其中包含一個用來顯示主要內容的 view,而另外一個 view 則是包含 navigation drawer 的內容。所以 layout 會是這樣(drawer.xml):<android.support.v4.widget.DrawerLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/drawer_layout"
android:layout_width="match_parent"
android:layout_height="match_parent">
<!-- The main content view -->
<FrameLayout
android:id="@+id/content_frame"
android:layout_width="match_parent"
android:layout_height="match_parent" />
<!-- The navigation drawer -->
<ListView android:id="@+id/left_drawer"
android:layout_width="240dp"
android:layout_height="match_parent"
android:layout_gravity="start"
android:choiceMode="singleChoice"
android:divider="@android:color/transparent"
android:dividerHeight="0dp"
android:background="#111"/>
</android.support.v4.widget.DrawerLayout>
這裡有幾點必須注意的重點:
- 用來顯示主要內容的 view (即 FrameLayout) ,必須排在第一個,這是因為 XML 排序的關係,如此一來,之後的 navigation drawer 才會顯示在其上,蓋住它。
- 用來顯示主要內容的 view 的寬及高必須和父層的 view 一樣(即 match_parent)。
- drawer view (即 ListView) 必須指定 horizontal gravity (即 android:layout_gravity屬性),其值為 "start",不要用 "left",這樣在由右到左(RTL)的語言中,選單就會從右邊出現。
- drawer view 的寬度以 dp 為單位,高度則符合父層的 view。寬度不能超過 320 dp。
Activity
有點要注意的地方,這裡為了舉例方便,範例使用的 SDK 最小版本為 11,這是為了可以直接取用 ActionBar ,如果要在更舊的版本中執行,必須搭配 ActionBarCompat 來使用,使用方式請參考 [Android]使用 ActionBarCompat 製作導覽列(1)。首先讓 Drawer 能出現,程式碼如下:
MainActivity.java
public class MainActivity extends Activity ActionBarActivity {
private DrawerLayout layDrawer;
private ListView lstDrawer;
private ActionBarDrawerToggle drawerToggle;
private CharSequence mDrawerTitle;
private CharSequence mTitle;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
initActionBar();
initDrawer();
initDrawerList();
}
private void initActionBar(){
getActionBar().setDisplayHomeAsUpEnabled(true);
getActionBar().setHomeButtonEnabled(true);
}
private void initDrawer(){
setContentView(R.layout.drawer);
layDrawer = (DrawerLayout) findViewById(R.id.drawer_layout);
lstDrawer = (ListView) findViewById(R.id.left_drawer);
layDrawer.setDrawerShadow(R.drawable.drawer_shadow, GravityCompat.START);
mTitle = mDrawerTitle = getTitle();
drawerToggle = new ActionBarDrawerToggle(
this,
layDrawer,
R.drawable.ic_drawer,
R.string.drawer_open,
R.string.drawer_close) {
@Override
public void onDrawerClosed(View view) {
super.onDrawerClosed(view);
getActionBar().setTitle(mTitle);
}
@Override
public void onDrawerOpened(View drawerView) {
super.onDrawerOpened(drawerView);
getActionBar().setTitle(mDrawerTitle);
}
};
drawerToggle.syncState();
layDrawer.setDrawerListener(drawerToggle);
}
private void initDrawerList(){
String[] drawer_menu = this.getResources().getStringArray(R.array.drawer_menu);
ArrayAdapter<String> adapter = new ArrayAdapter<String>(this, R.layout.drawer_list_item, drawer_menu);
lstDrawer.setAdapter(adapter);
}
}
執行畫面:
說明:initActionBar() 中,讓 ActionBar 的返回箭號顯現,並且讓 App icon 可以被點選。
接著 initDrawer(),讓側選單能夠出現。先將 layout 指定為我們建立的 drawer.xml 。layDrawer.setDrawerShadow() 用來設定側選單被開啟時的陰影。
建立側選單觸發器, 其中會將 DrawerLayout(layDrawer) 及 R.drawable.ic_drawer (側選單的三條線圖示) 等等參數指定給 ActionBarDrawerToggle 。然後要覆寫兩個方法,分別是開啟側選單 onDrawerOpened 及關閉側選單 onDrawerClosed。通常會在其中更新 ActionBar 的標題,或是顯示相關的 Action button。
最後,記得呼叫 drawerToggle.syncState(); 讓 ActionBar 中的返回箭號置換成 Drawer 的三條線圖示。並且把這個觸發器指定給 layDrawer 。
到目前為止就能執行了,可以從左邊往右滑出選單,但選單是空的。
在 initDrawerList() 中,就只簡單的把字串陣列建立一個 adapter 送給 lstDrawer 來顯示。這裡要在資源檔中加入一些資料,打開 res/values/strings.xml ,然後輸入以下文字:
<string name="drawer_open">Open navigation drawer</string>
<string name="drawer_close">Close navigation drawer</string>
<string-array name="drawer_menu">
<item>Apple</item>
<item>Book</item>
<item>Cat</item>
<item>Dog</item>
<item>Eagle</item>
<item>Food</item>
<item>God</item>
<item>House</item>
<item>Iron</item>
<item>Jingle</item>
</string-array>
還要建立一個給 list item 用的 layout,drawer_list_item.xml:
<?xml version="1.0" encoding="utf-8"?>
<TextView xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/txtItem"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_alignParentLeft="true"
android:layout_alignParentTop="true"
android:padding="10dp"
android:text="Item"
android:textAppearance="?android:attr/textAppearanceMedium"
android:textColor="#cccccc" />
單單一個 TextView 而以。如此,一個基本的側選單的就製完成了。
續:使用 Android Navigation Drawer 製作側選單(2)
本文網址:https://blog.tonycube.com/2014/02/android-navigation-drawer-1.html
由 Tony Blog 撰寫,請勿全文複製,轉載時請註明出處及連結,謝謝 😀
由 Tony Blog 撰寫,請勿全文複製,轉載時請註明出處及連結,謝謝 😀
(留這系統有問題,以下為手動還原)
回覆刪除=================================================
(Flying Nick)
感謝版主的中文說明,很實用,謝謝!
版主你好,執行時getActionBar().setDisplayHomeAsUpEnabled(true);此行出現錯誤訊息,可以請問一下如何解決嗎?
回覆刪除以下錯誤訊息:
java.lang.NullPointerException: Attempt to invoke virtual method 'void android.app.ActionBar.setDisplayHomeAsUpEnabled(boolean)' on a null object reference
Android 最近這幾版的改版中對 ActionBar 做了一些調整,
刪除所以要先確定你是在哪個版本上使用 ActionBar,
你可以參考這篇(http://blog.tonycube.com/2015/06/android-navigation-drawer-toolbar.html),
因為 Android 5.x 之後已經改用 Toolbar 了。
版主你好,我再匯入android-support-v7-appcompat 後
回覆刪除我專案的r檔就會消失,請問該如何解決
我專案是剛開起來,只會加了一個toolbar.xml
其他程式碼都還沒加,就出錯了
通常是版本不對或衝突,你的 v7 和 v4 版本對不上,
刪除你可以去 SDK 目錄下 extras -> android -> support,
在v4目錄下只會有 v4 的 support 檔,不要用這個,
去 v7 的 appcompat/libs 目錄下,應該會同時有 v4及v7 兩個檔,
把專案中的換成這同一組檔案,應該能解決。
作者已經移除這則留言。
回覆刪除注意你使用的(import)是哪個版本的Activity,用到不同API版本的類別,會無法呼叫。
刪除layDrawer 問題也相同,注意 API 版本,是否有用到 support lirbary 的類別。
這邊顯示紅字
回覆刪除layDrawer.setDrawerShadow(R.drawable.drawer_shadow, GravityCompat.START); 裡面的 drawer_shadow顯示紅字
&&
R.drawable.ic_drawer,
裡面的 ic_drawer 顯示紅字
我嘗試按ALT+Enter開啟新的ic_drawer.xml && drawer_shadow.xml
都無濟與事
請問該怎麼解決好
我的Android Studio版本是 2.1.1
看看你的 import 是不是你自己的 package名稱.R
刪除錯誤應該是 import 了 android.R
在續篇裡面有範例下載 https://github.com/tony915/NavigationDrawerDemo
刪除在 res/drawable-xxxx 4個目錄裡面有 ic_drawer.png ,你可能少了這個圖檔,
drawer_shadow 也是一樣,它是陰影。前面那位朋友應該也是一樣問題。
我是遇到↓這個問題,想請問一下這是為什麼?
回覆刪除java.lang.RuntimeException: Unable to start activity ComponentInfo{com.tonycube.demo.navigationdrawerdemo/com.tonycube.demo.navigationdrawerdemo.MainActivity}: java.lang.IllegalArgumentException: AppCompat does not support the current theme features
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2693)
at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2758)
at android.app.ActivityThread.access$900(ActivityThread.java:177)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1448)
at android.os.Handler.dispatchMessage(Handler.java:102)
at android.os.Looper.loop(Looper.java:145)
at android.app.ActivityThread.main(ActivityThread.java:5942)
at java.lang.reflect.Method.invoke(Native Method)
at java.lang.reflect.Method.invoke(Method.java:372)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1400)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1195)
Caused by: java.lang.IllegalArgumentException: AppCompat does not support the current theme features
at android.support.v7.app.AppCompatDelegateImplV7.ensureSubDecor(AppCompatDelegateImplV7.java:363)
at android.support.v7.app.AppCompatDelegateImplV7.setContentView(AppCompatDelegateImplV7.java:246)
at android.support.v7.app.AppCompatActivity.setContentView(AppCompatActivity.java:106)
at com.tonycube.demo.navigationdrawerdemo.MainActivity.onCreate(MainActivity.java:36)
at android.app.Activity.performCreate(Activity.java:6289)
at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1119)
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2646)
at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2758)
at android.app.ActivityThread.access$900(ActivityThread.java:177)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1448)
at android.os.Handler.dispatchMessage(Handler.java:102)
at android.os.Looper.loop(Looper.java:145)
at android.app.ActivityThread.main(ActivityThread.java:5942)
at java.lang.reflect.Method.invoke(Native Method)
at java.lang.reflect.Method.invoke(Method.java:372)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1400)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1195)
看一下 build.gradle 中的 dependencies 裡面,
刪除com.android.support:appcompat-v7:
com.android.support:design:
com.android.support:support-v4:
是不是都有使用最新版本,SDK 記得要先更新。
或是調整 theme.xml 裡的設定,
這個問題是 theme 用了這個 API 等級沒有的功能。
版主你好,我是這邊drawerToggle = new ActionBarDrawerToggle(
回覆刪除this,
layDrawer,
R.drawable.ic_drawer,
R.string.drawer_open,
R.string.drawer_close)
參數那幾行出現紅字,然後下面跳出訊息說ActionBarDrawerToggle() in ActionBarDrawerToggle cannot be applied to:
Expected Parameters:
Actual Arguments:
activity:
Activity
this
drawerLayout:
DrawerLayout
layDrawer
toolbar:
android.support.v7.widget.Toolbar
R.drawable.ic_drawer (int)
openDrawerContentDescRes:
int
R.string.drawer_open
closeDrawerContentDescRes:
int
R.string.drawer_close
toobar那裡顯示的參數是紅色的,好像是第三個參數有問題,想請問該如何解決?
是參數問題,但你貼的內容我看不出原因,
刪除可能要檢查其他地方的程式碼,例如你的 Activity 是不是 extends ActionBarActivity
我貼的程式碼好像有問題,
你可以直接下載前一篇的範例 https://github.com/tony915/NavigationDrawerDemo
這是舊 Eclipse 專案,AS 要用匯入 Eclipse 專案的方式。
drawer.xml 要去哪裡找....
回覆刪除請自行建立,像範例一樣。
刪除