Jetpack Compose常用UI组件实战演练

一、前言

这是 Jetpack Compose 系列的第五篇。前面四篇我们介绍了Compose的背景、完成了第一个Compose程序理解了Composable与Modifier的核心机制,还深入学习了Modifier的各种修饰符。今天,让我们用实战的方式,系统学习Compose中最常用的UI组件。

Compose的组件体系和传统的 Android View 一样:布局组件决定UI怎么排列,基础组件决定UI长什么样,列表组件决定大量数据怎么展示。下面逐一展示给大家。

二、布局容器

传统 Android UI开发用 XML 写布局(LinearLayoutRelativeLayoutFrameLayout),Compose 则使用Kotlin函数描述布局。最常用的三个容器是 ColumnRow Box

Column——纵向排列,子组件从上到下依次摆放

@Composable
fun ColumnExample() {
    Column(
        modifier = Modifier
            .fillMaxWidth()
            .padding(16.dp),
        verticalArrangement = Arrangement.spacedBy(8.dp)
    ) {
        Text("北京")
        Text("上海")
        Text("广州")
    }
}

Row——横向排列,子组件从左到右依次摆放。

@Composable
fun RowExample() {
    Row(
        modifier = Modifier
            .fillMaxWidth()
            .padding(16.dp),
        horizontalArrangement = Arrangement.SpaceEvenly
    ) {
        Text("左")
        Text("中")
        Text("右")
    }
}

Box——层叠布局,子组件堆叠在一起,类似传统View 体系的FrameLayout

@Composable
fun BoxExample() {
    Box(
        modifier = Modifier.size(150.dp),
        contentAlignment = Alignment.Center
    ) {
        Box(modifier = Modifier
            .fillMaxSize()
            .background(Color.Yellow))
        Text("文字居中", color = Color.White)
    }
}

💡Column 和 Row负责”排列“,Box 负责”叠加“。三者配合可以构建绝大多数界面布局。

布局效果如下:
在这里插入图片描述

三、基础组件

3.1 Text

Text 文本组件,用来显示文本,替代传统的TextView,支持丰富的样式配置。如:

  • fontWeight:文本的粗细
  • fontFamily:文本的字体
  • fontStyle:文本的变体(Italic/Normal)
  • lineHeight:行高

除了直接给 Text 传入要显示的文字内容外,Compose 同样支持 R资源 的方式获取字符串——stringResource()

@Composable
fun TextExample() {
    // 指定字符串
    Text(
        text = "Hello Compose!",
        fontSize = 20.sp,
        fontWeight = FontWeight.Bold,
        color = Color.Blue,
        text = TextAlign.Center,
        maxLines = 1,
        modifier = Modifier.padding(16.dp)
    )
    
    // 指定文字资源
    Text(
     	text = stringResource(R.string.hello_world)
    )
}

3.2 Image

Image 图片组件,显示图片,替代传统的 ImageView。支持3种类型的图片设置:

  • ImageVector:矢量图对象,可以显示SVG格式的图
  • ImageBitmap:位图对象,可以显示JPG、PNG等格式图
  • Painter:自定义画笔,可以在Canvas上直接绘制图

Image 组件支持直接传递实例参数,但一般开发中我们优先使用 res/drawable 下的资源图。

@Composable
fun ImageSample() {
    Column() {
        Image(
            painter = painterResource(id = R.drawable.ic_weather_sun),
            contentDescription = "晴",
        )
        Image(
            bitmap = ImageBitmap.imageResource(id = R.drawable.pic_2),
            contentDescription = null
        )
        // 本地图片放在 res/drawable 目录下,通过 painterResource 加载的示例。
        Image(
            imageVector = ImageVector.vectorResource(id = R.drawable.ic_search),
            contentDescription = "矢量图资源"
        )

    }
}

图片显示效果如下:
在这里插入图片描述

熟悉传统 Android View的小伙伴肯定熟悉 scaleType,它用来指定图片的伸缩样式(拉伸、裁剪、留白还是保持原样),Compose的 Image 同样有提供这样的功能——contentScale参数

ContentScale类型说明
ContentScale.Crop按比例缩放使图片完全覆盖容器,超出部分裁剪,类似ScaleType.centerCrop
ContentScale.Fit按比例缩放使图片完整显示在容器内,居中,类似ScaleType.fitCenter
ContentScale.Inside完整显示且不放大,仅当图片大于容器时缩小,类似ScaleType.centerInside
ContentScale.FillBounds不保持比例拉伸填满容器,类似ScaleType.fitXY
ContentScale.FillWidthCompose独有,按比例缩放使图片宽度填满容器,高度自适应
ContentScale.FillHeightCompose独有,按比例缩放使图片高度填满容器,宽度自适应
ContentScale.None不缩放,原尺寸居中绘制,过大裁剪/过小留白,类似ScaleType.center

