Android Design Support Library系列之二:NavigationView的使用

一、 DrawerLayout

DrawerLayout官網(wǎng)教程
DrawerLayout官網(wǎng)API
在很多應(yīng)用中都會有抽屜式導航欄,鑒于此,谷歌就提供了DrawerLayout來實現(xiàn)這個功能.


DrawerLayout在v4包中,使用時需要導入v4包,使用eclipse創(chuàng)建項目會自動導入v4包,使用studio創(chuàng)建項目時會自動添加v7依賴,v7是兼容v4的,所以直接用就是了......

1、 DrawerLayout的簡單使用

DrawerLayout的使用非常簡單,只要遵循幾個規(guī)則就行了
布局文件:

<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">

    <RelativeLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent">
        <TextView
            android:id="@+id/tv_main"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="主頁面" />
    </RelativeLayout>

    <ListView
        android:id="@+id/list_view"
        android:layout_width="240dp"
        android:layout_height="match_parent"
        android:layout_gravity="start"
        android:background="@android:color/holo_blue_dark"
        android:choiceMode="singleChoice"
        android:divider="@android:color/transparent"
        android:dividerHeight="0dp"
        android:scrollbars="none" />

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

直接使用DrawerLayout作為根標簽,然后DrawerLayout根據(jù)android:layout_gravity屬性判斷哪個是側(cè)滑面板,使用start/end或者left/right來表明是抽屜式導航欄是左邊的還是右邊的,沒有android:layout_gravity屬性的就是主頁面視圖了.

ok,簡單的側(cè)滑效果完成了,就是這么簡單,來看一下效果圖:


是不是很簡單,官網(wǎng)介紹了使用DrawerLayout的幾條規(guī)范:
1、DrawerLayout最好聲明為根標簽
2、在DrawerLayout中,主頁面視圖(上面的 TextView那一部分,當然,這個內(nèi)容是你自己決定的,不一定要是TextView)必須是第一個子視圖
3、主頁面視圖設(shè)置為匹配父視圖的寬度和高度, 因為在抽屜式導航欄處于隱藏狀態(tài)時, 它代表整個 UI
4、抽屜式導航欄視圖 必須使用 android:layout_gravity屬性指定。
如果要支持“從右到左”(RTL) 語言,請使用 "start"(而非"left")指定該值(這樣當布局為 RTL 時,抽屜式導航欄會顯示在右側(cè))。

PS:RTL就是從右到左(Right To Left)的布局,我們在手機上/設(shè)置/開發(fā)者選項中有一個強制使用從右到左的布局方向,可以打開試一試效果.
雖然我們國內(nèi)app一般都是從左到右,但我們還是聽谷歌的建議比較好,使用start/end而非left/right.

5、抽屜式導航欄視圖以 dp 為單位指定其寬度, 且高度與父視圖相匹配。抽屜式導航欄的寬度不應(yīng)超過 320dp,從而用戶始終可以看到部分主內(nèi)容。

2、 抽屜的數(shù)據(jù)填充

抽屜其實只是一個普通的View,這里我放的是ListView,看起來就像菜單,當然,你完全可以只放一個ImageView、TextView等等。這和Activity的菜單不一樣,Activity的菜單只需要在資源文件中定義好,就能按照固定的形式顯示出來。而DrawerLayout的側(cè)邊菜單顯示成什么樣完全是取決于你自己,同樣點擊菜單之后的邏輯也完全由你自己去寫。

接下來給菜單填充數(shù)據(jù)
布局文件

<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">

    <RelativeLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent">
        <TextView
            android:id="@+id/tv_main"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_centerInParent="true"
            android:text="主頁面" />
        <Button
            android:id="@+id/bt_open"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_alignParentRight="true"
            android:text="打開" />

    </RelativeLayout>

    <ListView
        android:id="@+id/list_view"
        android:layout_width="240dp"
        android:layout_height="match_parent"
        android:layout_gravity="start"
        android:background="@android:color/holo_blue_dark"
        android:choiceMode="singleChoice"
        android:divider="@android:color/transparent"
        android:dividerHeight="0dp"
        android:scrollbars="none" />

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

