那些底部導(dǎo)航(頂部導(dǎo)航)和側(cè)滑菜單放在一起的坑

1、前言

在日常開發(fā)中昆汹,單個(gè)需求可能不難實(shí)現(xiàn),多個(gè)合在一起可能就會(huì)產(chǎn)生各種問題婴栽,比如最近我在實(shí)現(xiàn)頂部導(dǎo)航加上底部導(dǎo)航再加上側(cè)滑菜單满粗,這三種布局相結(jié)合時(shí),就會(huì)產(chǎn)生布局相互覆蓋愚争,或者獲取不到焦點(diǎn)種種問題映皆。在研究后得到一種比較兼容三種需求的實(shí)現(xiàn)方法,頂部導(dǎo)航欄可以參考上篇文章轰枝,底部導(dǎo)航采用TabLayout結(jié)合Fragment捅彻,側(cè)滑菜單采用官方實(shí)現(xiàn)方式DrawerLayout+NavigationView,就此做個(gè)分享鞍陨。

2沟饥、效果圖

底部導(dǎo)航.gif

由圖中看到,已經(jīng)是一個(gè)比較常見的布局了湾戳,包括了上下導(dǎo)航欄和側(cè)滑菜單贤旷。

3、底部導(dǎo)航

一般分為 3 —— 5 個(gè)Tab砾脑,比如微信幼驶,展示了有四個(gè)Tab,分別對(duì)應(yīng)不同的板塊(微信韧衣、通訊錄盅藻、發(fā)現(xiàn)购桑、我),現(xiàn)在市面出了少部分的Material Design 風(fēng)格的除外氏淑,大部分都是這樣的一個(gè)框架勃蜘。頁面做Tab切換首先最容易想到的還是TabLayout,切換Fragment對(duì)頁面顯示更加靈活一點(diǎn)假残。

頁面布局

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

        <FrameLayout
            android:id="@+id/fragment_content"
            android:layout_width="match_parent"
            android:layout_height="0dp"
            android:layout_weight="1">
        </FrameLayout>

        <android.support.design.widget.TabLayout
            android:id="@+id/bottom_tab_layout"
            android:layout_width="match_parent"
            android:layout_height="50dp"
            app:tabIndicatorHeight="0dp"
            app:tabSelectedTextColor="@color/bottom_tab_text_color">
        </android.support.design.widget.TabLayout>

    </LinearLayout>

TabLayout默認(rèn)是帶有Indicator的缭贡,也就是指示條,做底部導(dǎo)航時(shí)是不需要的辉懒,在布局中設(shè)置tabIndicatorHeight="0dp“即可阳惹。

代碼

private void initView() {
        //按鈕圖標(biāo)資源
        iconList = Arrays.asList(bottomTabIcon);
        iconPressList = Arrays.asList(bottomIconPress);
        //由Tab控制切換的Fragment
        fragmentList = new ArrayList<>();
        fragmentList.add(new HomeFragment());
        fragmentList.add(new FavoriteFragment());
        fragmentList.add(new FriendsFragment());
        fragmentList.add(new PersonFragment());

        bottmeTab.addOnTabSelectedListener(new TabLayout.OnTabSelectedListener() {
            @Override
            public void onTabSelected(TabLayout.Tab tab) {
                if(pos_tab != null) {
                    //將上一次被選中的Tab置為未選中狀態(tài)
                    bottmeTab.getTabAt(pos_tab).setIcon(iconList.get(pos_tab));
                }
                fragment = fragmentList.get(tab.getPosition());
                ft = getSupportFragmentManager().beginTransaction();
                ft.replace(R.id.fragment_content,fragment).commit();
                pos_tab = tab.getPosition();
                bottmeTab.getTabAt(pos_tab).setIcon(iconPressList.get(pos_tab));
            }

            @Override
            public void onTabUnselected(TabLayout.Tab tab) {

            }

            @Override
            public void onTabReselected(TabLayout.Tab tab) {

            }
        });

        bottmeTab.addTab(bottmeTab.newTab().setIcon(R.mipmap.home).setText("首頁"));
        bottmeTab.addTab(bottmeTab.newTab().setIcon(R.mipmap.favorite).setText("關(guān)注"));
        bottmeTab.addTab(bottmeTab.newTab().setIcon(R.mipmap.friends).setText("好友"));
        bottmeTab.addTab(bottmeTab.newTab().setIcon(R.mipmap.account).setText("我"));
    }

