Android開發(fā):最詳細(xì)的 NavigationDrawer 開發(fā)實(shí)踐總結(jié)

最詳細(xì)的 NavigationDrawer 開發(fā)實(shí)踐總結(jié)

繼前面寫的兩篇文章之后(有問題歡迎反饋哦):

  1. Android開發(fā):Translucent System Bar 的最佳實(shí)踐
  2. Android開發(fā):最詳細(xì)的 Toolbar 開發(fā)實(shí)踐總結(jié)

接著來寫寫Android系統(tǒng)UI新特性,本文是我對最近開發(fā)過程中應(yīng)用 NavigationDrawer 特性的詳細(xì)總結(jié)。本文涉及到的所有代碼實(shí)現(xiàn)細(xì)節(jié),會在文末附上源碼地址。有問題歡迎在下方留言討論 。

NavigationDrawer 簡介

NavigationDrawer 是 Google 在 Material Design 中推出的一種側(cè)滑導(dǎo)航欄設(shè)計風(fēng)格。說起來可能很抽象,我們直接來看看 網(wǎng)易云音樂 的側(cè)滑導(dǎo)航欄效果

網(wǎng)易云音樂側(cè)滑導(dǎo)航欄效果

Google 為了支持這樣的導(dǎo)航效果,推出一個新控件 —— DrawerLayout 。而在 DrawerLayout 沒誕生之前,需求中需要實(shí)現(xiàn)側(cè)滑導(dǎo)航效果時,我們必然會選擇去選擇一些成熟的第三方開源庫(如最有名的 SlidingMenu)來完成開發(fā) 。效果上,普遍都像 手Q 那樣:

手Q的SlidingMenu實(shí)現(xiàn)側(cè)滑效果

在對比過 DrawerLayoutSlidingMenu 的實(shí)現(xiàn)效果后,基于以下的幾點(diǎn),我認(rèn)為完全可以在開發(fā)中使用 DrawerLayout 取代以前的 SlidingMenu

  1. 從動畫效果上看,你會發(fā)現(xiàn)兩者僅僅是在移動的效果上有些差別外,其他地方并沒有太大的差異
  2. 在交互效果上,我認(rèn)為這兩者都差不多的,就算你把 網(wǎng)易云音樂 的效果套到了 手Q 上,也不會影響到用戶的交互
  3. DrawerLayout 用起來比 SlidingMenu 更簡單,代碼量更少(往下看就知道了)
  4. DrawerLayout 是向下兼容的,所以不會存在低版本兼容性問題
  5. Google 親兒子,沒理由不支持?。。。。。?!

到這里,要是你還沒有引入 DrawerLayout 開發(fā)的沖動,請繼續(xù)聽我為你好好安利一番。

初識 DrawerLayout

一般情況下,在 DrawerLayout 布局下只會存在兩個子布局,一個 內(nèi)容布局 和 一個 側(cè)滑菜單布局,這兩個布局關(guān)鍵在于 android:layout_gravity 屬性的設(shè)置。如果你想把其中一個子布局設(shè)置成為左側(cè)滑菜單,只需要設(shè)置 android:layout_gravity="start" 即可(也可以是 left,右側(cè)滑則為 end 或 right ),而沒有設(shè)置的布局則自然成為 內(nèi)容布局 。那么,使用 DrawerLayout 到底有多簡單呢,我們先直接看看下面的布局文件

layout/activity_simple_drawer.xml


<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <android.support.v4.widget.DrawerLayout
        android:id="@+id/simple_navigation_drawer"
        android:layout_width="match_parent"
        android:layout_height="match_parent">

        <!--內(nèi)容視圖-->
        <include
            android:id="@+id/tv_content"
            layout="@layout/drawer_content_layout"
            android:layout_width="match_parent"
            android:layout_height="match_parent" />

        <!--左側(cè)滑菜單欄-->
        <include
            layout="@layout/drawer_menu_layout"
            android:layout_width="250dp"
            android:layout_height="match_parent"
            android:layout_gravity="start" />

        <!--右側(cè)滑菜單欄-->
        <include
            layout="@layout/drawer_menu_layout"
            android:layout_width="250dp"
            android:layout_height="match_parent"
            android:layout_gravity="end" />
    </android.support.v4.widget.DrawerLayout>

