問(wèn)題
如何實(shí)現(xiàn)常見(jiàn)應(yīng)用中的底部導(dǎo)航欄的功能惑折?
回答
可以借助 BottomNavigationView
來(lái)實(shí)現(xiàn)這一效果。
效果
簡(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ì)有所幫助种远。
步驟
- 添加
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
, 要求 compileSdkVersion
和 targetSdkVersion
不低于 31 妙同。其他版本的項(xiàng)目要求可以查閱 material-components-android/releases。
- 在 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>
- 第二步中粥帚,
BottomNavigationView
的app: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è)屬性。
- 第三步中的
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>
item
的 drawable
屬性引用 png 之類(lèi)的圖片即可店枣。
至此速警,底部導(dǎo)航欄的樣式就實(shí)現(xiàn)了叹誉。
創(chuàng)建“主頁(yè)”、“聯(lián)系人”和“我的” Fragment 和 layout 文件闷旧。當(dāng)某個(gè)菜單項(xiàng)選中時(shí)长豁,切換到對(duì)應(yīng)的 Fragment。
在 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));
}
}
- 在 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();
}
附
參考資料
- 斌林誠(chéng)上 : Android 底部導(dǎo)航欄 BottomNavigationView
- BottomNavigationView
- material design : bottom-navigation