MainActivity.java

public class MainActivity extends AppCompatActivity {

    private List<String> mDatas;
    private DrawerLayout mDrawerLayout;
    private ListView mListView;
    private TextView tvMain;
    private Button btOpen;


    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        initData();
        initView();

        mListView.setAdapter(new ArrayAdapter<>(MainActivity.this,android.R.layout.simple_list_item_1,mDatas));

        /**
         * 點擊菜單條目更改主界面TextView內(nèi)容,同時關(guān)閉菜單
         *      關(guān)閉菜單使用DrawerLayout.closeDrawer()方法,傳入要關(guān)閉的菜單View或者菜單的方向都可以
         */
        mListView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
            @Override
            public void onItemClick(AdapterView<?> adapterView, View view, int position, long id) {
                tvMain.setText(mDatas.get(position));
                mDrawerLayout.closeDrawer(mListView);
//              mDrawerLayout.closeDrawer(GravityCompat.START);
            }
        });

        /**
         *  打開菜單使用DrawerLayout.openDrawer()方法,傳入要關(guān)閉的菜單View或者菜單的方向都可以
         */
        btOpen.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                mDrawerLayout.openDrawer(GravityCompat.START);
//              mDrawerLayout.openDrawer(mListView);
            }
        });
    }

    private void initView() {
        mDrawerLayout = (DrawerLayout) findViewById(R.id.drawer_layout);
        mListView = (ListView) findViewById(R.id.list_view);
        tvMain = (TextView) findViewById(R.id.tv_main);
        btOpen = (Button) findViewById(R.id.bt_open);
    }

    private void initData() {
        mDatas = new ArrayList<>();
        for (int i = 'A'; i < 'Z'; i++) {
            mDatas.add("" + (char) i);
        }
    }
}

效果圖


實際開發(fā)中這里的主頁面視圖一般用FrameLayout代替,點擊菜單條目,動態(tài)為FrameLayout添加內(nèi)容.
ok,簡單的介紹了DrawerLayout的使用,接下來來看一下我們今天的主角

二、NavigationView

NavigationView官網(wǎng)教程

1、NavigationView是什么

NavigationView就是菜單View,也就是上面我們使用的ListView那一部分。
那么,有了DrawerLayout之后為什么還會出現(xiàn)一個NavigationView,看下面這張圖:



這種效果的菜單用ListView或者RecyclerView也能實現(xiàn),不過總要花點時間吧,但是用NavigationView之后簡直分分鐘搞定.

2、NavigationView的使用

(1)簡單使用

<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_layout"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <RelativeLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent">
        <TextView
            android:id="@+id/tv_main"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_centerInParent="true"
            android:text="主頁面" />
    </RelativeLayout>

    
    <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/header"
        app:menu="@menu/main">
    </android.support.design.widget.NavigationView>


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

NavigationView就是菜單面板,其中最重要的兩條屬性就是:

1、這就是菜單面板的頭布局,也就是剛才頭像,昵稱那一欄,引用了一個布局文件
 app:headerLayout="@layout/header"

header.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="150dp"
    android:background="@color/colorPrimaryDark"
    android:gravity="center"
    android:orientation="vertical">

    <ImageView
        android:layout_width="144dp"
        android:layout_height="90dp"
        android:layout_marginTop="10dp"
        android:background="@mipmap/icon" />

    <TextView
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_marginTop="10dp"
        android:gravity="center"
        android:text="隨風飄揚的smile"
        android:textColor="@android:color/white"
        android:textSize="15sp" />
</LinearLayout>
2、這就是菜單面板的內(nèi)容部分,也就是會員特權(quán)、XX錢包...那一部分,定義在res/menu/main.xml中
app:menu="@menu/main"

