Android笔记(七)Android JetPack Compose组件搭建Scaffold脚手架

在去年2022年曾发布一篇关于脚手架的文章:“Android JetPack Compose组件中Scaffold的应用” 。但是Android的版本从12变更到13及以上版本,导致一些细节的实现存在不同。在本文中,将从头开始介绍整个脚手架的搭建过程。

一、新建项目模块

在Android Studio(版本是Graffie)中新建模块,选择“Empty Activity",如图1所示。
在这里插入图片描述
图1

二、定义脚手架Scaffold

@OptIn(ExperimentalMaterial3Api::class)
@SuppressLint("UnusedMaterial3ScaffoldPaddingParameter")
@Composable
fun MainScreen(){Scaffold(//定义头部topBar = {},//定义底部导航bottomBar = {},//定义信息提示区snackbarHost = {},//定义悬浮按钮floatingActionButton = {},content = {//content定义中心区})

或也可以定义成如下形式:

@OptIn(ExperimentalMaterial3Api::class)
@SuppressLint("UnusedMaterial3ScaffoldPaddingParameter")
@Composable
fun MainScreen(){Scaffold(//定义头部topBar = {},//定义底部导航bottomBar = {},//定义信息提示区snackbarHost = {},//定义悬浮按钮floatingActionButton = {}){//content定义中心区}
}

与原来:“Android JetPack Compose组件中Scaffold的应用” 最大的不同在于现在Android13版本的Scaffold取消了drawerContent的属性,因此,导致对于侧滑菜单的定义发生变化。

三、创建三个不同界面

首先,定义一个通用的界面:

@Composable
fun DisplayScreen(title:String, preColor: Color=Color.Black, backgroundColor:Color=colorResource(R.color.teal_200)){Box(contentAlignment= Alignment.Center,modifier = Modifier.fillMaxSize().background(backgroundColor)){Text(text = title,fontSize = 30.sp,color = preColor)}
}

然后,定义的三个不同的界面分别调用上述的DisplayScreen组合函数,代码分别如下,运行效果如图2所示。

@Composable
fun HomeScreen(){DisplayScreen(title = "首页")
}
@Composable
fun SettingScreen(){DisplayScreen(title = "配置")
}
@Composable
fun HelpScreen(){DisplayScreen(title = "帮助和支持")
}

在这里插入图片描述
图2
为了方便后续对这三个界面的切换,定义一个通用的密封类Screen,代码如下

/*** 定义要切换界面的密封类Screen* @property route String 导航线路名* @property title String  标题* @property icon ImageVector 图标* @property loadScreen [@androidx.compose.runtime.Composable] Function0<Unit> 加载动作处理* @constructor*/
sealed class Screen(val route:String, val title:String, val icon: ImageVector, val loadScreen: @Composable ()->Unit){object Home:Screen("home","首页", Icons.Filled.Home,loadScreen={HomeScreen()})object Setting:Screen("setting","配置",Icons.Filled.Settings, loadScreen = {SettingScreen()})object Help:Screen("help","帮助和支持",Icons.Filled.Info, loadScreen = {HelpScreen()})
}

在此前提下定义一个保存要显示界面的列表:

val screens = listOf(Screen.Home,Screen.Setting,Screen.Help)

四、定义底部导航栏

@Composable
fun BottomView(currentScreen: MutableState<Screen>){BottomAppBar {screens.forEach {NavigationBarItem(selected = currentScreen.value.route == it.route,onClick = {//定义点击动作currentScreen.value = it},icon = {Column(horizontalAlignment = Alignment.CenterHorizontally){Icon(imageVector = it.icon,tint = Color.Blue,contentDescription = it.title)Text(text = it.title,fontSize = 20.sp)}})}}
}

然后在Scaffold中进行调用,因为需要保存一个当前屏幕的状态,因此在MainScreen增加一个currentScreen的状态值,修改MainScreen()如下所示。

@OptIn(ExperimentalMaterial3Api::class)
@SuppressLint("UnusedMaterial3ScaffoldPaddingParameter")
@Composable
fun MainScreen(){val currentState:MutableState<Screen> = remember{mutableStateOf(Screen.Home)}Scaffold(//定义头部topBar = {},//定义底部导航bottomBar = {BottomView(currentScreen = currentState)},//定义信息提示区snackbarHost = {},//定义悬浮按钮floatingActionButton = {}){//content定义中心区currentState.value.loadScreen()}
}

这时运行效果如图3所示。
在这里插入图片描述
图3
通过选择底部不同的按钮,可以切换到不同的界面,如图3所示。

五、定义顶部栏

定义顶部栏需要解决两个问题:(1)需要在顶部栏定义顶部的右侧导航菜单;(2)需要定义顶部的导航按钮,使得启动侧滑菜单;

1.定义顶部的后侧菜单

@Composable
fun MenuView(currentScreen: MutableState<Screen>, expandedState:MutableState<Boolean>){DropdownMenu(expanded = expandedState.value,onDismissRequest = {expandedState.value = false}) {screens.forEach {DropdownMenuItem(leadingIcon = {Icon(imageVector = it.icon,contentDescription = it.title)},text = {Text(text = it.title,fontSize = 20.sp)}, onClick = {currentScreen.value = it})}}
}

然后再修改MainScreen,通过一个状态参数expandedState的值判断是否打开菜单,这时修改的MainScreen的代码如下:

@OptIn(ExperimentalMaterial3Api::class)
@SuppressLint("UnusedMaterial3ScaffoldPaddingParameter")
@Composable
fun MainScreen(){//保存当前界面val currentState:MutableState<Screen> = remember{mutableStateOf(Screen.Home)}//记录菜单是否可以扩展val expandedState = remember{mutableStateOf(false)}Scaffold(//定义头部topBar = {TopAppBar(//左侧的文本title = { /*TODO*/ },//导航图标navigationIcon = {},//按行处理的交互actions = {IconButton(onClick={expandedState.value = !expandedState.value}){Icon(imageVector = Icons.Filled.MoreVert,contentDescription = "More...")if(expandedState.value)MenuView(currentState, expandedState)}})},//定义底部导航bottomBar = {BottomView(currentScreen = currentState)},//定义信息提示区snackbarHost = {},//定义悬浮按钮floatingActionButton = {}){//content定义中心区currentState.value.loadScreen()}
}

这时,代码的运行效果如图4所示。
在这里插入图片描述
图4
如图4所示,可以发现右上角出现了更多的图标,点击该图标会弹出一个菜单,通过这个菜单可以切换不同的界面。

2.定义顶部栏的导航按钮启动侧滑菜单

定义侧滑菜单的内容,代码如下所示:

@OptIn(ExperimentalMaterial3Api::class)
@Composable
fun DrawerView(currentScreen: MutableState<Screen>, drawerState: DrawerState,scope:CoroutineScope){ModalNavigationDrawer(drawerState = drawerState,drawerContent = {Column(verticalArrangement = Arrangement.Center,modifier = Modifier.fillMaxHeight().width(360.dp).background(Color.White)){screens.forEach {NavigationDrawerItem(label = {Text(it.title,fontSize = 30.sp)},icon={Icon(imageVector = it.icon,tint=Color.Green,contentDescription = null)},selected = it.route==currentScreen.value.route,onClick = {scope.launch {currentScreen.value = itdrawerState.close()}})}}}) {currentScreen.value.loadScreen()}
}

在此基础上,修改MainScreen,使得点击顶部栏的导航按钮可以弹出侧滑菜单:

@OptIn(ExperimentalMaterial3Api::class)
@SuppressLint("UnusedMaterial3ScaffoldPaddingParameter")
@Composable
fun MainScreen(){val currentState:MutableState<Screen> = remember{mutableStateOf(Screen.Home)}val expandedState = remember{mutableStateOf(false)}val drawerState = rememberDrawerState(initialValue = DrawerValue.Closed)val scope = rememberCoroutineScope()Scaffold(//定义头部topBar = {TopAppBar(//左侧的文本title = {Text("侧滑菜单")},//导航图标navigationIcon = {IconButton(onClick={scope.launch {drawerState.open()}}){Icon(imageVector = Icons.Filled.ArrowForward,contentDescription = "弹出侧滑菜单")}},//按行处理的交互actions = {IconButton(onClick={expandedState.value = !expandedState.value}){Icon(imageVector = Icons.Filled.MoreVert,contentDescription = "More...")if(expandedState.value)MenuView(currentState, expandedState)}})},//定义底部导航bottomBar = {BottomView(currentScreen = currentState)},//定义信息提示区snackbarHost = {},//定义悬浮按钮floatingActionButton = {}){ //content定义中心区//直接调用侧滑界面DrawerView(currentState, drawerState, scope )}
}

注意在MainScreen中的Scaffold的中心区修改为调用drawerView组合函数,并增加DrawerState状态值控制侧滑菜单的启动和关闭,通过调用drawerState的open函数和close函数分别实现。因为drawerState的open函数和close函数均为suspend挂起函数,需要在协程中运行,因此还增加了一个scope的参数,用它来加载drawerState的open函数和close函数。
这时,点击顶部栏的导航图标,运行效果如图5所示。
在这里插入图片描述
图5

六、定义悬浮按钮

悬浮按钮定义在Scaffold脚手架的floatingActionButton属性对应的部分,下列将定义一个悬浮按钮,使得点击该按钮可以返回到首页。代码如下:

@OptIn(ExperimentalMaterial3Api::class)
@SuppressLint("UnusedMaterial3ScaffoldPaddingParameter")
@Composable
fun MainScreen(){val currentState:MutableState<Screen> = remember{mutableStateOf(Screen.Home)}val expandedState = remember{mutableStateOf(false)}val drawerState = rememberDrawerState(initialValue = DrawerValue.Closed)val scope = rememberCoroutineScope()Scaffold(......//定义悬浮按钮floatingActionButton = {FloatingActionButton(onClick = {currentState.value = Screen.Home}) {Icon(imageVector = Icons.Filled.Refresh,contentDescription = "返回")}}){ //content定义中心区DrawerView(currentState, drawerState, scope )}
}

运行效果如图6所示。
在这里插入图片描述
图6

七、定义信息栏

定义一个信息栏增加一个状态值displayedSnackState,通过它来修改信息栏显示的控制。代码示例如下:

@Composable
fun MainScreen(){val currentState:MutableState<Screen> = remember{mutableStateOf(Screen.Home)}val expandedState = remember{mutableStateOf(false)}val drawerState = rememberDrawerState(initialValue = DrawerValue.Closed)val scope = rememberCoroutineScope()val displayedSnackState = remember { mutableStateOf(false)}Scaffold(//定义头部topBar = {TopAppBar(//左侧的文本title = {Text("侧滑菜单")},//导航图标navigationIcon = {IconButton(onClick={scope.launch {drawerState.open()}}){Icon(imageVector = Icons.Filled.ArrowForward,contentDescription = "弹出侧滑菜单")}},//按行处理的交互actions = {IconButton(onClick={expandedState.value = !expandedState.value}){Icon(imageVector = Icons.Filled.MoreVert,contentDescription = "More...")if(expandedState.value)MenuView(currentState, expandedState)}})},//定义底部导航bottomBar = {BottomView(currentScreen = currentState)},//定义信息提示区snackbarHost = {if(displayedSnackState.value){Snackbar(modifier = Modifier.fillMaxWidth().background(Color.Blue),) {Text("提示信息:返回首页",fontSize = 24.sp)}}},//定义悬浮按钮floatingActionButton = {FloatingActionButton(onClick = {currentState.value = Screen.HomedisplayedSnackState.value = !displayedSnackState.value}) {Icon(imageVector = Icons.Filled.Refresh,contentDescription = "返回")}}){ //content定义中心区DrawerView(currentState, drawerState, scope )}
}

运行结果如图7所示:
在这里插入图片描述
图7

八、状态优化的处理

在上述的处理过程中,可以发现MainScreen中定义了很多的状态值,这些状态值往往需要作为函数的参数进行传递,处理过程复杂,可以对这些状态值做一个优化处理。
首先,定义一个类,保存各种需要的状态。代码如下:

@OptIn(ExperimentalMaterial3Api::class)
class StateHolder(val currentScreen:MutableState<Screen>,val expandedState: MutableState<Boolean>,val drawerState: DrawerState,val displayedSnackState:MutableState<Boolean>,val scope:CoroutineScope)

然后再定义一个组合函数获取所有的状态值,代码如下:

@OptIn(ExperimentalMaterial3Api::class)
@Composable
fun rememberStates(currentScreen: MutableState<Screen> = remember { mutableStateOf(Screen.Home) },expandedState: MutableState<Boolean> = remember { mutableStateOf(false) },drawerState: DrawerState = rememberDrawerState(initialValue = DrawerValue.Closed),displayedSnackState: MutableState<Boolean> = remember{mutableStateOf(false)},scope: CoroutineScope = rememberCoroutineScope(),
)=StateHolder(currentScreen,expandedState,drawerState,displayedSnackState,scope)

在此前提的基础上,修改代码,这时以MainScreen为例:

@Composable
fun MainScreen(){val states = rememberStates()Scaffold(//定义头部topBar = {TopAppBar(//左侧的文本title = {Text("侧滑菜单")},//导航图标navigationIcon = {IconButton(onClick={states.scope.launch {states.drawerState.open()}}){Icon(imageVector = Icons.Filled.ArrowForward,contentDescription = "弹出侧滑菜单")}},//按行处理的交互actions = {IconButton(onClick={states.expandedState.value = !states.expandedState.value}){Icon(imageVector = Icons.Filled.MoreVert,contentDescription = "More...")if(states.expandedState.value)MenuView(states)}})},//定义底部导航bottomBar = {BottomView(states)},//定义信息提示区snackbarHost = {if(states.displayedSnackState.value){Snackbar(modifier = Modifier.fillMaxWidth().background(Color.Blue),) {Text("提示信息:返回首页",fontSize = 24.sp)}}},//定义悬浮按钮floatingActionButton = {FloatingActionButton(onClick = {states.currentScreen.value = Screen.Homestates.displayedSnackState.value = !states.displayedSnackState.value}) {Icon(imageVector = Icons.Filled.Refresh,contentDescription = "返回")}}){ //content定义中心区DrawerView(states)}
}

同时对MainScreen调用的MenuView、BottomView和DrawerView中需要传递状态参数的函数进行修改,修改的代码分别是:

MenuView的定义

@OptIn(ExperimentalMaterial3Api::class)
@Composable
fun MenuView(states:StateHolder){DropdownMenu(expanded = states.expandedState.value,onDismissRequest = {states.expandedState.value = false}) {screens.forEach {DropdownMenuItem(leadingIcon = {Icon(imageVector = it.icon,contentDescription = it.title)},text = {Text(text = it.title,fontSize = 20.sp)}, onClick = {states.currentScreen.value = it})}}
}

BottomView的定义

@OptIn(ExperimentalMaterial3Api::class)
@Composable
fun BottomView(states:StateHolder){BottomAppBar {screens.forEach {NavigationBarItem(selected = states.currentScreen.value.route == it.route,onClick = {//定义点击动作states.currentScreen.value = it},icon = {Column(horizontalAlignment = Alignment.CenterHorizontally){Icon(imageVector = it.icon,tint = Color.Blue,contentDescription = it.title)Text(text = it.title,fontSize = 20.sp)}})}}
}

DrawerView的定义

@OptIn(ExperimentalMaterial3Api::class)
@Composable
fun DrawerView(states:StateHolder){ModalNavigationDrawer(drawerState = states.drawerState,drawerContent = {Column(verticalArrangement = Arrangement.Center,modifier = Modifier.fillMaxHeight().width(360.dp).background(Color.White)){screens.forEach {NavigationDrawerItem(label = {Text(it.title,fontSize = 30.sp)},icon={Icon(imageVector = it.icon,tint=Color.Green,contentDescription = null)},selected = it.route==states.currentScreen.value.route,onClick = {states.scope.launch {states.currentScreen.value = itstates.drawerState.close()}})}}}) {states.currentScreen.value.loadScreen()}
}

通过这样的方式,单一传递状态值在不同的组合函数共享。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/166029.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

安装Docker

本安装教程参考Docker官方文档&#xff0c;地址如下&#xff1a;https://docs.docker.com/engine/install/centos/ 卸载旧版 首先如果系统中已经存在旧的Docker&#xff0c;则先卸载&#xff1a; yum remove docker \ docker-client \ docker-client-latest \ docker-common…

经典题型---旋转数组

经典题型—旋转数组 文章目录 经典题型---旋转数组一、题目二、代码实现 一、题目 给定一个整数数组 nums&#xff0c;将数组中的元素向右轮转 k 个位置&#xff0c;其中 k 是非负数。 示例 1: 输入: nums [1,2,3,4,5,6,7], k 3 输出: [5,6,7,1,2,3,4] 解释: 向右轮转 1 步…

Ubuntu系统下使用docker容器配置nginx并部署前端项目

1.下载 Nginx 镜像 命令 描述 docker pull nginx 下载最新版 Nginx 镜像 :2. 创建要挂载的宿主机目录 启动前需要先创建 Nginx 外部挂载的配置文件&#xff08; /home/nginx/conf/nginx.conf&#xff09; 之所以要先创建 , 是因为 Nginx 本身容器只存在 / etc/nginx 目录 ,…

识别准确率竟如此高,实时语音识别服务

前言 本文将介绍一个准确率非常高的语音识别框架&#xff0c;那就是FunASR&#xff0c;这个框架的模型训练数据超过几万个小时&#xff0c;经过测试&#xff0c;准确率非常高。本文将介绍如何启动WebSocket服务和Android调用这个服务来实时识别&#xff0c;一边说话一边出结果…

计算机毕业设计 基于SpringBoot智慧养老中心管理系统的设计与实现 Javaweb项目 Java实战项目 前后端分离 文档报告 代码讲解 安装调试

&#x1f34a;作者&#xff1a;计算机编程-吉哥 &#x1f34a;简介&#xff1a;专业从事JavaWeb程序开发&#xff0c;微信小程序开发&#xff0c;定制化项目、 源码、代码讲解、文档撰写、ppt制作。做自己喜欢的事&#xff0c;生活就是快乐的。 &#x1f34a;心愿&#xff1a;点…

C++:类的默认成员函数------构造函数析构函数(超详细解析,小白一看就懂!)

目录 一、前言 二、为什么会出现构造函数和析构函数 三、构造函数 &#x1f34e;构造函数的概念 &#x1f350;构造函数特性 &#x1f4a6;解释特性3&#xff1a;对象实例化时编译器自动调用对应的构造函数 &#x1f4a6;解释特性4&#xff1a;构造函数支持重载 &…

什么是大数据测试?有哪些类型?应该怎么测?

随着目前世界上各个国家使用大数据应用程序或应用大数据技术场景的数量呈指数增长&#xff0c;相应的&#xff0c;对于测试大数据应用时所需的知识与大数据测试工程师的需求也在同步增加。 针对大数据测试的相关技术已慢慢成为当下软件测试人员需要了解和掌握的一门通用技术。…

YOLOv5改进实战 | 更换主干网络Backbone(四)之轻量化模型MobileNetV3

前言 轻量化网络设计是一种针对移动设备等资源受限环境的深度学习模型设计方法。下面是一些常见的轻量化网络设计方法: 网络剪枝:移除神经网络中冗余的连接和参数,以达到模型压缩和加速的目的。分组卷积:将卷积操作分解为若干个较小的卷积操作,并将它们分别作用于输入的不…

JAVA基础(JAVA SE)学习笔记(六)面向对象编程(基础)

前言 1. 学习视频&#xff1a; 尚硅谷Java零基础全套视频教程(宋红康2023版&#xff0c;java入门自学必备)_哔哩哔哩_bilibili 2023最新Java学习路线 - 哔哩哔哩 第二阶段&#xff1a;Java面向对象编程 6.面向对象编程&#xff08;基础&#xff09; 7.面向对象编程&…

react-router-dom v6版本实现Tabs路由缓存切换

目录 文章目录 概要 效果 完整代码 概要 摆了半年摊&#xff0c;好久没写代码了&#xff0c;今天有人问我怎么实现React-Router-dom类似标签页缓存。后面看了一下router的官网。很久以前用的是react-router v5那个比较容易实现。v6变化挺大&#xff0c;但了解react的机制和rea…

Leetcode—2530.执行K次操作后的最大分数【中等】(C语言向上取整数学公式)

2023每日刷题&#xff08;五&#xff09; Leetcode—2530.执行K次操作后的最大分数 向上取整思想 参考了这篇文章 有人肯定会问&#xff0c;这个向上取整为什么是这样来的。接下来我简单讲解一下。 数学式&#xff1a; x y 数学式&#xff1a;\frac{x}{y} 数学式&#xff1a…

实时消息传送:WebSocket实现系统后台消息实时通知

实时消息传送&#xff1a;WebSocket实现系统后台消息实时通知 WebSocket简介基本实现步骤后台服务器后端接口SimpMessagingTemplate MessageDto前端客户端 示例应用 在现代Web应用中&#xff0c;提供实时通知对于改善用户体验至关重要。WebSocket技术允许建立双向通信通道&…

Linux高性能服务器编程——ch1笔记

第1章 TCP/IP 协议族 1.1 TCP/IP 协议族体系结构以及主要协议 数据链路层 网卡接口的网络驱动程序&#xff0c;以处理数据在物理媒介&#xff08;比如以太网、令牌环等&#xff09;上的传输。 协议&#xff1a;ARP、RARP&#xff0c;实现IP地址和机器物理地址之间的转换。 网络…

IOS屏幕旋转监听

1.设计窗口,添加三个按钮 2.添加事件连接 3.按钮点击事件实现 先添加三个IBAction 实现IBAction 使用旋转立刻生效 -(IBAction)btnFixPortrait:(id)sender{//访问应用程序委托成员_app.mask UIInterfaceOrientationMaskPortrait;//设置窗口旋转属性[self setNeedsUpdateOf…

揭开 Amazon Bedrock 的神秘面纱 | 基础篇

在 2023 年 4 月&#xff0c;亚马逊云科技曾宣布将 Amazon Bedrock 纳入使用生成式人工智能进行构建的新工具集。Amazon Bedrock 是一项完全托管的服务&#xff0c;提供各种来自领先 AI 公司&#xff08;包括 AI21 Labs、Anthropic、Cohere、Stability AI 和 Amazon 等&#xf…

【COMP305 LEC 3 LEC 4】

LEC 3 A basic abstract model for a biological neuron 1. Weights of connections Neuron gets fired if it has received from the presynaptic neurons 突触前神经元 a summary impulse 脉冲, which is above a certain threshold. Signal from a single synapse突触 ma…

LiveQing视频点播流媒体RTMP推流服务功能-如何配置资源进行轮巡播放视频轮播分屏展示

LiveQing视频点播流媒体RTMP推流服务功能-如何配置资源进行轮巡播放视频轮播分屏展示 1、分屏展示2、右击节点新建分组3、配置轮播间隔(秒&#xff09;4、选择资源5、轮巡播放6、停止分组播7、切换播放的流类型8、RTMP推流视频直播和点播流媒体服务 1、分屏展示 2、右击节点新建…

towxml的使用,在微信小程序中快速将markdown格式渲染为wxml文本

towxml的使用&#xff0c;在微信小程序中快速将markdown格式渲染为wxml文本 Towxml概述安装下载 Towxml在小程序中使用 towxml Towxml概述 towxml3.0 支持以下功能&#xff1a; ● echarts图表&#xff0c;默认禁用&#xff0c;需自行构建以开启此功能 ● LaTeX数学公式&#…

【linux】Linux 查看内存使用情况的几种方法汇总

文章目录 GUI 查看命令获取命令 free命令 vmstat命令 top命令 htop Linux 查看内存使用情况的几种方法包括使用 free 命令、top 命令、htop 命令、vmstat 命令和/proc/meminfo 文件。这些方法可以帮助用户了解系统内存的使用情况&#xff0c;包括总内存、已用内存、空闲内存、缓…

FPGA的64点FFT代码及报告,verilog快速傅里叶变换

名称&#xff1a;64点FFT快速傅里叶变换Radix4 软件&#xff1a;Quartus 语言&#xff1a;Verilog 代码功能&#xff1a; 使用verilog实现64-point Pipeline FFT处理器 FPGA代码资源下载网&#xff1a;hdlcode.com 代码下载&#xff1a; 名称&#xff1a;64点FFT快速傅里…