Jetpack Compose学习(7)——MD样式架构组件Scaffold及导航底部菜单
Jetpack Compose学习(7)——MD样式架构组件Scaffold及导航底部菜单 | Stars-One的杂货小窝
Compose给我们提供了一个Material Design样式的首页组件(
Scaffold),我们可以直接套用从而完成一个APP的首页界面
本系列以往文章请查看此分类链接Jetpack compose学习
由于Scaffold中还包含有其他的组件,所以讲解Scaffold先讲解前置的一些组件
TopAppBar
首先,便是TopAppBar,其本质就是我们Android原生常见的Toolbar,不过其封装的比较好,可以快速构建,下面是其的参数列表
TopAppBar( title: @Composable () -> Unit, modifier: Modifier = Modifier, navigationIcon: @Composable (() -> Unit)? = null, actions: @Composable RowScope.() -> Unit = {}, backgroundColor: Color = MaterialTheme.colors.primarySurface, contentColor: Color = contentColorFor(backgroundColor), elevation: Dp = AppBarDefaults.TopAppBarElevation )
title
标题,接收Compose组件,可以传个Text文本进去modifier
修饰符,详情见上一章节navigationIcon
导航图标actions
动作组件backgroundColor
背景色contentColor
内容颜色elevation
阴影
可能说的那么明确,我们直接上代码和效果图,各位就清晰了
TopAppBar( navigationIcon = { IconButton( onClick = {} ) { Icon(Icons.Filled.Menu, null) } }, title = { Text("stars-one的测试应用") },actions = { IconButton( onClick = {} ) { Icon(Icons.Filled.Share, null) } IconButton( onClick = {} ) { Icon(Icons.Filled.Settings, null) } } )
效果图如下
FloatingActionButton
比较常见的悬浮按钮,一般里面是个简单的按钮,参数与之前的Button一样,详情请参考Jetpack Compose学习(3)——图标(Icon) 按钮(Button) 输入框(TextField) 的使用 | Stars-One的杂货小窝
FloatingActionButton( onClick: () -> Unit, modifier: Modifier = Modifier, interactionSource: MutableInteractionSource = remember { MutableInteractionSource() }, shape: Shape = MaterialTheme.shapes.small.copy(CornerSize(percent = 50)), backgroundColor: Color = MaterialTheme.colors.secondary, contentColor: Color = contentColorFor(backgroundColor), elevation: FloatingActionButtonElevation = FloatingActionButtonDefaults.elevation(), content: @Composable () -> Unit )
使用:
FloatingActionButton(onClick = { /*TODO*/ }) { Icon(imageVector = Icons.Default.Add, contentDescription = null) }
PS: 一般这个与
Scaffold连用,Scaffold里面可控制FloatingActionButton的位置
除此之外,还有个
ExtendedFloatingActionButton,这种就是可以带图标和文字的,如下图
ExtendedFloatingActionButton( icon = { Icon(Icons.Filled.Favorite, contentDescription = null) }, text = { Text("ADD TO BASKET") }, onClick = { /*do something*/ } )
ExtendedFloatingActionButton和
FloatingActionButton区别是,
ExtendedFloatingActionButton是以文字为主,图标是可选的,而
FloatingActionButton只显示图标
BottomAppBar
这个与之前的TopAppBar参数有所不同,从名字看我们知道其实放在底部的一个Toolbar,但是其本身是不带有位置控制,也是得与Scaffold连用,如果单独使用,效果也是会和TopAppBar的一样放在页面的顶头
BottomAppBar( modifier: Modifier = Modifier, backgroundColor: Color = MaterialTheme.colors.primarySurface, contentColor: Color = contentColorFor(backgroundColor), cutoutShape: Shape? = null, elevation: Dp = AppBarDefaults.BottomAppBarElevation, contentPadding: PaddingValues = AppBarDefaults.ContentPadding, content: @Composable RowScope.() -> Unit )
可以把这个布局看作是个Row布局,里面的参数从名字都能看到出来,设置背景色或者设置padding边距的,这里不再赘述
唯一值得注意的是
cutoutShape属性,如果在
Scaffold中,有
BottomAppBar和
FloatingActionButton,可以实现下面的效果
BottomNavigation
BottomNavigation里面会有N个
BottomNavigationItem,这里就看你自己准备定义多少个菜单项了
BottomNavigation( modifier: Modifier = Modifier, backgroundColor: Color = MaterialTheme.colors.primarySurface, contentColor: Color = contentColorFor(backgroundColor), elevation: Dp = BottomNavigationDefaults.Elevation, content: @Composable RowScope.() -> Unit )
BottomNavigation提供的一些参数也就是改变颜色或者阴影,重点是在
BottomNavigationItem
BottomNavigationItem( selected: Boolean, onClick: () -> Unit, icon: @Composable () -> Unit, modifier: Modifier = Modifier, enabled: Boolean = true, label: @Composable (() -> Unit)? = null, alwaysShowLabel: Boolean = true, interactionSource: MutableInteractionSource = remember { MutableInteractionSource() }, selectedContentColor: Color = LocalContentColor.current, unselectedContentColor: Color = selectedContentColor.copy(alpha = ContentAlpha.medium) )
BottomNavigationItem有个
selected参数,表示是否选中
icon则是图标的设置,
label则是文字,这两个都是需要接收一个组件的
selectedContentColor
选中颜色unselectedContentColor
未选中颜色
下面直接来个例子讲解
var selectIndex by remember { mutableStateOf(0) } val navList = listOf("首页","发现","我的") BottomNavigation() { navList.forEachIndexed { index, str -> BottomNavigationItem( selected = index == selectIndex, onClick = { selectIndex = index }, icon = { Icon(imageVector = Icons.Default.Favorite, contentDescription =null ) },label = {Text(str)} ) } } Text(text = "这是${navList[selectIndex]}")
效果如下所示
Scaffold
Scaffold( modifier: Modifier = Modifier, scaffoldState: ScaffoldState = rememberScaffoldState(), topBar: @Composable () -> Unit = {}, bottomBar: @Composable () -> Unit = {}, snackbarHost: @Composable (SnackbarHostState) -> Unit = { SnackbarHost(it) }, floatingActionButton: @Composable () -> Unit = {}, floatingActionButtonPosition: FabPosition = FabPosition.End, isFloatingActionButtonDocked: Boolean = false, drawerContent: @Composable (ColumnScope.() -> Unit)? = null, drawerGesturesEnabled: Boolean = true, drawerShape: Shape = MaterialTheme.shapes.large, drawerElevation: Dp = DrawerDefaults.Elevation, drawerBackgroundColor: Color = MaterialTheme.colors.surface, drawerContentColor: Color = contentColorFor(drawerBackgroundColor), drawerScrimColor: Color = DrawerDefaults.scrimColor, backgroundColor: Color = MaterialTheme.colors.background, contentColor: Color = contentColorFor(backgroundColor), content: @Composable (PaddingValues) -> Unit )
属性说明
topBar
顶部的布局bottomBar
底部的布局floatingActionButton
悬浮按钮布局floatingActionButtonPosition
悬浮按钮位置,有FabPosition.End
(默认)和FabPosition.Center
可选isFloatingActionButtonDocked
与BottomAppBar配合使用,可以实现底部导航条的裁剪效果,效果可以看下图drawerGesturesEnabled
是否开启侧边抽屉手势(开启后可侧滑弹出抽屉)drawerShape
抽屉的形状drawerContent
侧边抽屉内容,是个Column布局,自己可以顺便排列drawerElevation
侧边抽屉的阴影drawerBackgroundColor
侧边抽屉的背景色drawerContentColor
侧边抽屉内容颜色(似乎是覆盖字体颜色而已)drawerScrimColor
侧边抽屉遮盖最底层的颜色
基本使用
使用5个属性
topBar
bottomBar
floatingActionButton
floatingActionButtonPosition
isFloatingActionButtonDocked,实现个简单架构效果
Scaffold( topBar = { TopAppBar( navigationIcon = { IconButton( onClick = {} ) { Icon(Icons.Filled.Menu, null) } }, title = { Text("stars-one的测试应用") },actions = { IconButton( onClick = {} ) { Icon(Icons.Filled.Share, null) } IconButton( onClick = {} ) { Icon(Icons.Filled.Settings, null) } } )}, floatingActionButton = { FloatingActionButton(onClick = { /*TODO*/ }) { Icon(imageVector = Icons.Default.Favorite, contentDescription = null) } }, bottomBar = { BottomAppBar(cutoutShape = CircleShape) { } }, //注意此参数,可以实现图中那种被裁剪的效果,前提是上面的cutoutShape也有设置 isFloatingActionButtonDocked = true, floatingActionButtonPosition = FabPosition.End ) { //这里是主界面 Text("我是要展示的内容") }
效果如下图所示
底部导航条
我们在上面的基础改下即可(主要是bottomAppBar这个参数),代码如下所示
//当前选择的NavItem var selectIndex by remember { mutableStateOf(0) } val navTextList = listOf("主页", "发现", "我的") //图标 val iconList = listOf(Icons.Default.Home,Icons.Default.Favorite,Icons.Default.AccountBox) Scaffold( topBar = { TopAppBar( navigationIcon = { IconButton( onClick = {} ) { Icon(Icons.Filled.Menu, null) } }, title = { Text("stars-one的测试应用") },actions = { IconButton( onClick = {} ) { Icon(Icons.Filled.Share, null) } IconButton( onClick = {} ) { Icon(Icons.Filled.Settings, null) } } )}, floatingActionButton = { FloatingActionButton(onClick = { /*TODO*/ }) { Icon(imageVector = Icons.Default.Add, contentDescription = null) }}, bottomBar = { BottomNavigation() { navTextList.forEachIndexed { index, str -> BottomNavigationItem(label = {Text(str)},selected = index==selectIndex , onClick = {selectIndex = index },icon = { Icon(imageVector = iconList[index], contentDescription = null) }) } } }, //注意此参数,可以实现图中那种被裁剪的效果,前提是上面的cutoutShape也有设置 floatingActionButtonPosition = FabPosition.End ) { //这里是主界面 //根据底部导航选中的下标改变展示的页面 when(selectIndex){ 0 -> Text("这是首页") 1 -> Text("这是发现") 2 -> Text("这是我的") } }
效果如下图所示
带侧边抽屉
这里需要注意的是,弹出侧边抽屉是个挂起操作(suspend),所以需要使用到Kotlin中的协程,不过不是涉及太深,我们先知道怎么用即可,后面有空我再补充协程的用法
这里主要是测试了带drawer开头的那几个参数,及点击左上角的菜单按钮弹出侧边抽屉功能(即对应的点击事件)
//状态 val scaffoldState = rememberScaffoldState() //协程的作用域 val scope = rememberCoroutineScope() //当前选择的NavItem var selectIndex by remember { mutableStateOf(0) } val navTextList = listOf("主页", "发现", "我的") //图标 val iconList = listOf(Icons.Default.Home, Icons.Default.Favorite, Icons.Default.AccountBox) Scaffold( scaffoldState = scaffoldState, topBar = { TopAppBar( navigationIcon = { IconButton( onClick = { //使用协程 scope.launch { //改变状态,显示drawer抽屉 scaffoldState.drawerState.open() } } ) { Icon(Icons.Filled.Menu, null) } }, title = { Text("stars-one的测试应用") }, actions = { IconButton( onClick = {} ) { Icon(Icons.Filled.Share, null) } IconButton( onClick = {} ) { Icon(Icons.Filled.Settings, null) } } ) }, floatingActionButton = { FloatingActionButton(onClick = { /*TODO*/ }) { Icon(imageVector = Icons.Default.Add, contentDescription = null) }}, bottomBar = { BottomNavigation() { navTextList.forEachIndexed { index, str -> BottomNavigationItem( label = { Text(str) }, selected = index == selectIndex, onClick = { selectIndex = index }, icon = { Icon( imageVector = iconList[index], contentDescription = null ) }) } } }, //注意此参数,可以实现图中那种被裁剪的效果,前提是上面的cutoutShape也有设置 floatingActionButtonPosition = FabPosition.End, drawerContent = { Text("这是抽屉的内容") }, drawerContentColor = Color.Black, drawerBackgroundColor = Color.Green, drawerGesturesEnabled = true, drawerScrimColor = Color.Red, drawerShape = RoundedCornerShape(20.dp) ) { //这里是主界面 //根据底部导航选中的下标改变展示的页面 when (selectIndex) { 0 -> Text("这是首页") 1 -> Text("这是发现") 2 -> Text("这是我的") } }
参考
- Jetpack Compose学习(5)——从登录页美化开始学习布局组件使用
- Jetpack架构组件学习(0)——总结篇
- Jetpack架构组件学习(1)——LifeCycle的使用
- Jetpack架构组件学习(2)——ViewModel和Livedata使用
- bootstrap菜单、按钮及导航学习笔记5-18导航(基础样式)
- 转-TabHost组件(二)(实现底部菜单导航)
- Android Jetpack架构组件 — Navigation入坑详解
- 转-TabHost组件(一)(实现底部菜单导航)
- Android Jetpack架构组件 — Room入坑详解
- Android使用开源组件PagerBottomTabStrip实现底部菜单和顶部导航功能
- Android Jetpack架构组件 — LiveData与ViewModel入坑详解
- Android Jetpack架构组件 — Lifecycle入坑指南
- Flutter第五期 - 样式、Scaffold、TabBar、底部导航
- Android Jetpack 架构组件篇(一)
- 安卓开发笔记——TabHost组件(二)(实现底部菜单导航)
- 初步学习JetPack组件——Paging
- Jetpack Compose 架构比较:MVP & MVVM & MVI
- 安卓开发笔记——TabHost组件(一)(实现底部菜单导航)
- bootstrap菜单、按钮及导航学习笔记5-15导航(基础样式)
- Metro UI CSS 学习笔记之组件(菜单与导航)