效果
頁面結構解析
這是一個比較常見的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
寫作不易,有用就點個讚唄 ^ _ ^