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这个参数),代码如下所示
//当前选择的NavItemvar 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()//当前选择的NavItemvar 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("这是我的")}}
参考
- Scaffold – Jetpack Compose
- TopAppBar – Jetpack Compose
- BottomAppBar官方文档