项目已开源,开源地址: https://gitcode.com/nutpi/HarmonyosNextCaseStudyTutorial , 欢迎fork & star
效果演示
1. 引言
在上一部分中,我们介绍了垂直列表的基础结构、数据模型设计以及外层Column的实现。本教程将继续深入探讨列表项的内部结构,包括Row布局的实现、图片与文本的样式设置以及嵌套标签的实现方法,帮助开发者掌握更复杂的布局技巧,创建视觉层次分明、信息丰富的产品列表界面。
2. 列表项的Row布局实现
2.1 列表项的基本结构
Row({ space: 16 }) // 每个列表项内部用 Row 水平排列
{
// 左侧图片
Image(item.image)
.width(80)
.height(80)
.objectFit(ImageFit.Cover)
.borderRadius(4)
// 右侧内容区域(垂直排列)
Column({ space: 8 }) {
// 文本和标签内容
}
} .width('100%')
.height(120)
.padding(12)
.backgroundColor(0xFFFFFF)
.borderRadius(8)
.shadow({ radius: 2, color: 0x05000000 })
每个列表项使用Row组件实现水平布局,将产品图片和详细信息分别放置在左右两侧。
2.2 Row组件属性详解
属性/参数 | 值 | 作用 |
---|---|---|
space | 16 | 设置子组件之间的水平间距为16vp |
width | '100%' | 设置Row宽度占父容器的100% |
height | 120 | 设置Row高度为固定的120vp |
padding | 12 | 设置内边距为12vp,使内容与边框保持适当距离 |
backgroundColor | 0xFFFFFF | 设置背景色为白色 |
borderRadius | 8 | 设置边框圆角为8vp,使列表项更美观 |
shadow | 对象 | 添加阴影效果,提升列表项的立体感 |
2.3 阴影效果的实现
.shadow({ radius: 2, color: 0x05000000 })
阴影效果是卡片式设计中常用的视觉元素,可以增强界面的层次感和立体感。
参数 | 值 | 作用 |
---|---|---|
radius | 2 | 设置阴影的模糊半径为2vp,值越大阴影越模糊 |
color | 0x05000000 | 设置阴影颜色为黑色(000000)且透明度为5%(05) |
在设计阴影时,应遵循以下原则:
- 保持适度的模糊半径,避免过于锐利或过于模糊
- 使用低透明度的颜色,避免阴影过于明显
- 与卡片的圆角配合,创造自然的立体效果
3. 图片组件的实现
3.1 图片组件的基本结构
Image(item.image)
.width(80)
.height(80)
.objectFit(ImageFit.Cover)
.borderRadius(4)
3.2 图片组件属性详解
属性 | 值 | 作用 |
---|---|---|
构造参数 | item.image | 设置图片源,来自Product对象的image属性 |
width | 80 | 设置图片宽度为80vp |
height | 80 | 设置图片高度为80vp |
objectFit | ImageFit.Cover | 设置图片填充模式为覆盖,确保图片填满容器且不变形 |
borderRadius | 4 | 设置边框圆角为4vp,使图片边角更圆润 |
3.3 objectFit属性的重要性
objectFit
属性控制图片如何适应其容器的尺寸,在列表项中尤为重要:
ImageFit值 | 效果描述 | 适用场景 |
---|---|---|
Cover | 保持宽高比缩放图片,使图片完全覆盖容器,可能裁剪部分内容 | 产品列表、缩略图等需要统一尺寸的场景 |
Contain | 保持宽高比缩放图片,使图片完全显示在容器内,可能有空白区域 | 需要显示完整图片内容的场景 |
Fill | 拉伸图片填满容器,可能导致图片变形 | 背景图等不强调原始比例的场景 |
None | 保持图片原始大小,不进行缩放 | 需要显示原始图片的场景 |
ScaleDown | 保持宽高比,在None和Contain之间选择较小的一个 | 需要在保持原始大小和完全显示之间平衡的场景 |
在产品列表中,通常使用ImageFit.Cover
可以确保所有产品图片具有统一的视觉效果,无论原始图片的宽高比如何。
4. 右侧内容区域的Column布局
4.1 右侧Column的基本结构
Column({ space: 8 }) {
Text(item.title)
.fontSize(16)
.fontWeight(500)
.textOverflow({ overflow: TextOverflow.Ellipsis })
.maxLines(1)
Text(item.price)
.fontSize(14)
.fontColor(0xFF4D4F53)
// 水平排列的标签(嵌套 Row)
Row({ space: 4 }) {
// 标签内容
}
}
右侧内容区域使用Column组件垂直排列产品标题、价格和标签。
4.2 右侧Column属性详解
属性/参数 | 值 | 作用 |
---|---|---|
space | 8 | 设置子组件之间的垂直间距为8vp |
4.3 文本组件的实现
4.3.1 标题文本
Text(item.title)
.fontSize(16)
.fontWeight(500)
.textOverflow({ overflow: TextOverflow.Ellipsis })
.maxLines(1)
属性 | 值 | 作用 |
---|---|---|
构造参数 | item.title | 设置文本内容,来自Product对象的title属性 |
fontSize | 16 | 设置字体大小为16vp |
fontWeight | 500 | 设置字体粗细为中等偏粗 |
textOverflow | { overflow: TextOverflow.Ellipsis } | 设置文本溢出时显示省略号 |
maxLines | 1 | 限制最多显示1行文本,超出部分截断 |
4.3.2 价格文本
Text(item.price)
.fontSize(14)
.fontColor(0xFF4D4F53)
属性 | 值 | 作用 |
---|---|---|
构造参数 | item.price | 设置文本内容,来自Product对象的price属性 |
fontSize | 14 | 设置字体大小为14vp,小于标题 |
fontColor | 0xFF4D4F53 | 设置字体颜色为深灰色 |
5. 嵌套标签的Row布局
5.1 标签Row的基本结构
Row({ space: 4 }) {
Text('新品')
.fontSize(12)
.padding({ top: 2, bottom: 2, left: 8, right: 8 })
.backgroundColor(0xFFF0F0)
.borderRadius(10)
Text('热卖')
.fontSize(12)
.padding({ top: 2, bottom: 2, left: 8, right: 8 })
.backgroundColor(0xFFE5F5FF)
.borderRadius(10)
}
标签区域使用Row组件水平排列多个标签,每个标签使用Text组件实现。
5.2 标签Row属性详解
属性/参数 | 值 | 作用 |
---|---|---|
space | 4 | 设置子组件之间的水平间距为4vp |
5.3 标签Text组件的实现
Text('新品')
.fontSize(12)
.padding({ top: 2, bottom: 2, left: 8, right: 8 })
.backgroundColor(0xFFF0F0)
.borderRadius(10)
属性 | 值 | 作用 |
---|---|---|
构造参数 | '新品' | 设置标签文本内容 |
fontSize | 12 | 设置字体大小为12vp,小于价格文本 |
padding | { top: 2, bottom: 2, left: 8, right: 8 } | 设置内边距,使标签文本有适当的留白 |
backgroundColor | 0xFFF0F0 | 设置背景色为浅红色(新品标签) |
borderRadius | 10 | 设置边框圆角为10vp,使标签呈胶囊形状 |
5.4 标签颜色的视觉区分
在本案例中,我们使用不同的背景色来区分不同类型的标签:
标签类型 | 背景色 | 颜色描述 | 视觉效果 |
---|---|---|---|
新品 | 0xFFF0F0 | 浅红色 | 突出新上市的产品 |
热卖 | 0xFFE5F5FF | 浅蓝色 | 强调销售良好的产品 |
这种颜色编码方式可以帮助用户快速识别产品的特性,提升信息传达效率。
6. 完整代码分析
让我们回顾完整的ProductList组件代码:
interface Product { image: Resource |string, title: string, price: string }
@Component
export struct ProductList {
private products:Product[] = [
{ image: $r('app.media.phone'), title: '智能手表', price: '¥1299' },
{ image: $r('app.media.phone'), title: '无线耳机', price: '¥499' }
]
build() {
Column({ space: 20 }) // 外层 Column 控制列表垂直间距
{
ForEach(this.products, (item:Product) => {
Row({ space: 16 }) // 每个列表项内部用 Row 水平排列
{
// 左侧图片
Image(item.image)
.width(80)
.height(80)
.objectFit(ImageFit.Cover)
.borderRadius(4)
// 右侧内容区域(垂直排列)
Column({ space: 8 }) {
Text(item.title)
.fontSize(16)
.fontWeight(500)
.textOverflow({ overflow: TextOverflow.Ellipsis })
.maxLines(1)
Text(item.price)
.fontSize(14)
.fontColor(0xFF4D4F53)
// 水平排列的标签(嵌套 Row)
Row({ space: 4 }) {
Text('新品')
.fontSize(12)
.padding({ top: 2, bottom: 2, left: 8, right: 8 })
.backgroundColor(0xFFF0F0)
.borderRadius(10)
Text('热卖')
.fontSize(12)
.padding({ top: 2, bottom: 2, left: 8, right: 8 })
.backgroundColor(0xFFE5F5FF)
.borderRadius(10)
}
}
} .width('100%')
.height(120)
.padding(12)
.backgroundColor(0xFFFFFF)
.borderRadius(8)
.shadow({ radius: 2, color: 0x05000000 })
}, (item:Product) => item.title)
}.width('100%')
.padding(16)
}
}
6.1 代码结构分析
- 接口定义:定义Product接口,描述产品数据结构
- 组件定义:使用@Component装饰器定义ProductList自定义组件
- 数据初始化:初始化products数组,包含两个产品示例
布局结构:
- 外层Column:垂直排列所有列表项
- ForEach循环:遍历products数组,渲染每个产品
- 列表项Row:水平排列图片和内容
- 内容Column:垂直排列标题、价格和标签
- 标签Row:水平排列多个标签
6.2 布局嵌套层次
本案例展示了多层嵌套布局的实现方式:
- 第一层:外层Column(垂直列表)
- 第二层:列表项Row(水平排列)
- 第三层:右侧内容Column(垂直排列)
- 第四层:标签Row(水平排列)
这种多层嵌套的布局结构能够实现复杂的界面设计,但也需要注意控制嵌套深度,避免过度嵌套导致性能问题。
6.3 链式调用的优势
在代码中,我们大量使用了链式调用来设置组件属性:
Image(item.image)
.width(80)
.height(80)
.objectFit(ImageFit.Cover)
.borderRadius(4)
链式调用的优势包括:
- 代码简洁:避免重复写组件变量名
- 可读性强:属性设置清晰可见
- 易于修改:可以方便地添加或删除属性
7. 总结
通过本教程的两个部分,我们详细讲解了如何使用Column和Row组件的嵌套组合,创建一个垂直列表与水平操作栏相结合的复合布局
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。