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>
复制代码
到此页面布局的部分介绍完毕,下面开始说代码部分。
代码部分
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 了。
完整代码
写作不易,有用就点个赞呗 ^ _ ^
评论