添加Tab之前先添加監(jiān)聽器,避免設(shè)置失效眶俩,第一次載入頁面時(shí)莹汤,第一個(gè)Tab是選中狀態(tài),所以可以在第一個(gè)Tab做初始化操作颠印,如果后加監(jiān)聽器第一次onTabSelected就不會(huì)選中纲岭。由于圖標(biāo)與字之間的距離不能改變,如果想要改變可以對(duì)Tab按鈕做自定義线罕,調(diào)用newTab().setCustomView(View view)傳入自定義View止潮。

需要注意的是,采用replace的方法切換Fragment闻坚,會(huì)使前一個(gè)Fragment被已銷毀一次沽翔,生命周期一直走到Detach,其中有一些成員變量需要自己保存窿凤,在重新切換回來時(shí)還原仅偎,由于Fragment實(shí)例沒被銷毀,View的狀態(tài)還被保存著雳殊,如果初始化中有繪制View的操作橘沥,會(huì)導(dǎo)致View被繪制倆次,需要在初始化中設(shè)置避免

4夯秃、側(cè)滑菜單

首先看一下基礎(chǔ)的布局

<android.support.v4.widget.DrawerLayout
    android:id="@+id/drawer_layout"
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:fitsSystemWindows="true"
    tools:openDrawer="start">

    <FrameLayout
        android:id="@+id/fragment_content"
        android:layout_width="match_parent"
        android:layout_height="0dp"
        android:layout_weight="1">
    </FrameLayout>

    <android.support.design.widget.NavigationView
        android:id="@+id/nav_view"
        android:layout_width="wrap_content"
        android:layout_height="match_parent"
        android:layout_gravity="start"
        android:fitsSystemWindows="true"
        app:headerLayout="@layout/nav_header_drawer_layout__one"
        app:menu="@menu/activity_drawer_layout__one_drawer"/>

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

這里把TabLayout直接加在Fragment布局下面探赫,會(huì)導(dǎo)致頁面被底部導(dǎo)航欄充滿课梳,可能是DrawerLagout本身這樣設(shè)計(jì)铅歼,所以要做改動(dòng)险绘,將我們需要切換的Fragment與TabLayout包裝在一起。

<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"
    android:orientation="vertical">

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

        <FrameLayout
            android:id="@+id/fragment_content"
            android:layout_width="match_parent"
            android:layout_height="0dp"
            android:layout_weight="1">
        </FrameLayout>

        <android.support.design.widget.TabLayout
            android:id="@+id/bottom_tab_layout"
            android:layout_width="match_parent"
            android:layout_height="50dp"
            app:tabIndicatorHeight="0dp"
            app:tabSelectedTextColor="@color/bottom_tab_text_color">
        </android.support.design.widget.TabLayout>

    </LinearLayout>

    <android.support.design.widget.NavigationView
        android:id="@+id/nav_left"
        android:layout_width="300dp"
        android:layout_height="match_parent"
        android:layout_gravity="start"
        app:headerLayout="@layout/header_nav_left"
        app:menu="@menu/menu_nav_left"
        app:insetForeground="@android:color/transparent">

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

在Fragment和TabLayout外面包裹一層布局色建,當(dāng)然也可以獨(dú)立出去哺呜,include進(jìn)來,這里放在一起更加直觀箕戳。側(cè)滑菜單包括一個(gè)頭布局header和一個(gè)菜單menu

header.xml

<RelativeLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="130dp"
    android:background="@color/colorPrimary"
    android:orientation="vertical">

    <ImageView
        android:id="@+id/icon_person"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginTop="30dp"
        android:layout_marginLeft="10dp"
        android:src="@mipmap/icon_person"/>

    <TextView
        android:id="@+id/text_person"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_below="@+id/icon_person"
        android:layout_marginTop="10dp"
        android:layout_marginLeft="20dp"
        android:text="用戶名"/>

</RelativeLayout>

menu.xml

<menu xmlns:android="http://schemas.android.com/apk/res/android">
    <group
        android:id="@+id/group_content"
        android:checkableBehavior="single"
        >
        <item
            android:id="@+id/menu_home"
            android:icon="@mipmap/home"
            android:title="home" />
        <item
            android:id="@+id/menu_favorite"
            android:icon="@mipmap/favorite"
            android:title="favorite"/>
    </group>

    <group
        android:id="@+id/group_person"
        android:checkableBehavior="single">
        <item
            android:id="@+id/menu_account"
            android:icon="@mipmap/account"
            android:title="account"/>
        <item
            android:id="@+id/menu_messages"
            android:icon="@mipmap/comments"
            android:title="messages"/>
        <item
            android:id="@+id/menu_down"
            android:icon="@mipmap/down"
            android:title="down"/>
    </group>
</menu>

<item>就是定義一個(gè)菜單項(xiàng)某残。
<group>是對(duì)菜單進(jìn)行分組国撵,如果需要分割線,添加id后玻墅,這一組菜單的頂部就會(huì)顯示一個(gè)分割線介牙,如上圖效果圖中的那條橫線。

結(jié)合后代碼

    private void initView() {
        iconList = Arrays.asList(bottomTabIcon);
        iconPressList = Arrays.asList(bottomIconPress);
        fragmentList = new ArrayList<>();
        fragmentList.add(new HomeFragment());
        fragmentList.add(new FavoriteFragment());
        fragmentList.add(new FriendsFragment());
        fragmentList.add(new PersonFragment());

        bottmeTab.addOnTabSelectedListener(new TabLayout.OnTabSelectedListener() {
            @Override
            public void onTabSelected(TabLayout.Tab tab) {
                if(pos_tab != null) {
                    bottmeTab.getTabAt(pos_tab).setIcon(iconList.get(pos_tab));
                }
                fragment = fragmentList.get(tab.getPosition());
                ft = getSupportFragmentManager().beginTransaction();
                ft.replace(R.id.fragment_content,fragment).commit();
                pos_tab = tab.getPosition();
                bottmeTab.getTabAt(pos_tab).setIcon(iconPressList.get(pos_tab));
            }

            @Override
            public void onTabUnselected(TabLayout.Tab tab) {

            }

            @Override
            public void onTabReselected(TabLayout.Tab tab) {

            }
        });

        bottmeTab.addTab(bottmeTab.newTab().setIcon(R.mipmap.home).setText("首頁"));
        bottmeTab.addTab(bottmeTab.newTab().setIcon(R.mipmap.favorite).setText("關(guān)注"));
        bottmeTab.addTab(bottmeTab.newTab().setIcon(R.mipmap.friends).setText("好友"));
        bottmeTab.addTab(bottmeTab.newTab().setIcon(R.mipmap.account).setText("我"));

        //側(cè)滑菜單部分
        navigationView.setItemIconTintList(null);
        navigationView.setNavigationItemSelectedListener(new NavigationView.OnNavigationItemSelectedListener() {
            @Override
            public boolean onNavigationItemSelected(@NonNull MenuItem item) {
                //關(guān)閉左邊導(dǎo)航
                int id = item.getItemId();
                drawerLayout.closeDrawer(GravityCompat.START);
                return true;
            }
        });
    }

菜單中如果使用矢量圖標(biāo)澳厢,需先setItemIconTintList(null)环础,否則會(huì)采用自身機(jī)制,矢量圖不能完全顯示赏酥,并且點(diǎn)擊后矢量圖標(biāo)顏色改為應(yīng)用內(nèi)部主要顏色喳整。

