底部導(dǎo)航欄

問(wèn)題

如何實(shí)現(xiàn)常見(jiàn)應(yīng)用中的底部導(dǎo)航欄的功能惑折?


底部導(dǎo)航欄.png

回答

可以借助 BottomNavigationView 來(lái)實(shí)現(xiàn)這一效果。

效果

效果.gif

簡(jiǎn)介

BottomNavigationView 是應(yīng)用程序的標(biāo)準(zhǔn)底部導(dǎo)航欄归露,是 Material Design 3 導(dǎo)航規(guī)范萨赁、Material Design 2 底部導(dǎo)航規(guī)范 的實(shí)現(xiàn)苟耻。

應(yīng)用于頂級(jí)頁(yè)面的導(dǎo)航吱瘩,適用于 3 - 5 個(gè)菜單項(xiàng)的場(chǎng)景荷逞。

本文的說(shuō)明不涉及角標(biāo) ( 圖標(biāo)右上角顯示的數(shù)字 )媒咳。如有需要,BottomNavigation 可能會(huì)有所幫助种远。

步驟

  1. 添加 BottomNavigationView 所在庫(kù)的依賴(lài)涩澡。
dependencies {
...
implementation 'com.google.android.material:material:1.4.0'
...
}

如果 build 失敗,可能和項(xiàng)目與 material 庫(kù)的版本不匹配有關(guān)坠敷。

1.5.0 版本對(duì)應(yīng) Material Design 3, 要求 compileSdkVersiontargetSdkVersion 不低于 31 妙同。其他版本的項(xiàng)目要求可以查閱 material-components-android/releases

  1. 在 Activity 的 layout 文件中使用 BottomNavigationView 控件膝迎。
<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto">

    <data>

    </data>

    <androidx.constraintlayout.widget.ConstraintLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent">

        <com.google.android.material.bottomnavigation.BottomNavigationView
            android:id="@+id/main_navigation_bar"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:background="@android:color/white"
            app:layout_constraintBottom_toBottomOf="parent"
            app:menu="@menu/navigation_view_menu_items" />

    </androidx.constraintlayout.widget.ConstraintLayout>
</layout>
  1. 第二步中粥帚,BottomNavigationViewapp:menu 屬性需要引用一個(gè)菜單資源,該菜單資源用于定義導(dǎo)航欄中菜單項(xiàng)的數(shù)量和樣式限次。創(chuàng)建 res/menu 目錄芒涡,在目錄下創(chuàng)建菜單文件。
<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android">

    <item
        android:id="@+id/navigation_menu_item_home"
        android:icon="@drawable/navigation_home"
        android:title="主頁(yè)" />

    <item
        android:id="@+id/navigation_menu_item_contact"
        android:icon="@drawable/navigation_contact"
        android:title="聯(lián)系人" />

    <item
        android:id="@+id/navigation_menu_item_mine"
        android:icon="@drawable/navigation_mine"
        android:title="我的" />

</menu>

上面的菜單文件中卖漫,定義了 3 個(gè)菜單項(xiàng)费尽,每個(gè)菜單項(xiàng)包含 id, icon(圖標(biāo)) 和title (標(biāo)題) 三個(gè)屬性。

  1. 第三步中的 icon 屬性需要引用 drawable 資源懊亡,以“主頁(yè)”為例進(jìn)行說(shuō)明依啰。創(chuàng)建 drawable 文件, 為選中和非選中狀態(tài)添加對(duì)應(yīng)的圖標(biāo)。
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
    <item android:drawable="@drawable/navigation_home_selected" android:state_selected="true" />
    <item android:drawable="@drawable/navigation_home_default" android:state_selected="false" />
</selector>

itemdrawable屬性引用 png 之類(lèi)的圖片即可店枣。

navigation_home_default.png
navigation_home_selected.png

至此速警,底部導(dǎo)航欄的樣式就實(shí)現(xiàn)了叹誉。

  1. 創(chuàng)建“主頁(yè)”、“聯(lián)系人”和“我的” Fragment 和 layout 文件闷旧。當(dāng)某個(gè)菜單項(xiàng)選中時(shí)长豁,切換到對(duì)應(yīng)的 Fragment。

  2. 在 Activity 的 layout 文件中使用 ViewPager2 控件忙灼。作為 3 個(gè) Fragment 的容器匠襟,并控制它們的切換。

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

    <data>

    </data>

    <androidx.constraintlayout.widget.ConstraintLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent">

        <androidx.viewpager2.widget.ViewPager2
            android:id="@+id/main_fragment_container"
            android:layout_width="match_parent"
            android:layout_height="0dp"
            app:layout_constraintBottom_toTopOf="@id/main_navigation_bar"
            app:layout_constraintTop_toTopOf="parent"
            app:layout_constraintVertical_weight="1" />

        <com.google.android.material.bottomnavigation.BottomNavigationView
            android:id="@+id/main_navigation_bar"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:background="@android:color/white"
            app:layout_constraintBottom_toBottomOf="parent"
            app:menu="@menu/navigation_view_menu_items" />

    </androidx.constraintlayout.widget.ConstraintLayout>
</layout>

創(chuàng)建 ViewPager2 的 Fragment 適配器该园。

public class FragmentAdapter extends FragmentStateAdapter {

  private final ArrayList<Fragment> fragments;

  public FragmentAdapter(@NonNull FragmentActivity fragmentActivity) {
    super(fragmentActivity);
    fragments = new ArrayList<>();
    fragments.add(new HomeFragment());
    fragments.add(new ContactFragment());
    fragments.add(new MineFragment());
  }

  @NonNull
  @Override
  public Fragment createFragment(int position) {
    return fragments.get(position);
  }

