Kotlin APP首頁主流框架搭建DrawerLayout+NavigationView+Toolbar+ViewPager+BottomNavigationView

效果

在這裏插入圖片描述

頁面結構解析

這是一個比較常見的APP首頁的結構,側邊欄+主頁,側邊欄裏是一些菜單,主頁由底部菜單控制內容區,內容區是可滑動的子頁面。整體比較舒服合理,各自爲陣,卻又能關聯在一起,加上又是大衆喜愛的Material Design風格,所以成爲了當下APP首頁的主流結構。
在這裏插入圖片描述
上圖是做的一個簡單的思維導圖,並不複雜,理清了結構就能事半功倍。


頁面佈局

1.首頁

即整個大的容器。
在這裏插入圖片描述

<?xml version="1.0" encoding="utf-8"?>
<androidx.drawerlayout.widget.DrawerLayout
    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/drawer_layout"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:fitsSystemWindows="true"
    tools:context=".module.MainActivity"
    tools:openDrawer="start">

    <include
        layout="@layout/app_bar_main"
        android:layout_width="match_parent"
        android:layout_height="match_parent" />

    <com.google.android.material.navigation.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_main"
        app:menu="@menu/activity_main_drawer" />

</androidx.drawerlayout.widget.DrawerLayout>
  • DrawerLayout包裹着include的主頁和側邊欄內容NavigationView
  • app_bar_main是主頁內容,採用include的方式引用是爲了結構清晰,避免混亂。
  • 側邊欄NavigationView分爲頭部佈局headerLayout和菜單menu,注意一個是layout一個是menu。
  • 其他需要注意的是,NavigationView的位置應與主內容app_bar_main同級,且在主內容之後。
  • 關於DrawerLayout更多使用可以查看:DrawerLayout使用詳解

2.主頁

這裏主頁說的是首頁除側邊欄以外的頁面。
在這裏插入圖片描述

<?xml version="1.0" encoding="utf-8"?>
<androidx.coordinatorlayout.widget.CoordinatorLayout
    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"
    tools:context=".module.MainActivity">

    <com.google.android.material.appbar.AppBarLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:theme="@style/AppTheme.AppBarOverlay">

        <androidx.appcompat.widget.Toolbar
            android:id="@+id/toolbar"
            android:layout_width="match_parent"
            android:layout_height="?attr/actionBarSize"
            android:background="?attr/colorPrimary"
            app:popupTheme="@style/AppTheme.PopupOverlay"/>

    </com.google.android.material.appbar.AppBarLayout>

    <include layout="@layout/content_main"/>

    <com.google.android.material.floatingactionbutton.FloatingActionButton
        android:id="@+id/fab"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="bottom|end"
        android:layout_marginRight="@dimen/dp_20"
        android:layout_marginEnd="@dimen/dp_20"
        android:layout_marginBottom="@dimen/dp_70"
        app:srcCompat="@android:drawable/ic_dialog_email"/>

</androidx.coordinatorlayout.widget.CoordinatorLayout>

上面是標題,中間是內容區,FloatingActionButton可以忽略。

3.主頁內容區

效果同2一樣

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout 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"
    app:layout_behavior="@string/appbar_scrolling_view_behavior"
    tools:context=".module.MainActivity"
    tools:showIn="@layout/app_bar_main">

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

        <androidx.viewpager.widget.ViewPager
            android:id="@+id/view_pager"
            android:layout_width="match_parent"
            android:layout_height="0dp"
            android:layout_weight="1" />

        <com.google.android.material.bottomnavigation.BottomNavigationView
            android:id="@+id/bottom_navigation"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_marginTop="8dp"
            android:background="?android:attr/windowBackground"
            app:layout_constraintBottom_toTopOf="@+id/viewPager"
            app:menu="@menu/bottom_navigation" />

    </LinearLayout>

</androidx.constraintlayout.widget.ConstraintLayout>

  • 上面是ViewPager,可滑動的內容區,填充一個一個的Fragment子頁面。
  • 下面是BottomNavigationView底部菜單,與上面的ViewPager關聯。

到此頁面佈局的部分介紹完畢,下面開始說代碼部分。


代碼部分

1.側邊欄