main.xml

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

        <item
            android:id="@+id/item_1"
            android:icon="@mipmap/a"
            android:title="會員特權(quán)" />

        <item
            android:id="@+id/item_2"
            android:icon="@mipmap/b"
            android:title="XX錢包" />

        <item
            android:id="@+id/item_3"
            android:icon="@mipmap/c"
            android:title="個性裝扮" />
        <item
            android:id="@+id/item_4"
            android:icon="@mipmap/d"
            android:title="我的收藏" />
        <item
            android:id="@+id/item_5"
            android:icon="@mipmap/e"
            android:title="我的相冊" />

        <item
            android:id="@+id/item_6"
            android:icon="@mipmap/f"
            android:title="設(shè)置" />
</menu>

header和item部分內(nèi)容都是根據(jù)實際需要來設(shè)置的.
(2)效果圖:


效果有點不一樣,沒有了分隔線,而且圖片都是灰灰的。

(3)添加分隔線:

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

        <group android:id="@+id/group1">
                <item
                    android:id="@+id/item_1"
                    android:icon="@mipmap/a"
                    android:title="會員特權(quán)" />
        </group>

        <group android:id="@+id/group2">
                <item
                    android:id="@+id/item_2"
                    android:icon="@mipmap/b"
                    android:title="XX錢包" />
        </group>

        <group android:id="@+id/group3">
                <item
                    android:id="@+id/item_3"
                    android:icon="@mipmap/c"
                    android:title="個性裝扮" />
        </group>
        <group android:id="@+id/group4">
                <item
                    android:id="@+id/item_4"
                    android:icon="@mipmap/d"
                    android:title="我的收藏" />
        </group>
        <group android:id="@+id/group5">
                <item
                    android:id="@+id/item_5"
                    android:icon="@mipmap/e"
                    android:title="我的相冊" />
        </group>

        <group android:id="@+id/group6">
                <item
                    android:id="@+id/item_6"
                    android:icon="@mipmap/f"
                    android:title="設(shè)置" />
        </group>
</menu>

在菜單條目文件中給item分組,就可以添加分隔線了。
再來看效果圖:


ok!
(4)解決圖片變灰問題:
方式1:你可以為NavigationView設(shè)置下面這條屬性,不過那樣item圖片只能是統(tǒng)一的顏色

app:itemIconTint=""

方式2:Activity中代碼設(shè)置,這樣能讓圖片恢復(fù)原樣了

mNavigationView = (NavigationView) findViewById(R.id.navigation_view);
mNavigationView.setItemIconTintList(null);

ok,現(xiàn)在效果圖和剛開始那張圖完全一樣了。

(5)item繼續(xù)添加分組:

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

        <group android:id="@+id/group1">
                <item
                    android:id="@+id/item_1"
                    android:icon="@mipmap/a"
                    android:title="會員特權(quán)" />
        </group>

        <group android:id="@+id/group2">
                <item
                    android:id="@+id/item_2"
                    android:icon="@mipmap/b"
                    android:title="XX錢包" />
        </group>

        <group android:id="@+id/group3">
                <item
                    android:id="@+id/item_3"
                    android:icon="@mipmap/c"
                    android:title="個性裝扮" />
        </group>
        <group android:id="@+id/group4">
                <item
                    android:id="@+id/item_4"
                    android:icon="@mipmap/d"
                    android:title="我的收藏" />
        </group>
        <group android:id="@+id/group5">
                <item
                    android:id="@+id/item_5"
                    android:icon="@mipmap/e"
                    android:title="我的相冊" />
        </group>

        <group android:id="@+id/group6">
                <item
                    android:id="@+id/item_6"
                    android:icon="@mipmap/f"
                    android:title="設(shè)置" />
        </group>

        <group android:id="@+id/group7">
                <item
                    android:id="@+id/item_7"
                    android:icon="@mipmap/f"
                    android:title="其它" >
                        <menu>
                                <item
                                    android:id="@+id/item_8"
                                    android:icon="@mipmap/f"
                                    android:title="分享" />
                                <item
                                    android:id="@+id/item_9"
                                    android:icon="@mipmap/f"
                                    android:title="隱私" />

                        </menu>

                </item>
        </group>