通過setNavigationItemSelectedListener設(shè)置監(jiān)聽處理菜單每個(gè)選項(xiàng)點(diǎn)擊事件谆构,用closeDrawer(GravityCompat.START)關(guān)閉側(cè)滑菜單裸扶。

未設(shè)置.png

源碼地址 個(gè)人項(xiàng)目加入了一些其他東西,主要看MainActivity

總結(jié)了一下三種效果結(jié)合在一起實(shí)現(xiàn)的過程搬素,雖然都是容易的實(shí)現(xiàn)呵晨,在這里分享出來希望看過的人能少走彎路。水平有限熬尺,如果有不正確或者不足的地方歡迎指出摸屠,共同分享一起進(jìn)步。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末粱哼,一起剝皮案震驚了整個(gè)濱河市季二,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌揭措,老刑警劉巖胯舷,帶你破解...
    沈念sama閱讀 206,602評(píng)論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異绊含,居然都是意外死亡桑嘶,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,442評(píng)論 2 382
  • 文/潘曉璐 我一進(jìn)店門躬充,熙熙樓的掌柜王于貴愁眉苦臉地迎上來逃顶,“玉大人,你說我怎么就攤上這事充甚∫哉” “怎么了?”我有些...
    開封第一講書人閱讀 152,878評(píng)論 0 344
  • 文/不壞的土叔 我叫張陵伴找,是天一觀的道長盈蛮。 經(jīng)常有香客問我,道長疆瑰,這世上最難降的妖魔是什么眉反? 我笑而不...
    開封第一講書人閱讀 55,306評(píng)論 1 279
  • 正文 為了忘掉前任昙啄,我火速辦了婚禮,結(jié)果婚禮上寸五,老公的妹妹穿的比我還像新娘梳凛。我一直安慰自己,他們只是感情好梳杏,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,330評(píng)論 5 373
  • 文/花漫 我一把揭開白布韧拒。 她就那樣靜靜地躺著,像睡著了一般十性。 火紅的嫁衣襯著肌膚如雪叛溢。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,071評(píng)論 1 285
  • 那天劲适,我揣著相機(jī)與錄音楷掉,去河邊找鬼。 笑死霞势,一個(gè)胖子當(dāng)著我的面吹牛烹植,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播愕贡,決...
    沈念sama閱讀 38,382評(píng)論 3 400
  • 文/蒼蘭香墨 我猛地睜開眼草雕,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了固以?” 一聲冷哼從身側(cè)響起墩虹,我...
    開封第一講書人閱讀 37,006評(píng)論 0 259
  • 序言:老撾萬榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎憨琳,沒想到半個(gè)月后诫钓,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 43,512評(píng)論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡栽渴,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 35,965評(píng)論 2 325
  • 正文 我和宋清朗相戀三年尖坤,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片闲擦。...
    茶點(diǎn)故事閱讀 38,094評(píng)論 1 333
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡慢味,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出墅冷,到底是詐尸還是另有隱情纯路,我是刑警寧澤,帶...
    沈念sama閱讀 33,732評(píng)論 4 323
  • 正文 年R本政府宣布寞忿,位于F島的核電站驰唬,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜叫编,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,283評(píng)論 3 307
  • 文/蒙蒙 一辖佣、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧搓逾,春花似錦卷谈、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,286評(píng)論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至朗兵,卻和暖如春污淋,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背余掖。 一陣腳步聲響...
    開封第一講書人閱讀 31,512評(píng)論 1 262
  • 我被黑心中介騙來泰國打工寸爆, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人浊吏。 一個(gè)月前我還...
    沈念sama閱讀 45,536評(píng)論 2 354
  • 正文 我出身青樓而昨,卻偏偏與公主長得像救氯,于是被迫代替她去往敵國和親找田。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,828評(píng)論 2 345

推薦閱讀更多精彩內(nèi)容