在这里插入图片描述

3.3 Button

Button 按钮组件,处理点击交互用,Material 3 提供了多种的按钮样式。

@Composable
fun ButtonExample() {
    var clickCount by remember { mutableStateOf(0) }
    
    Button(
        onClick = { clickCount++ },
        modifier = Modifier.padding(16.dp)
    ) {
        Text(
            text = "点击次数: $clickCount",
            fontSize = 18.sp,
            modifier = Modifier.padding(2.dp)
        )
    }
}

Button 的点击事件通过 onClick 参数传入,组件内部状态用remember { mutableStateOf()} 管理。

四、列表

LazyColumn ——高性能列表,类似传统Android View中的 RecyclerView

@Composable
fun LazyColumnExample() {
    val items = List(50) { "条目 #$it" }
    
    LazyColumn(modifier = Modifier.fillMaxSize()) {
        items(items) { item ->
            Text(
                text = item,
                modifier = Modifier
                    .fillMaxWidth()
                    .padding(16.dp)
            )
        }
    }
}

运行代码效果如下:
在这里插入图片描述

五、页面骨架

Scaffold —— Material Design 页面骨架,内置了TopAppBarFloatingActionButtonNavigationBar等。

@Composable
fun ScaffoldExample() {
    var fabClickCount by remember { mutableStateOf(0) }
    
    Scaffold(
        topBar = {
            TopAppBar(title = { Text("我的应用") })
        },
        floatingActionButton = {
            FloatingActionButton(onClick = { fabClickCount++ }) {
                Icon(Icons.Default.Add, contentDescription = "添加")
            }
        }
    ) { innerPadding ->
        Box(
            modifier = Modifier
                .fillMaxSize()
                .padding(innerPadding),
            contentAlignment = Alignment.Center
        ) {
            Text("FAB点击: $fabClickCount 次")
        }
    }
}

效果示意图如下:

在这里插入图片描述

六、综合实践

看了这么多单个组件用法,下面让我们来完成综合学习——使用上面提到的组件实现一个天气主界面:

private val city = "北京"
private val currentTemp = "28°C"
private val weatherCondition = "晴"
private val feelsLike = "26°C"
private val humidity = "65%"
private val wind = "12 km/h"

private val hourlyList = listOf(
    "现在 28°", "13:00 29°", "14:00 30°", "15:00 29°", "16:00 28°"
)

private val dailyList = listOf(
    "今天 30°/22° 晴",
    "周一 28°/20° 多云",
    "周二 26°/19° 小雨",
    "周三 27°/21° 晴",
    "周四 29°/23° 多云",
    "周五 31°/24° 晴",
    "周六 30°/22° 阴"
)