</menu>

效果圖:



當item過多會出現(xiàn)滾動條,如果要隱藏滾動條,給NavigationView設(shè)置android:scrollbars="none"是不管用的,因為這個滾動條不是NavigationView的,而是菜單的·.
可以在Activity中找到菜單View,然后取消滾動條

NavigationMenuView menuView  = (NavigationMenuView) mNavigationView.getChildAt(0);
menuView.setVerticalScrollBarEnabled(false);
3、NavigationView其它屬性
給菜單item部分添加背景
 app:itemBackground=" "
給菜單item文字設(shè)置顏色
app:itemTextColor=" "

更多文字特效可以通過下面這條屬性設(shè)置:
app:itemTextAppearance=" "
4、菜單item的一些屬性
設(shè)定一組菜單項可以選中幾個item,none、single、all三個值
  <group android:id="@+id/group1" android:checkableBehavior="single"> 
菜單項 item 是否被選中,如果要默認選中一個菜單 item 則設(shè)為true
<item   android:checked="true" />
5、NavigationView點擊事件

(1)頭部點擊事件

        headerView = mNavigationView.getHeaderView(0);

        headerView.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                Toast.makeText(MainActivity.this,"headerView",Toast.LENGTH_SHORT).show();
            }
        });

找到headerView ,然后設(shè)置點擊事件即可
(2)頭部控件點擊事件
通過headerView.findViewById()找到要點擊的控件,然后設(shè)置點擊事件即可

        ivIcon = (ImageView) headerView.findViewById(R.id.icon);
        tvName = (TextView) headerView.findViewById(R.id.name);

        ivIcon.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                Toast.makeText(MainActivity.this,"icon",Toast.LENGTH_SHORT).show();
            }
        });

        tvName.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                Toast.makeText(MainActivity.this,"name",Toast.LENGTH_SHORT).show();
            }
        });

(3)item點擊事件

通過NavigationView.setNavigationItemSelectedListener()設(shè)置監(jiān)聽即可
        mNavigationView.setNavigationItemSelectedListener(new NavigationView.OnNavigationItemSelectedListener() {
            @Override
            public boolean onNavigationItemSelected(@NonNull MenuItem item) {
                switch (item.getItemId()){
                    case R.id.item_1:
                        //do something
                        break;
                    case R.id.item_2:
                        //do something
                        break;
                   //......
                }
                return false;
            }
        });

(4)隱藏菜單某部分item
有時候可能會有些奇葩的需求,要求我們隱藏一些菜單item,滿足一定條件才會顯示出來.

MenuItem item = mNavigationView.getMenu().findItem(R.id.item_1);//找到要隱藏的item
item.setVisible(false);//false即隱藏,true即顯示

三、 完整代碼

Activity布局文件:

<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_layout"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <RelativeLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent">
        <TextView
            android:id="@+id/tv_main"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_centerInParent="true"
            android:text="主頁面" />
    </RelativeLayout>

    
    <android.support.design.widget.NavigationView
        android:id="@+id/navigation_view"
        android:layout_width="wrap_content"
        android:layout_height="match_parent"
        android:layout_gravity="left"
        app:itemTextColor="@color/colorPrimaryDark"
        app:headerLayout="@layout/header"
        app:menu="@menu/main">

    </android.support.design.widget.NavigationView>

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