  @Override
  public int getItemCount() {
    return fragments.size();
  }

}

在 Activity 中為 ViewPager2 設(shè)置適配器酸舍。

public class BottomNavigationBarActivity extends AppCompatActivity {

  private NavigationActivityBottomNavigationBarBinding binding;

  @Override
  protected void onCreate(@Nullable Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    int layoutId = R.layout.navigation_activity_bottom_navigation_bar;
    binding = DataBindingUtil.setContentView(this, layoutId);
    // 為 ViewPager2 設(shè)置適配器
    binding.mainFragmentContainer.setAdapter(new FragmentAdapter(this));
  }

}
  1. 在 Activity 中為 BottomNavigationView 控件添加菜單項(xiàng)選中事件監(jiān)聽(tīng)器,當(dāng)某一項(xiàng)選中后里初,ViewPager2 切換為對(duì)應(yīng)的 Fragment啃勉。
private void setNavigationItemSelectedListener() {
    binding.mainNavigationBar.setOnItemSelectedListener(new NavigationBarView.OnItemSelectedListener() {
      @Override
      public boolean onNavigationItemSelected(@NonNull MenuItem item) {
        String itemTitle = (String) item.getTitle();
        switch (itemTitle) {
          case "主頁(yè)": {
            binding.mainFragmentContainer.setCurrentItem(0);
          }
          break;
          case "聯(lián)系人": {
            binding.mainFragmentContainer.setCurrentItem(1);
          }
          break;
          case "我的": {
            binding.mainFragmentContainer.setCurrentItem(2);
          }
          break;
        }
        return true;
      }
    });
  }

禁用 ViewPager2 控件的滑動(dòng)切換頁(yè)面功能,僅支持點(diǎn)擊底部導(dǎo)航欄的菜單項(xiàng)切換頁(yè)面双妨。( 監(jiān)聽(tīng) ViewPager2 的頁(yè)面切換淮阐,設(shè)置 BottomNavigationView 的選中項(xiàng)亦可。類(lèi)似于微信的效果刁品,支持點(diǎn)擊和滑動(dòng)兩種切換方式 )

@Override
  protected void onCreate(@Nullable Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    int layoutId = R.layout.navigation_activity_bottom_navigation_bar;
    binding = DataBindingUtil.setContentView(this, layoutId);
    binding.mainFragmentContainer.setAdapter(new FragmentAdapter(this));

   // 禁用滑動(dòng)切換頁(yè)面功能
    binding.mainFragmentContainer.setUserInputEnabled(false);

    setNavigationItemSelectedListener();
  }

參考資料

  1. 斌林誠(chéng)上 : Android 底部導(dǎo)航欄 BottomNavigationView
  2. BottomNavigationView
  3. material design : bottom-navigation

代碼

XuMeng-0/android-study

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末泣特,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子挑随,更是在濱河造成了極大的恐慌状您,老刑警劉巖,帶你破解...
    沈念sama閱讀 219,110評(píng)論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件镀裤,死亡現(xiàn)場(chǎng)離奇詭異竞阐,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī)暑劝,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,443評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門(mén),熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)颗搂,“玉大人担猛,你說(shuō)我怎么就攤上這事《猓” “怎么了傅联?”我有些...
    開(kāi)封第一講書(shū)人閱讀 165,474評(píng)論 0 356
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)疚察。 經(jīng)常有香客問(wèn)我蒸走,道長(zhǎng),這世上最難降的妖魔是什么貌嫡? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 58,881評(píng)論 1 295
  • 正文 為了忘掉前任比驻,我火速辦了婚禮该溯,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘别惦。我一直安慰自己狈茉,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,902評(píng)論 6 392
  • 文/花漫 我一把揭開(kāi)白布掸掸。 她就那樣靜靜地躺著氯庆,像睡著了一般。 火紅的嫁衣襯著肌膚如雪扰付。 梳的紋絲不亂的頭發(fā)上堤撵,一...
    開(kāi)封第一講書(shū)人閱讀 51,698評(píng)論 1 305
  • 那天,我揣著相機(jī)與錄音羽莺,去河邊找鬼实昨。 笑死,一個(gè)胖子當(dāng)著我的面吹牛禽翼,可吹牛的內(nèi)容都是我干的屠橄。 我是一名探鬼主播,決...
    沈念sama閱讀 40,418評(píng)論 3 419
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼闰挡,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼锐墙!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起长酗,我...
    開(kāi)封第一講書(shū)人閱讀 39,332評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤溪北,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后夺脾,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體之拨,經(jīng)...
    沈念sama閱讀 45,796評(píng)論 1 316
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,968評(píng)論 3 337
  • 正文 我和宋清朗相戀三年咧叭,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了蚀乔。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 40,110評(píng)論 1 351
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡菲茬,死狀恐怖吉挣,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情婉弹,我是刑警寧澤睬魂,帶...
    沈念sama閱讀 35,792評(píng)論 5 346
  • 正文 年R本政府宣布,位于F島的核電站镀赌,受9級(jí)特大地震影響氯哮,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜商佛,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,455評(píng)論 3 331
  • 文/蒙蒙 一喉钢、第九天 我趴在偏房一處隱蔽的房頂上張望姆打。 院中可真熱鬧,春花似錦出牧、人聲如沸穴肘。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 32,003評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)评抚。三九已至,卻和暖如春伯复,著一層夾襖步出監(jiān)牢的瞬間慨代,已是汗流浹背。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 33,130評(píng)論 1 272
  • 我被黑心中介騙來(lái)泰國(guó)打工啸如, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留侍匙,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 48,348評(píng)論 3 373
  • 正文 我出身青樓叮雳,卻偏偏與公主長(zhǎng)得像想暗,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子帘不,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,047評(píng)論 2 355

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