@Composable
fun SimpleWeatherScreen() {
    Scaffold { innerPadding ->
        Column(
            modifier = Modifier
                .fillMaxSize()
                .padding(innerPadding)
                .padding(16.dp),
            horizontalAlignment = Alignment.CenterHorizontally
        ) {
            Row(
                modifier = Modifier.fillMaxWidth(),
                horizontalArrangement = Arrangement.SpaceBetween,
                verticalAlignment = Alignment.CenterVertically
            ) {
                Text(
                    text = city,
                    fontSize = 24.sp,
                    fontWeight = FontWeight.Bold
                )
            }

            Spacer(modifier = Modifier.height(20.dp))

            Box(
                modifier = Modifier
                    .fillMaxWidth()
                    .height(150.dp),
                contentAlignment = Alignment.Center
            ) {
                Column(horizontalAlignment = Alignment.CenterHorizontally) {
                    Image(
                        painter = painterResource(id = android.R.drawable.ic_menu_gallery),
                        contentDescription = "天气图标",
                        modifier = Modifier.size(60.dp)
                    )
                    Text(
                        text = currentTemp,
                        fontSize = 40.sp,
                        fontWeight = FontWeight.Bold
                    )
                    Text(text = weatherCondition, fontSize = 18.sp)
                }
            }

            Spacer(modifier = Modifier.height(16.dp))

            Row(
                modifier = Modifier.fillMaxWidth(),
                horizontalArrangement = Arrangement.SpaceEvenly
            ) {
                Column(horizontalAlignment = Alignment.CenterHorizontally) {
                    Text(text = feelsLike, fontWeight = FontWeight.Bold)
                    Text(text = "体感", fontSize = 12.sp, color = Color.Gray)
                }
                Column(horizontalAlignment = Alignment.CenterHorizontally) {
                    Text(text = humidity, fontWeight = FontWeight.Bold)
                    Text(text = "湿度", fontSize = 12.sp, color = Color.Gray)
                }
                Column(horizontalAlignment = Alignment.CenterHorizontally) {
                    Text(text = wind, fontWeight = FontWeight.Bold)
                    Text(text = "风速", fontSize = 12.sp, color = Color.Gray)
                }
            }

            Spacer(modifier = Modifier.height(20.dp))

            Row(
                modifier = Modifier.fillMaxWidth(),
                horizontalArrangement = Arrangement.SpaceEvenly
            ) {
                hourlyList.take(5).forEach { item ->
                    Column(horizontalAlignment = Alignment.CenterHorizontally) {
                        Text(text = item.split(" ")[0], fontSize = 12.sp)
                        Image(
                            painter = painterResource(id = android.R.drawable.ic_menu_gallery),
                            contentDescription = null,
                            modifier = Modifier.size(24.dp)
                        )
                        Text(text = item.split(" ")[1], fontSize = 12.sp)
                    }
                }
            }

            Spacer(modifier = Modifier.height(20.dp))

            LazyColumn(
                modifier = Modifier.fillMaxSize(),
                verticalArrangement = Arrangement.spacedBy(8.dp)
            ) {
                items(dailyList) { dayInfo ->
                    val parts = dayInfo.split(" ")
                    val day = parts[0]
                    val temp = parts[1]
                    val condition = parts[2]
                    Row(
                        modifier = Modifier.fillMaxWidth(),
                        horizontalArrangement = Arrangement.SpaceBetween
                    ) {
                        Text(text = day, fontWeight = FontWeight.Medium)
                        Row {
                            Text(text = condition)
                            Spacer(modifier = Modifier.width(8.dp))
                            Text(text = temp)
                        }
                    }
                }
            }
        }
    }
}

感兴趣的读者可以直接Copy上面的代码在 AndroidStudio 里运行,最后的效果类似下面:

在这里插入图片描述

七、 总结

本篇内容覆盖了 Compose 日常开发中最核心的几类组件:布局容器(Column/Row/Box)基础组件(Text/Image/Button)列表(LazyColumn)页面骨架(Scaffold)

掌握了这些组件后足以支撑起一个简单但完整APP的UI开发,如待办事项APP、天气APP、新闻APP等。

🚨 最后提醒,本文示例使用的为 Material Design 3

八、参考资料