</RelativeLayout>

到此,你在 Activity 里面什么都不用做,就已經(jīng)完成了下面?zhèn)然Ч膶?shí)現(xiàn)了,簡單到害怕有木有。

最簡單的側(cè)滑效果實(shí)現(xiàn)

在欣賞著 DrawerLayout 簡單方便的同時,Google 也為我們提供了 DrawerLayout 很多常用的API,其中包括:打開或關(guān)閉側(cè)滑欄、控制側(cè)滑欄的方向、設(shè)置滑動時漸變的陰影顏色和監(jiān)聽滑動事件等。

SimpleDrawerActivity運(yùn)行效果

具體詳細(xì)代碼請參加工程中的 SimpleDrawerActivity,此處就不貼代碼了。還有一處 DrawerLayout 使用的小細(xì)節(jié)需要溫馨提醒一下,有一次,我手誤把 DrawerLayoutandroid:layout_width 設(shè)置成 wrap_content,就出現(xiàn)下面的異常了

DrawerLayout的wrap_content錯誤

遇到過相同情況的童鞋,只需要把 android:layout_width 設(shè)置成 match_parent 即可。

再識 NavigationView

在 Google 推出 NavigationDrawer 設(shè)計中,NavigationViewDrawerLayout 是官方推薦的最佳組合。在使用 NavigationView 前,因?yàn)樗窃?Material Design 的兼容包中,所以需要先在 build.gradle 中引入

    compile 'com.android.support:design:23.1.1'

這里因?yàn)槲夜こ膛渲玫?compileSdkVersion23 ,所以需要引入 com.android.support:design:23.x.x 的版本。需要吐槽的是,這里如果你引入了 com.android.support:design:23.1.0 ,工程運(yùn)行后 NavigationView 會報一個 android.view.InflateException:xxxxxx 的錯誤(又是一個大坑)。

接下來簡單的介紹一下 NavigationView 的使用,我們繼續(xù)看看幾個相關(guān)布局文件 layout/activity_simple_navigation_drawer.xml、layout/navigation_drawer_header.xml、menu/navigation_drawer_menu.xml 和 實(shí)現(xiàn)效果:

layout/activity_simple_navigation_drawer.xml


<?xml version="1.0" encoding="utf-8"?>
<android.support.v4.widget.DrawerLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:id="@+id/drawer"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:orientation="vertical">

        <TextView
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:gravity="center"
            android:text="NavigationDrawerContent" />
    </LinearLayout>

    <android.support.design.widget.NavigationView
        android:id="@+id/navigation_view"
        android:layout_width="wrap_content"
        android:layout_height="match_parent"
        android:layout_gravity="start"
        app:headerLayout="@layout/navigation_drawer_header"
        app:menu="@menu/navigation_drawer_menu" />

</android.support.v4.widget.DrawerLayout>

layout/navigation_drawer_header.xml


<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="250dp"
    android:background="@color/color_512da8">

    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignParentBottom="true"
        android:layout_alignParentLeft="true"
        android:layout_margin="10dp"
        android:text="HeaderLayout"
        android:textColor="@android:color/white"
        android:textSize="18sp" />
</RelativeLayout>

menu/navigation_drawer_menu.xml


<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android">

    <group android:checkableBehavior="single">
        <item
            android:id="@+id/item_green"
            android:icon="@mipmap/green"
            android:title="Green" />
        <item
            android:id="@+id/item_blue"
            android:icon="@mipmap/blue"
            android:title="Blue" />
        <item
            android:id="@+id/item_pink"
            android:icon="@mipmap/pink"
            android:title="Pink" />
    </group>

    <item android:title="SubItems">
        <menu>
            <item
                android:id="@+id/subitem_01"
                android:icon="@mipmap/ic_launcher"
                android:title="SubItem01" />
            <item
                android:id="@+id/subitem_02"
                android:icon="@mipmap/ic_launcher"
                android:title="SubItem02" />
            <item
                android:id="@+id/subitem_03"
                android:icon="@mipmap/ic_launcher"
                android:title="SubItem03" />
        </menu>
    </item>

    <item android:title="SubItems">
        <menu>
            <item
                android:id="@+id/subitem_04"
                android:icon="@mipmap/ic_launcher"
                android:title="SubItem04" />
            <item
                android:id="@+id/subitem_05"
                android:icon="@mipmap/ic_launcher"
                android:title="SubItem05" />
            <item
                android:id="@+id/subitem_06"
                android:icon="@mipmap/ic_launcher"
                android:title="SubItem06" />
        </menu>
    </item>