我們要在toolbar上加一個按鈕,把側邊欄關聯起來,讓其點擊可以彈出側邊欄。

    /**
     * Drawer關聯Toolbar
     */
    private fun initActionBarDrawer() {
        val toggle = ActionBarDrawerToggle(
            this,
            drawer_layout,
            toolbar,
            R.string.navigation_drawer_open,
            R.string.navigation_drawer_close
        )
        drawer_layout.addDrawerListener(toggle)
        toggle.syncState()
    }

2.內容區

關聯了側邊欄,我們來看內容區,上面說過內容區是ViewPager包含的一個個子頁面Fragment,來看代碼的實現

    /**
     * 初始化Fragment
     */
    private fun initFragments() {
        val viewPagerAdapter = CommonViewPagerAdapter(supportFragmentManager)
        viewPagerAdapter.addFragment(HomeFragment())
        viewPagerAdapter.addFragment(TreeFragment())
        viewPagerAdapter.addFragment(NaviFragment())
        viewPagerAdapter.addFragment(ProjectFragment())

        view_pager.offscreenPageLimit = 1
        view_pager.adapter = viewPagerAdapter
    }

處理事件

1.側邊欄點擊事件

        /**
         * 側邊欄點擊事件
         */
        nav_view.setNavigationItemSelectedListener {
            // Handle navigation view item clicks here.
            when (it.itemId) {
                R.id.nav_collect -> {
                    ToastUtilKt.showToast("收藏")
                }
                R.id.nav_share -> {
                    ToastUtilKt.showToast("分享")
                }
                R.id.nav_about -> {
                    ToastUtilKt.showToast("關於")
                }
                R.id.nav_logout -> { 
                    ToastUtilKt.showToast("退出") 
                }
            }

            //關閉側邊欄
            drawer_layout.closeDrawer(GravityCompat.START)

            true
        }

根據itemId判斷觸發事件,並關閉側邊欄,這一步可選,也可以不關閉 保持側邊欄打開的狀態。

2.view_pager 滑動監聽

        /**
         * view_pager 滑動監聽
         */
        view_pager.addOnPageChangeListener(object : OnPageChangeListener {
            override fun onPageScrollStateChanged(state: Int) {
            }

            override fun onPageScrolled(
                position: Int,
                positionOffset: Float,
                positionOffsetPixels: Int
            ) {
            }

            override fun onPageSelected(position: Int) {
                bottom_navigation.menu.getItem(position).isChecked = true
                //設置checked爲true,但是不能觸發ItemSelected事件,所以滑動時也要設置一下標題
                when (position) {
                    0 -> {
                        toolbar.title = resources.getString(R.string.app_name)
                    }
                    1 -> {
                        toolbar.title = resources.getString(R.string.title_tree)
                    }
                    2 -> {
                        toolbar.title = resources.getString(R.string.title_navi)
                    }
                    else -> {
                        toolbar.title = resources.getString(R.string.title_project)
                    }
                }
            }
        })

view_pager滑動之後底部對應的菜單選中,並重新設置標題。

3.bottom_navigation 底部菜單點擊事件

        /**
         * bottom_navigation 點擊事件
         */
        bottom_navigation.setOnNavigationItemSelectedListener {
            when (it.itemId) {
                R.id.navigation_home -> {
                    view_pager.currentItem = 0
                    return@setOnNavigationItemSelectedListener true
                }
                R.id.navigation_tree -> {
                    view_pager.currentItem = 1
                    return@setOnNavigationItemSelectedListener true
                }
                R.id.navigation_navi -> {
                    view_pager.currentItem = 2
                    return@setOnNavigationItemSelectedListener true
                }
                R.id.navigation_project -> {
                    view_pager.currentItem = 3
                    return@setOnNavigationItemSelectedListener true
                }
            }
            false
        }

底部菜單點擊的時候也讓view_pager滑動的響應的位置,同第2步其實是相互關聯的。


到此,整個搭建就完成了,從頁面佈局到初始化控件,再到處理事件,整體思路要清晰,搭建起來就很快,小的功能細節再調試完善完善就ok了。


完整代碼

https://github.com/yechaoa/wanandroid_kotlin


寫作不易,有用就點個讚唄 ^ _ ^


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章