[Android] NavigationUI + BottomNavigationView 教學

簡介

Navigation Component 導入了 NavigationUI。通過這篇文章,我們來看看如何使用 NavigationUI 來對App bar和頁面切換進行管理。



教學

創建專案

創建專案並選擇 BottomNavigationActivity,目前官方提供的 Sample Code 都已經套用 NavigationUI,可方便建置。


建置內容

此檔案內容負責管理 Fragment 的互動以及跳轉。

Main

<navigation 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:id="@+id/main_navigation" app:startdestination="@id/navigation_index">

    <fragment android:id="@+id/navigation_index" android:name="com.jim.covenantbible.view.IndexFragment" android:label="@string/index_title" tools:layout="@layout/fragment_index">
</fragment></navigation>


bottomnavmenu.xml

此檔案為設定 BottomNavigationView 的項目

<!--xml version="1.0" encoding="utf-8"?-->
<menu xmlns:android="http://schemas.android.com/apk/res/android">
    <item android:id="@+id/navigation_index" android:icon="@drawable/icon_drawer_index" android:title="@string/index_title">
</item></menu>


activity_base.xml

其中使用 CoordinatorLayout 並包含 AppBarLayout (Toolbar)、FragmentContainerView、BottomNavigationView,以下再來細分說明各元件的用途。

Main View


  1. AppBarLayout (Toolbar):為 App 的 Top Action Bar。
    • app:layout_scrollFlags:可實現滑動隱藏 Toolbar。
<com.google.android.material.appbar.appbarlayout style="@style/Widget.Material3.AppBarLayout" android:layout_width="match_parent" android:layout_height="wrap_content" android:fitssystemwindows="true">

    <com.google.android.material.appbar.materialtoolbar android:id="@+id/toolbar" style="@style/TopAppBarTheme" android:layout_width="match_parent" android:layout_height="?attr/actionBarSize" app:contentinsetstart="0dp" app:layout_scrollflags="scroll|enterAlways|snap" app:titlemarginstart="16dp">
</com.google.android.material.appbar.materialtoolbar></com.google.android.material.appbar.appbarlayout>


  1. FragmentContainerView:為 Fragment 顯示的主區塊
    • app:layout_scrollFlags:須設定此項目才可與 Toolbar 組合實現滑動隱藏 Toolbar。
    • app:navGraph:指定Navigation Graph的xml檔。
<androidx.fragment.app.fragmentcontainerview android:id="@+id/nav_host_fragment" android:name="androidx.navigation.fragment.NavHostFragment" android:layout_width="match_parent" android:layout_height="match_parent" app:defaultnavhost="true" app:layout_behavior="@string/appbar_scrolling_view_behavior" app:navgraph="@navigation/main_navigation">


  1. BottomNavigationView:為 Bottom Bar 的主體。
    • app:layout_behavior:可實現滑動隱藏 BottomNavigationView。
    • app:menu:指定 Bottom Bar 項目。
<com.google.android.material.bottomnavigation.bottomnavigationview android:id="@+id/nav_view" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_gravity="bottom|start" android:background="?android:attr/windowBackground" app:labelvisibilitymode="labeled" app:layout_behavior="@string/hide_bottom_view_on_scroll_behavior" app:menu="@menu/bottom_nav_menu">


BaseActivity.kt

class BaseActivity : AppCompatActivity() {
    lateinit var binding: ActivityBaseBinding

    private var nowSelectedPageID: Int? = 0

    //region System Function
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        binding = ActivityBaseBinding.inflate(layoutInflater)
        setContentView(binding.root)

        this.initNavigation()
    }
    //endregion

    //region NavigateUI Function
    /**
     * set Fragment Navigation
     * @menu/bottom_nav_menu: 底部 Navigation bar
     * @navigation/main_navigation:主要控管 Fragment 的 Host Navigation
     */
    private fun initNavigation() {
        val navController = (supportFragmentManager.findFragmentById(R.id.nav_host_fragment) as NavHostFragment).navController.apply {
            this.addOnDestinationChangedListener { _, destination, _ -&gt;
                if (this@BaseActivity.nowSelectedPageID == destination.id) {
                    return@addOnDestinationChangedListener
                }

                this@BaseActivity.nowSelectedPageID = destination.id
                when (destination.id) {
                    R.id.navigation_index -&gt; {
                        binding.navView.visibility = View.VISIBLE
                        binding.btnClickLeft.visibility = View.GONE
                        binding.btnClickRight.visibility = View.GONE
                    }
                    else -&gt; {
                        binding.navView.visibility = View.GONE
                        binding.btnClickLeft.visibility = View.GONE
                        binding.btnClickRight.visibility = View.GONE
                    }
                }
            }
        }

        setSupportActionBar(binding.toolbar)

        // Passing each menu ID as a set of Ids because each
        // menu should be considered as top level destinations.
        val appBarConfiguration = AppBarConfiguration(setOf(R.id.navigation_index))
        setupActionBarWithNavController(navController, appBarConfiguration)
        binding.navView.setupWithNavController(navController)
    }

    /**
     * if using setupActionBarWithNavController then also override and config this methods
     */
    override fun onSupportNavigateUp(): Boolean {
        val navController = (supportFragmentManager.findFragmentById(R.id.nav_host_fragment) as NavHostFragment).navController
        return navController.navigateUp() || super.onSupportNavigateUp()
    }

    fun changeBottomNavigationViewItem(pageID: Int) {
        this.binding.navView.selectedItemId = pageID
    }
    //endregion
}

留言

這個網誌中的熱門文章

[Android] Glide 教學

[ 教程 - 破解 ] IOS 10.2 JB 教學

[教學] AdMob for Android App