</menu>

最終得到下面的效果

activity_simple_navigation_drawer.xml實(shí)現(xiàn)效果

總的來說,NavigationView 比較關(guān)鍵的屬性就只有 app:headerLayoutapp:menu ,它們分別對應(yīng)效果圖中頂部的 紫色區(qū)域(layout/navigation_drawer_header.xml) 和 下方的 填充菜單項(xiàng)(menu/navigation_drawer_menu.xml)。其實(shí)是用起來也和 DrawerLayout 一樣,非常簡單。

不實(shí)用的 NavigationView

其實(shí)談到 NavigationView,個人認(rèn)為它設(shè)計并不實(shí)用,而且是比較呆板的。最直接的一點(diǎn)是,它的菜單圖標(biāo)

NavigationView默認(rèn)圖標(biāo)顏色

第一次運(yùn)行代碼的時候,把我五顏六色的圖標(biāo)居然跑出來這效果,差點(diǎn)沒一口水噴在屏幕上。好在代碼中可以調(diào)用下面這個API

    mNavigationView.setItemIconTintList(null);//設(shè)置菜單圖標(biāo)恢復(fù)本來的顏色

還原菜單圖標(biāo)廬山真面目。(著實(shí)看不懂 Google 的設(shè)計了...)

其次,是關(guān)于菜單相中圖標(biāo)大小和文字間距之類的設(shè)置,從 Google 的設(shè)計文檔來看,

NavigationView設(shè)計

NavigationView 基本已經(jīng)規(guī)定設(shè)置好了大小距離,留給我們可以改動的空間并不多。如果你想調(diào)整一下菜單的布局寬高之類的,基本是不可能的了(即使可能,也估計非常蛋疼)。所以,目前我基本還沒見過國內(nèi)哪個 app 是直接使用了 NavigationView 來做導(dǎo)航(如果有的話,歡迎告知一下)。

以上關(guān)于 NavigationView 不實(shí)用,僅是本人的一些看法,如果你有不同看法,歡迎留言討論。為了加深一下 NavigationDrawer 設(shè)計的實(shí)踐,下面來大致的模仿實(shí)現(xiàn)網(wǎng)易云音樂的導(dǎo)航效果。

仿網(wǎng)易云音樂的 NavigationDrawer 實(shí)現(xiàn)

先來看看網(wǎng)易云音樂的效果

云音樂導(dǎo)航菜單

主要就是一個線性布局的菜單并結(jié)合了 Translucent System Bar 的特性(還不知道的童鞋請看我前面寫的文章哈),下面就直接看看大致實(shí)現(xiàn)的布局文件 :

layout/activity_cloud_music.xml


<?xml version="1.0" encoding="utf-8"?>
<android.support.v4.widget.DrawerLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/drawer"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="@color/color_cd3e3a">

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:fitsSystemWindows="true"
        android:orientation="vertical">

        <TextView
            android:layout_width="match_parent"
            android:layout_height="65dp"
            android:background="@color/color_cd3e3a"
            android:gravity="center"
            android:text="網(wǎng)易云音樂"
            android:textColor="@android:color/white"
            android:textSize="18sp" />

        <LinearLayout
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:background="@android:color/white"
            android:orientation="vertical">

        </LinearLayout>
    </LinearLayout>

    <LinearLayout
        android:id="@+id/navigation_view"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:layout_gravity="start"
        android:background="@android:color/white"
        android:fitsSystemWindows="true"
        android:orientation="vertical">

        <ImageView
            android:layout_width="match_parent"
            android:layout_height="180dp"
            android:scaleType="centerCrop"
            android:src="@mipmap/topinfo_ban_bg" />

        <LinearLayout
            android:layout_width="match_parent"
            android:layout_height="50dp"
            android:gravity="center_vertical"
            android:orientation="horizontal">

            <ImageView
                android:layout_width="40dp"
                android:layout_height="40dp"
                android:layout_marginLeft="10dp"
                android:layout_marginRight="10dp"
                android:src="@mipmap/topmenu_icn_msg" />

            <TextView
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:text="我的消息"
                android:textColor="@android:color/black"
                android:textSize="15sp" />
        </LinearLayout>

        ...
        ...
        ...

    </LinearLayout>
