zoukankan      html  css  js  c++  java
  • 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*/ }
    )
    

    ExtendedFloatingActionButtonFloatingActionButton区别是,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中,有BottomAppBarFloatingActionButton,可以实现下面的效果

    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("这是我的")
        }
    
    }
    

    参考


    提问之前,请先看提问须知 点击右侧图标发起提问 联系我 或者加入QQ群一起学习 Stars-One安卓学习交流群 TornadoFx学习交流群:1071184701
  • 相关阅读:
    js 实现 间隙滚动效果
    js实现无缝滚动
    js 实现弹出层效果
    jQuery实现网页定位导航
    右侧定位的样式
    jQuery实现点击按钮展开和收起
    js实现点击按钮控制展开与收起.
    【BZOJ1202】[HNOI2005]狡猾的商人 带权并查集
    【BZOJ1067】[SCOI2007]降雨量 RMQ+特判
    【BZOJ1367】[Baltic2004]sequence 左偏树
  • 原文地址:https://www.cnblogs.com/stars-one/p/15367233.html
Copyright © 2011-2022 走看看