
回复
项目已开源,开源地址: https://gitcode.com/nutpi/HarmonyosNextCaseStudyTutorial , 欢迎fork & star
在HarmonyOS NEXT的ArkUI框架中,Grid组件是一种强大的网格容器,它与GridItem子组件一起使用,可以创建灵活的网格布局。网格布局是由"行"和"列"分割的单元格组成,通过指定"项目"所在的单元格,可以实现各种各样的布局效果。
特性 | 描述 |
---|---|
自定义行列数 | 可以通过rowsTemplate和columnsTemplate属性设置网格的行数和列数 |
尺寸占比控制 | 可以控制每行每列的尺寸占比 |
子组件跨行列 | 可以设置子组件横跨几行或几列 |
布局方向 | 支持垂直和水平布局 |
间距控制 | 可以设置行间距和列间距 |
滚动能力 | 支持构建可滚动的网格布局 |
在本案例中,我们将使用Grid和GridItem组件创建一个电商应用的商品列表页面,展示Apple Store的产品。
我们的电商商品列表页面包含以下几个部分:
首先,我们定义商品数据模型:
interface Product {
id: number,
name: string,
price: number,
image: Resource,
discount?: number
}
然后,创建商品数据数组:
@State products:Product[] = [
{ id: 1, name: 'iPhone 15 Pro', price: 7999, image: $r('app.media.phone'), discount: 10 },
{ id: 2, name: 'MacBook Pro', price: 12999, image: $r('app.media.big15') },
{ id: 3, name: 'iPad Air', price: 4399, image: $r('app.media.big14'), discount: 5 },
// 更多商品...
]
// 顶部标题栏
Row() {
Text('Apple Store')
.fontSize(24)
.fontWeight(FontWeight.Bold)
.fontColor('#1D1D1F')
Blank()
Button() {
Image($r('app.media.search_icon'))
.width(24)
.height(24)
}
.width(40)
.height(40)
.borderRadius(20)
.backgroundColor('#F5F5F7')
Button() {
Image($r('app.media.cart_icon'))
.width(24)
.height(24)
}
.width(40)
.height(40)
.borderRadius(20)
.backgroundColor('#F5F5F7')
.margin({ left: 12 })
}
.width('100%')
.padding({ left: 20, right: 20, top: 10, bottom: 10 })
.backgroundColor('#FFFFFF')
// 分类标签
Row() {
Text('热门商品')
.fontSize(18)
.fontWeight(FontWeight.Medium)
.fontColor('#1D1D1F')
Blank()
Text('查看全部')
.fontSize(14)
.fontColor('#007AFF')
}
.width('100%')
.padding({ left: 20, right: 20, top: 16, bottom: 16 })
.backgroundColor('#FFFFFF')
Grid() {
// GridItem子项...
}
.columnsTemplate('1fr 1fr') // 两列布局
.columnsGap(16) // 列间距
.rowsGap(16) // 行间距
.width('100%')
.layoutWeight(1)
.padding({ left: 20, right: 20, bottom: 20 })
.backgroundColor('#F2F2F7')
在这个配置中:
columnsTemplate('1fr 1fr')
:设置两列布局,每列占比相等columnsGap(16)
:设置列间距为16vprowsGap(16)
:设置行间距为16vp我们使用ForEach循环遍历商品数据,为每个商品创建一个GridItem:
ForEach(this.products, (product:Product) => {
GridItem() {
Column() {
// 商品图片容器
Stack({ alignContent: Alignment.TopEnd }) {
Image(product.image)
.width('100%')
.height(120)
.objectFit(ImageFit.Contain)
.backgroundColor('#F8F8F8')
.borderRadius(12)
// 折扣标签
if (product.discount) {
Text(`-${product.discount}%`)
.fontSize(12)
.fontColor('#FFFFFF')
.backgroundColor('#FF3B30')
.padding({ left: 8, right: 8, top: 4, bottom: 4 })
.borderRadius(8)
.margin({ top: 8, right: 8 })
}
}
.width('100%')
.height(120)
// 商品信息
Column() {
Text(product.name)
.fontSize(14)
.fontWeight(FontWeight.Medium)
.fontColor('#1D1D1F')
.maxLines(2)
.textOverflow({ overflow: TextOverflow.Ellipsis })
.margin({ top: 12 })
Row() {
if (product.discount) {
Text(`¥${(product.price * (100 - product.discount) / 100).toFixed(0)}`)
.fontSize(16)
.fontWeight(FontWeight.Bold)
.fontColor('#FF3B30')
Text(`¥${product.price}`)
.fontSize(12)
.fontColor('#8E8E93')
.decoration({ type: TextDecorationType.LineThrough })
.margin({ left: 4 })
} else {
Text(`¥${product.price}`)
.fontSize(16)
.fontWeight(FontWeight.Bold)
.fontColor('#1D1D1F')
}
Blank()
Button() {
Image($r('app.media.add_icon'))
.width(16)
.height(16)
.fillColor('#FFFFFF')
}
.width(28)
.height(28)
.borderRadius(14)
.backgroundColor('#007AFF')
}
.width('100%')
.margin({ top: 8 })
}
.alignItems(HorizontalAlign.Start)
.width('100%')
}
.width('100%')
.padding(12)
.backgroundColor('#FFFFFF')
.borderRadius(16)
.shadow({
radius: 8,
color: 'rgba(0, 0, 0, 0.1)',
offsetX: 0,
offsetY: 2
})
}
.onClick(() => {
console.log(`点击了商品: ${product.name}`)
})
})
每个GridItem包含:
// 底部导航栏
Row() {
Column() {
Image($r('app.media.home_icon'))
.width(24)
.height(24)
.fillColor('#007AFF')
Text('首页')
.fontSize(12)
.fontColor('#007AFF')
.margin({ top: 4 })
}
.layoutWeight(1)
// 其他导航项...
}
.width('100%')
.height(60)
.backgroundColor('#FFFFFF')
.borderColor('#E5E5EA')
.borderWidth({ top: 1 })
属性 | 描述 | 示例 |
---|---|---|
columnsTemplate | 设置网格布局的列数和每列的尺寸占比 | '1fr 2fr' :两列布局,第二列是第一列的两倍宽 |
rowsTemplate | 设置网格布局的行数和每行的尺寸占比 | '1fr 1fr 1fr' :三行布局,每行高度相等 |
columnsGap | 设置列间距 | columnsGap(16) |
rowsGap | 设置行间距 | rowsGap(16) |
属性 | 描述 | 示例 |
---|---|---|
rowStart | 设置起始行号 | rowStart(1) |
rowEnd | 设置结束行号 | rowEnd(3) |
columnStart | 设置起始列号 | columnStart(2) |
columnEnd | 设置结束列号 | columnEnd(4) |
Grid() {
// 子项...
}
.layoutDirection(GridDirection.Row) // 水平方向布局
GridDirection枚举值:
GridDirection.Row
:水平方向布局(默认)GridDirection.Column
:垂直方向布局在不同屏幕尺寸下,可以动态调整列数:
// 根据屏幕宽度调整列数
let columns = '1fr 1fr';
if (screenWidth >= 600) {
columns = '1fr 1fr 1fr';
}
if (screenWidth >= 840) {
columns = '1fr 1fr 1fr 1fr';
}
Grid() {
// 子项...
}
.columnsTemplate(columns)
适当的网格间距可以提升用户体验:
在本教程中,我们学习了如何使用HarmonyOS NEXT的Grid和GridItem组件创建一个电商商品列表页面。我们详细讲解了Grid组件的基本概念、主要属性和使用方法,以及如何通过合理的布局和样式设计,打造美观实用的商品卡片。