</android.support.v4.widget.DrawerLayout>

最終即可實(shí)現(xiàn)類似網(wǎng)易云音樂的效果。

仿造網(wǎng)易云音樂

彩蛋

彩蛋一:左上角的導(dǎo)航動畫效果實(shí)現(xiàn)

左上角的導(dǎo)航動畫

經(jīng)常會看有些 app 的左上角有這些帶感的導(dǎo)航動畫,之前想要引入這種效果,都是來自第三方的開源代碼,諸如下面兩個比較有名的:

  1. LDrawer
  2. android-ui

而現(xiàn)在再也不需要了,Google 推出的 ActionBarDrawerToggle 也能實(shí)現(xiàn)這樣的效果了,具體查看我在 NavigationDrawerAnimationActivity 中的實(shí)現(xiàn)代碼

ActionBarDrawerToggle實(shí)現(xiàn)效果

如果你對上面這種動畫,效果不滿意,也可以考慮一下 material-menu 的另一種實(shí)現(xiàn)效果。

material-menu動畫效果

彩蛋二:比 NavigationView 更好的選擇

前面提到 NavigationView 的不實(shí)用性,如果你真的要實(shí)現(xiàn) NavigationView那樣的效果,又渴望比較高的自由度。這個功能強(qiáng)大且自由度很高的開源庫 MaterialDrawer 應(yīng)該是個很不錯的選擇。

MaterialDrawer 效果圖一
MaterialDrawer 效果圖二

總結(jié)

到此,對于 NavigationDrawer 的實(shí)踐總結(jié)基本結(jié)束。整體給我的感覺是,自從 Material Design 設(shè)計開始推出后,Google 推出的這些新控件使用起來更加簡單,這能讓我們更好的把精力放在編寫業(yè)務(wù)代碼上。很多以前需要借助第三方開源庫才能實(shí)現(xiàn)的效果,現(xiàn)在已經(jīng)慢慢的不需要了。當(dāng)然,我們依舊可以去深入的學(xué)習(xí)這些優(yōu)秀開源代碼,沉淀到更多的干貨。這樣,小菜也就慢慢成為大牛了。

分享即美德,源代碼請看:https://github.com/D-clock/AndroidSystemUiTraining ,本篇的主要實(shí)現(xiàn)代碼如下紅圈所示

主要示例代碼

歡迎關(guān)注我的簡書,以及:

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • Android 自定義View的各種姿勢1 Activity的顯示之ViewRootImpl詳解 Activity...
    passiontim閱讀 179,324評論 25 708
  • afinalAfinal是一個android的ioc,orm框架 https://github.com/yangf...
    passiontim閱讀 15,898評論 2 45
  • 看過很多人關(guān)于最痛苦的一些陳述,其中記憶比較深刻的是趙本山在春晚的一個小品《不差錢》: 小沈陽:人這一生最痛苦的是...
    偉嘉豪閱讀 254評論 0 1
  • 今天部門第一次開了例會 好緊張啊第一次給別人開會 挺怕干事會覺得我們部門 太嚴(yán)肅 或者太單調(diào) 或者太隨便 老實(shí)說 ...
    朱智慧w閱讀 248評論 0 0
  • 有不少人會有這樣的情況:明明自己已經(jīng)很努力地看書,很努力的聽課,可是成長地卻很慢… 這就像是有孔的水桶一樣,倒進(jìn)去...
    松哥生涯閱讀 1,024評論 0 12

友情鏈接更多精彩內(nèi)容