内容概要:本文介绍了基于噪声抑制半监督学习的锂离子电池SOH(State of Health,健康状态)估计方法的Python代码实现。该方法融合半监督学习框架与先进的噪声抑制机制,旨在利用少量标注样本和大量未标注数据,有效提升电池健康状态预测的精度与模型鲁棒性,特别适用于实际工程中电池老化数据标注成本高、样本稀缺的挑战性场景。通过设计高效的特征提取网络与可靠的伪标签生成及优化策略,模型能够有效识别并抑制训练过程中的噪声干扰,增强在复杂工况和数据波动下的泛化能力与稳定性。; 适合人群:具备一定机器学习理论基础和Python编程能力,从事电池管理系统(BMS)、新能源汽车、储能系统等领域的科研人员、工程师,以及专注于电池寿命预测、设备状态监测与智能运维等方向的硕博研究生;; 使用场景及目标:①解决锂离子电池SOH估计中标注数据获取困难、成本高昂的核心痛点;②提升模型在存在测量误差、传感器漂移或异常数据等噪声环境下的预测准确性与可靠性;③为相关科研课题提供可复现、可扩展的算法基准与开源代码框架,加速算法迭代与工程落地; 阅读建议:此资源以Python代码为核心载体,强调算法的完整复现与实验验证过程,建议读者结合代码逐模块剖析模型架构、损失函数设计与训练流程细节,并积极在自有电池数据集上进行迁移学习、参数调优与性能对比,以深入掌握半监督学习与噪声抑制技术在电池退化建模中的关键应用。
内容概要:本文系统阐述了高速串行信号在传输过程中因信道损耗导致的眼图闭合问题,并介绍了主流的均衡技术解决方案。信道作为低通滤波器,会显著衰减高频分量,造成码间干扰(ISI),尤其在速率高于1GHz时更为严重。为恢复信号质量,发送端采用FFE(前馈均衡器)实施预加重或去加重,提前补偿高频损耗;接收端则结合CTLE与DFE进行二次均衡:CTLE通过模拟高通滤波器“削峰填谷”提升高频响应,而DFE利用反馈机制消除后向码间干扰,提高判决准确性。文章详细解析了各均衡模块的工作原理、电路结构、关键参数及其频率响应特性,并通过PCIe 3.0实例展示均衡前后眼图的改善效果,最后对比了不同技术的适用场景与优缺点。; 适合人群:从事高速电路设计、信号完整性分析等相关领域的工程师和技术人员,以及具备一定通信原理和电子工程基础的研发人员; 使用场景及目标:①理解高速信号传输中的损耗机理与眼图退化成因;②掌握FFE、CTLE、DFE等均衡技术的设计原理与应用场景;③为高速接口(如PCIe、USB等)的信号完整性优化提供理论支持与实践指导; 阅读建议:建议结合仿真工具观察不同均衡参数对眼图的影响,深入理解抽头系数、零极点配置等关键参数的调节逻辑,并关注实际硬件实现中的功耗与噪声权衡问题。
内容概要:本文详细介绍了基于光伏逆变器调节的中低压配电网电压分层协调控制策略的Matlab代码实现方法,旨在应对高渗透率光伏发电接入导致的配电网电压越限问题。该策略构建了分层控制架构,上层采用集中式优化算法进行全局决策,下层则依赖本地测量信息实现快速动态响应,从而实现对多个分布式光伏逆变器的协同调控。文中系统阐述了控制模型的数学建模过程、优化求解算法的设计流程以及仿真验证方案,并基于标准测试系统开展了仿真实验,结果表明该方法在抑制电压波动、提升电压稳定性、降低网络损耗方面具有显著优势,具备良好的工程应用前景。; 适合人群:具备电力系统分析、自动控制理论及新能源并网技术等相关专业知识背景,熟悉Matlab/Simulink仿真平台,从事相关领域科研工作的高校研究生、科研院所研究人员及电力行业工程技术开发人员。; 使用场景及目标:①深入研究高比例分布式光伏接入背景下中低压配电网的电压控制难题;②掌握分层协调控制体系的设计理念与实现机制;③学习并实践基于Matlab的电力系统建模、优化算法编程与仿真分析技术;④为实际配电网电压调控项目提供可复现、可拓展的技术参考与解决方案支撑。; 阅读建议:建议读者结合所提供的Matlab代码与典型配电系统模型开展仿真实践,重点剖析控制架构的层级划分逻辑、通信机制设计以及优化目标函数的构建方法,同时可尝试将其拓展至多时间尺度协调控制、考虑通信延迟与数据丢包等更贴近实际的复杂应用场景中进行深入研究。
源码下载地址: https://pan.quark.cn/s/2e09cbca2d82 【针对青龙面板wxpusher推送问题的修复包】是一个为青龙面板(QL Panel)设计的更新或改进版本,其目的是纠正与wxpusher相关的推送故障。青龙面板是一个被广泛应用的自动化部署及管理解决方案,它赋予用户在图形化环境中执行多种IT运维操作的能力,涵盖脚本操作、周期性任务执行以及文件处理等。wxpusher作为青龙面板的一个附加组件,承担着实现微信消息推送的任务,用以保障用户可以即时获取系统关键状态变动或异常警报。 sendNotify.js 是此修复包内含的关键模块,属于wxpusher插件的一部分,其核心职责是发送各类通知。在JavaScript编程语言中,该脚本或许内含了处理推送流程、调用微信推送端点以及消息内容的格式化和校验等操作。一旦青龙面板监测到新的事件状况,例如任务成功完成、发生错误或系统进入维护阶段,sendNotify.js便会被激活,将相关数据传送至用户的微信账户。 ql.js 另一个重要的构成部分,可能代表了青龙面板的核心代码库或专用于wxpusher的设定文档。它或许包含了整合wxpusher的相关参数,例如启动过程、授权核实、故障应对和日志管理等功能。ql.js与sendNotify.js协同工作,确保wxpusher能够顺利与青龙面板进行数据交互,并可靠地向用户传递通知信息。 CK_WxPusherUid.json 这一文档很可能是储存用户信息或配置参数的JSON格式文件。"CK"通常指代Cookie或某种缓存机制,而"WxPusherUid"可能意指wxpusher用户的专属识别码。该文件用于保存用户微信推送服务的连接详情,让青龙面板可以...
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值