header布局文件:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="150dp"
    android:background="@color/colorPrimaryDark"
    android:gravity="center"
    android:orientation="vertical">

    <ImageView
        android:id="@+id/icon"
        android:layout_width="144dp"
        android:layout_height="90dp"
        android:layout_marginTop="10dp"
        android:background="@mipmap/icon" />

    <TextView
        android:id="@+id/name"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_marginTop="10dp"
        android:gravity="center"
        android:text="隨風飄揚的smile"
        android:textColor="@android:color/white"
        android:textSize="15sp" />
</LinearLayout>

菜單文件

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

    <group android:id="@+id/group1">
        <item
            android:id="@+id/item_1"
            android:icon="@mipmap/a"
            android:title="會員特權(quán)" />
    </group>

    <group android:id="@+id/group2">
        <item
            android:id="@+id/item_2"
            android:icon="@mipmap/b"
            android:title="XX錢包" />
    </group>

    <group android:id="@+id/group3">
        <item
            android:id="@+id/item_3"
            android:icon="@mipmap/c"
            android:title="個性裝扮" />
    </group>
    <group android:id="@+id/group4">
        <item
            android:id="@+id/item_4"
            android:icon="@mipmap/d"
            android:title="我的收藏" />
    </group>
    <group android:id="@+id/group5">
        <item
            android:id="@+id/item_5"
            android:icon="@mipmap/e"
            android:title="我的相冊" />
    </group>

    <group android:id="@+id/group6">
        <item
            android:id="@+id/item_6"
            android:icon="@mipmap/f"
            android:title="設(shè)置" />
    </group>

    <group android:id="@+id/group7">
        <item
            android:id="@+id/item_7"
            android:icon="@mipmap/f"
            android:title="其它">
            <menu>
                <item
                    android:id="@+id/item_8"
                    android:icon="@mipmap/f"
                    android:title="分享" />
                <item
                    android:id="@+id/item_9"
                    android:icon="@mipmap/f"
                    android:title="隱私" />
            </menu>
        </item>
    </group>
</menu>

MainActivity.java

public class MainActivity extends AppCompatActivity {

    private DrawerLayout mDrawerLayout;
    private TextView tvMain;
    private NavigationView mNavigationView;
    private View headerView;
    private ImageView ivIcon;
    private TextView tvName;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        mDrawerLayout = (DrawerLayout) findViewById(R.id.drawer_layout);
        tvMain = (TextView) findViewById(R.id.tv_main);
        mNavigationView = (NavigationView) findViewById(R.id.navigation_view);

        mNavigationView.setItemIconTintList(null);//讓菜單item圖片正常


//          隱藏菜單item
//        MenuItem item = mNavigationView.getMenu().findItem(R.id.item_1);
//        item.setVisible(false);

        /**
         * 隱藏滾動條
         */
        NavigationMenuView menuView  = (NavigationMenuView) mNavigationView.getChildAt(0);
        menuView.setVerticalScrollBarEnabled(false);


        /**
         * header點擊事件
         */
        headerView = mNavigationView.getHeaderView(0);
        headerView.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                Toast.makeText(MainActivity.this,"headerView",Toast.LENGTH_SHORT).show();
            }
        });

        /**
         * headerView中組件點擊事件
         */
        ivIcon = (ImageView) headerView.findViewById(R.id.icon);
        tvName = (TextView) headerView.findViewById(R.id.name);

        ivIcon.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                Toast.makeText(MainActivity.this,"icon",Toast.LENGTH_SHORT).show();
            }
        });

        tvName.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                Toast.makeText(MainActivity.this,"name",Toast.LENGTH_SHORT).show();
            }
        });


        /**
         * 菜單item點擊事件
         */
        mNavigationView.setNavigationItemSelectedListener(new NavigationView.OnNavigationItemSelectedListener() {
            @Override
            public boolean onNavigationItemSelected(@NonNull MenuItem item) {
                switch (item.getItemId()) {
                    case R.id.item_1:
                        //do something
                        break;
                    case R.id.item_2:
                        //do something
                        break;
                    //......
                }
                return false;
            }
        });
    }
}

效果圖

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

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

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