HarmonyOS ArkTS实战:打造沉浸式“暗黑风”收藏列表
本文基于HarmonyOS NEXT的ArkTS开发范式,详细解析了一个暗黑风格收藏列表的实现过程。重点介绍了List组件的基础用法、Row与Column混合布局技巧、layoutWeight权重布局原理以及Image组件的圆角处理。文章特别指出代码中fontWeight属性的常见错误,建议使用FontWeight.Bold或700替代错误数值20。通过容器嵌套、空间分配和细节优化等技巧,展示了如
HarmonyOS ArkTS实战:打造沉浸式“暗黑风”收藏列表
摘要
本文基于HarmonyOS
NEXT的ArkTS声明式开发范式,深入解析一段高颜值的“暗黑风”收藏列表代码。我们将重点剖析List组件的基础用法、Row与Column的混合布局技巧、权重布局(layoutWeight)的自适应原理,以及Image组件的圆角处理。特别针对代码中出现的fontWeight属性进行纠错分析,帮助开发者避开常见误区。通过本文,你将学会如何构建一个结构清晰、适配全面且视觉精致的列表项。
完整效果
一、引言:从“写代码”到“做产品”
在前两篇教程中,我们学习了基础组件和样式。今天,我们要迈出一大步——构建一个完整的“功能模块”。
这段代码模拟了一个音乐或视频APP的“收藏列表”页面。它具备了现代移动应用的核心特征:
- 沉浸式设计:全屏黑色背景,白色文字,高对比度。
- 复杂列表项:图文混排,包含头像、标题、标签(SVIP)、操作按钮。
- 安全区域适配:使用了
expandSafeArea,确保在刘海屏或手势导航设备上内容不被遮挡。
这不仅仅是一段代码,更是一个标准的UI组件雏形。
二、代码全景与结构拆解
让我们先看代码的整体骨架。这是一个典型的“容器套容器”结构:
@Entry
@Component
struct Index {
build() {
Column() { // 【根容器】全屏黑色背景
Text('收藏列表') // 【顶部标题】
List() { // 【列表容器】
ListItem() { // 【列表项】
Row() { // 【列表项内部:水平布局】
// 左侧:图片
// 中间:文本与标签(Column)
// 右侧:更多按钮
}
}
}
}
// 【全局样式】背景、内边距、安全区域
}
}
三、核心知识点深度剖析
List与ListItem:列表的基石
代码中使用了List()和ListItem()组件。
- List:这是鸿蒙中用于展示滚动列表的核心容器。虽然本例中只写了一个
ListItem,但在实际开发中,通常会配合ForEach循环来渲染大量数据。 - ListItem:代表列表中的每一行。
- 注意:
ListItem必须直接作为List的子组件,不能隔着其他容器(如不能把ListItem包在Column里再放进List)。
- 注意:
混合布局:Row与Column的嵌套
这是UI开发中最常用的技巧。
- 外层Row:为了让“图片”、“内容”、“箭头”从左到右排列,我们使用了
Row。 - 内层Column:为了让“标题”和“标签行”从上到下排列,我们在
Row内部嵌套了一个Column。 - 布局口诀:横竖切换用嵌套,外横内竖最常见。
权重布局:layoutWeight(1)的奥义
代码中有一个非常关键的属性:
Column() {
// ...标题和标签...
}
.layoutWeight(1)
- 作用:
layoutWeight用于在Row容器中分配剩余空间。 - 原理:
- 图片(100宽)和箭头(24宽)是固定宽度。
- 中间的
Column设置了layoutWeight(1),意味着“占据Row中除了图片和箭头之外的所有剩余空间”。
- 为什么要这样做?:如果不加这个属性,中间的
Column宽度只会包裹住文字(wrap_content)。加上它之后,Column变宽了,内部的Text设置.width('100%')才能生效,从而撑满整个中间区域,保证点击热区或背景色的完整性。
图片圆角与资源引用
Image($r('app.media.pick1'))
.width(100)
.border({radius: 10})
$r引用:这是鸿蒙标准的资源引用方式,指向resources/base/media目录下的图片文件。border.radius:给方形的图片加上10vp的圆角,使其视觉上更柔和,这是现代UI设计的标配。
安全区域:expandSafeArea
代码末尾出现了:
.expandSafeArea([SafeAreaType.SYSTEM], [SafeAreaEdge.TOP, SafeAreaEdge.BOTTOM])
- 作用:这是鸿蒙开发中防止内容被系统UI(如刘海、底部手势条)遮挡的关键属性。
- 含义:告诉系统,“请把我的布局范围扩展到系统区域(如状态栏、导航栏),但我会自己处理好内边距,不要让内容被遮住”。
- 结合padding:代码中配合了
.padding({left: 20, right:10}),确保内容不会紧贴屏幕边缘。
四、易错点与代码纠错(重要!)
在代码审查中,我发现了一个明显的逻辑错误,这也是新手常犯的坑:
错误代码:
Text('鲸落万物生')
.fontWeight(20) // 错误!
问题分析:
fontWeight属性用于设置字体的粗细。- 合法值:通常是100, 200, 300… 到900。
- 400 = Normal(正常)
- 700 = Bold(加粗)
- 错误原因:代码中写了
20。这是一个极小的值,远低于标准范围。在大多数渲染引擎中,这会被忽略或回退到默认值(400)。 - 修正建议:如果你想让标题加粗,应该写
.fontWeight(FontWeight.Bold)或者.fontWeight(700)。
另一个潜在问题:List的用法
虽然代码能跑通,但List组件通常不建议只放一个静态的ListItem。如果这是静态页面,用Column性能会更好;如果是动态页面,应该这样写:
// 推荐写法
List({ space: 10 }) { // 设置列表项间距
ForEach(this.myDataList, (item) => {
ListItem() {
// ...内容...
}
}, item => item.id)
}
五、视觉优化与扩展建议
为了让这个列表更像商业级应用,我们可以做以下优化:
标签样式的优化
代码中的“SVIP”标签使用了border:
Text('SVIP')
.border({width: 1, color: Color.Yellow, radius: 12})
.padding({left: 5, right: 5, top: 3, bottom: 3})
- 点评:这是一个典型的“空心胶囊”样式。
- 优化:为了视觉更精致,可以添加
.fontSize(10)(限制字号)和.textAlign(TextAlign.Center)(确保文字在边框内居中)。
点击态反馈
列表项通常是可以点击的。建议给ListItem或最外层的Row添加点击事件和按压效果:
Row() {
// ...内容...
}
.onClick(() => {
// 跳转详情
})
.hoverEffect(true) // 开启鸿蒙默认的点击水波纹效果
暗黑模式的适配
目前代码强制使用了Color.Black和Color.White。在鸿蒙系统中,建议使用资源引用$r('app.color.bg_color'),这样当系统切换到“亮色模式”时,APP能自动变成白底黑字,提升用户体验。
六、总结
通过这段代码,我们不仅完成了一个漂亮的“收藏列表”界面,更重要的是掌握了以下核心技能:
- 容器嵌套:灵活运用Row和Column构建复杂结构。
- 空间分配:理解
layoutWeight如何让组件自动填满剩余空间。 - 细节打磨:使用
border.radius处理图片圆角,使用padding处理标签内边距。 - 避坑指南:纠正了
fontWeight的数值误区。
鸿蒙ArkTS的开发体验就像搭积木,只要理解了每一块积木(组件)的属性,你就能搭建出无限可能的界面。
完整代码
import text from '@ohos.graphics.text'
@Entry
@Component
struct Index {
build() {
Column() {
Text('收藏列表')
.fontColor(Color.White)
.width(360)
.margin({bottom: 10})
List() {
ListItem() {
Row() {
Image($r('app.media.pick1'))
.width(100)
.border({radius: 10})
.margin({right: 10})
Column() {
Text('鲸落万物生')
.fontColor(Color.White)
.width('100%')
.fontWeight(20)
.margin({bottom: 15})
Row() {
Text('SVIP')
.fontColor(Color.Yellow)
.border({width: 1,color: Color.Yellow, radius: 12})
.padding({left: 5,right: 5,top: 3,bottom: 3})
.margin({right: 10})
Text('小酌')
.fontColor(Color.White)
}
.width('100%')
}
.layoutWeight(1)
Image($r('app.media.more'))
.width(24)
}
.width('100%')
.height(80)
.margin({bottom: 10})
}
}
}
.width('100%')
.height('100%')
.backgroundColor(Color.Black)
.padding({left: 20, right:10})
.expandSafeArea([SafeAreaType.SYSTEM], [SafeAreaEdge.TOP,SafeAreaEdge.BOTTOM])
}
}
更多推荐
所有评论(0)