
💫 坚果派·红目香薰 倾情分享 🎯 用心打造每一个技术细节,为开发者创造更多价值 📱 让HarmonyOS开发变得更简单、更有趣
嗨,亲爱的技术朋友们!👋
我是来自坚果派的红目香薰,一个热爱技术、专注HarmonyOS开发的程序媛。在这个数字化飞速发展的时代,HarmonyOS作为华为自主研发的操作系统,正在改变着我们的数字生活体验。
🌈 为什么要写这个系列?
每一个Demo都是我精心设计和反复测试的结果,希望能够为你的HarmonyOS开发之路点亮一盏明灯。✨
今天我们来深入学习HarmonyOS中最实用的布局组件之一——Grid网格组件。从基础网格到复杂的瀑布流布局,让我们一起打造整齐美观的网格界面!

本Demo展示了HarmonyOS中Grid组件的全面使用方法,包括:
界面采用多样化的网格展示:
GridDemo/
├── src/
│ ├── main/
│ │ ├── ets/
│ │ │ ├── pages/
│ │ │ │ └── Index.ets // 主页面
│ │ │ └── entryability/
│ │ └── resources/
│ │ ├── base/
│ │ │ ├── element/
│ │ │ └── media/
│ │ └── rawfile/
│ └── module.json5Grid() {
ForEach(this.dataList, (item: DataItem) => {
GridItem() {
// 网格项内容
}
})
}
.columnsTemplate('1fr 1fr 1fr')
.rowsTemplate('1fr 1fr')
.columnsGap(10)
.rowsGap(10)Grid() {
// 网格内容
}
.columnsTemplate('repeat(auto-fit, minmax(150px, 1fr))')
.width('100%')
.height('100%')性能优化策略: 使用LazyForEach和虚拟滚动机制,确保大量数据时的流畅性。
响应式设计: 通过columnsTemplate的auto-fit和minmax实现自适应布局。
瀑布流实现: 结合不同高度的GridItem实现瀑布流效果。
// 数据模型接口
interface GridItemData {
id: number
title: string
subtitle?: string
icon: string
color: string
type?: string
}
interface ProductItemData {
id: number
name: string
price: number
image: string
rating: number
sales: number
}
interface PhotoItemData {
id: number
url: string
width: number
height: number
title: string
}
@Entry
@Component
struct Index {
@State selectedTab: number = 0
@State gridItems: GridItemData[] = []
@State products: ProductItemData[] = []
@State photos: PhotoItemData[] = []
// 功能网格数据
private functionItems: GridItemData[] = [
{ id: 1, title: '扫一扫', icon: '📷', color: '#FF6B6B', type: 'scan' },
{ id: 2, title: '付款码', icon: '💳', color: '#4ECDC4', type: 'pay' },
{ id: 3, title: '收款', icon: '💰', color: '#45B7D1', type: 'receive' },
{ id: 4, title: '转账', icon: '💸', color: '#96CEB4', type: 'transfer' },
{ id: 5, title: '充值', icon: '🔋', color: '#FFEAA7', type: 'recharge' },
{ id: 6, title: '理财', icon: '📈', color: '#DDA0DD', type: 'finance' },
{ id: 7, title: '保险', icon: '🛡️', color: '#98D8C8', type: 'insurance' },
{ id: 8, title: '更多', icon: '⋯', color: '#F7DC6F', type: 'more' }
]
// 商品数据
private productItems: ProductItemData[] = [
{ id: 1, name: '华为Mate60 Pro', price: 6999, image: '📱', rating: 4.9, sales: 1234 },
{ id: 2, name: 'MacBook Pro', price: 12999, image: '💻', rating: 4.8, sales: 567 },
{ id: 3, name: 'AirPods Pro', price: 1999, image: '🎧', rating: 4.7, sales: 890 },
{ id: 4, name: 'iPad Air', price: 4399, image: '📱', rating: 4.6, sales: 456 },
{ id: 5, name: 'Apple Watch', price: 2999, image: '⌚', rating: 4.8, sales: 678 },
{ id: 6, name: '小米电视', price: 3999, image: '📺', rating: 4.5, sales: 234 },
{ id: 7, name: '戴森吹风机', price: 2990, image: '💨', rating: 4.9, sales: 345 },
{ id: 8, name: '任天堂Switch', price: 2099, image: '🎮', rating: 4.7, sales: 567 }
]
// 照片数据
private photoItems: PhotoItemData[] = [
{ id: 1, url: '🌅', width: 200, height: 150, title: '日出' },
{ id: 2, url: '🌊', width: 200, height: 200, title: '海浪' },
{ id: 3, url: '🏔️', width: 200, height: 180, title: '雪山' },
{ id: 4, url: '🌸', width: 200, height: 160, title: '樱花' },
{ id: 5, url: '🌙', width: 200, height: 220, title: '月夜' },
{ id: 6, url: '🌈', width: 200, height: 140, title: '彩虹' },
{ id: 7, url: '⭐', width: 200, height: 190, title: '星空' },
{ id: 8, url: '🌺', width: 200, height: 170, title: '花朵' }
]
aboutToAppear() {
this.gridItems = [...this.functionItems]
this.products = [...this.productItems]
this.photos = [...this.photoItems]
}
build() {
Column() {
// 标题区域
this.buildTitleSection()
// 标签页
this.buildTabSection()
// 内容区域
if (this.selectedTab === 0) {
this.buildBasicGrid()
} else if (this.selectedTab === 1) {
this.buildProductGrid()
} else if (this.selectedTab === 2) {
this.buildPhotoGrid()
} else {
this.buildCustomGrid()
}
}
.width('100%')
.height('100%')
.backgroundColor('#F5F5F5')
}
// 标题区域
@Builder
buildTitleSection() {
Column({ space: 10 }) {
Text('🔲 HarmonyOS Grid网格组件')
.fontSize(24)
.fontWeight(FontWeight.Bold)
.fontColor(Color.White)
.textAlign(TextAlign.Center)
.width('100%')
.padding(20)
.borderRadius(15)
.linearGradient({
angle: 45,
colors: [['#667eea', 0.0], ['#764ba2', 1.0]]
})
.shadow({
radius: 10,
color: '#40000000',
offsetX: 0,
offsetY: 5
})
Text('打造整齐美观的网格界面')
.fontSize(14)
.fontColor('#666666')
.textAlign(TextAlign.Center)
.fontStyle(FontStyle.Italic)
}
.width('100%')
.backgroundColor(Color.White)
.padding(20)
.borderRadius(12)
.margin({ bottom: 10 })
.shadow({
radius: 8,
color: '#20000000',
offsetX: 0,
offsetY: 2
})
}
// 标签页
@Builder
buildTabSection() {
Row({ space: 5 }) {
Button('功能网格')
.width(70)
.height(35)
.fontSize(12)
.backgroundColor(this.selectedTab === 0 ? '#3498DB' : '#ECF0F1')
.fontColor(this.selectedTab === 0 ? Color.White : '#7F8C8D')
.borderRadius(8)
.onClick(() => {
this.selectedTab = 0
})
Button('商品网格')
.width(70)
.height(35)
.fontSize(12)
.backgroundColor(this.selectedTab === 1 ? '#3498DB' : '#ECF0F1')
.fontColor(this.selectedTab === 1 ? Color.White : '#7F8C8D')
.borderRadius(8)
.onClick(() => {
this.selectedTab = 1
})
Button('照片网格')
.width(70)
.height(35)
.fontSize(12)
.backgroundColor(this.selectedTab === 2 ? '#3498DB' : '#ECF0F1')
.fontColor(this.selectedTab === 2 ? Color.White : '#7F8C8D')
.borderRadius(8)
.onClick(() => {
this.selectedTab = 2
})
Button('自定义')
.width(70)
.height(35)
.fontSize(12)
.backgroundColor(this.selectedTab === 3 ? '#3498DB' : '#ECF0F1')
.fontColor(this.selectedTab === 3 ? Color.White : '#7F8C8D')
.borderRadius(8)
.onClick(() => {
this.selectedTab = 3
})
}
.width('100%')
.justifyContent(FlexAlign.SpaceEvenly)
.padding({ left: 20, right: 20, bottom: 10 })
}
// 基础功能网格
@Builder
buildBasicGrid() {
Column({ space: 20 }) {
// 4列功能网格
Column({ space: 10 }) {
Text('⚡ 快捷功能')
.fontSize(18)
.fontWeight(FontWeight.Medium)
.fontColor('#333333')
Grid() {
ForEach(this.gridItems, (item: GridItemData) => {
GridItem() {
Column({ space: 8 }) {
Text(item.icon)
.fontSize(32)
.width(60)
.height(60)
.textAlign(TextAlign.Center)
.backgroundColor(item.color)
.borderRadius(30)
.fontColor(Color.White)
Text(item.title)
.fontSize(14)
.fontColor('#333333')
.fontWeight(FontWeight.Medium)
}
.width('100%')
.padding(15)
.backgroundColor(Color.White)
.borderRadius(12)
.shadow({
radius: 8,
color: '#20000000',
offsetX: 0,
offsetY: 2
})
}
.onClick(() => {
console.log(`点击了: ${item.title}`)
})
})
}
.columnsTemplate('1fr 1fr 1fr 1fr')
.rowsTemplate('1fr 1fr')
.columnsGap(15)
.rowsGap(15)
.width('100%')
.height(200)
}
.width('100%')
.backgroundColor('#F8F9FA')
.padding(20)
.borderRadius(12)
// 2列大卡片网格
Column({ space: 10 }) {
Text('📊 数据统计')
.fontSize(18)
.fontWeight(FontWeight.Medium)
.fontColor('#333333')
Grid() {
GridItem() {
Column({ space: 15 }) {
Row() {
Text('📈')
.fontSize(24)
Text('今日收入')
.fontSize(16)
.fontWeight(FontWeight.Medium)
.fontColor('#333333')
.layoutWeight(1)
}
.width('100%')
Text('¥12,345')
.fontSize(28)
.fontWeight(FontWeight.Bold)
.fontColor('#27AE60')
Text('较昨日 +15.6%')
.fontSize(12)
.fontColor('#27AE60')
}
.alignItems(HorizontalAlign.Start)
.width('100%')
.padding(20)
.backgroundColor(Color.White)
.borderRadius(12)
.shadow({
radius: 8,
color: '#20000000',
offsetX: 0,
offsetY: 2
})
}
GridItem() {
Column({ space: 15 }) {
Row() {
Text('👥')
.fontSize(24)
Text('新增用户')
.fontSize(16)
.fontWeight(FontWeight.Medium)
.fontColor('#333333')
.layoutWeight(1)
}
.width('100%')
Text('1,234')
.fontSize(28)
.fontWeight(FontWeight.Bold)
.fontColor('#3498DB')
Text('较昨日 +8.2%')
.fontSize(12)
.fontColor('#3498DB')
}
.alignItems(HorizontalAlign.Start)
.width('100%')
.padding(20)
.backgroundColor(Color.White)
.borderRadius(12)
.shadow({
radius: 8,
color: '#20000000',
offsetX: 0,
offsetY: 2
})
}
GridItem() {
Column({ space: 15 }) {
Row() {
Text('📦')
.fontSize(24)
Text('订单数量')
.fontSize(16)
.fontWeight(FontWeight.Medium)
.fontColor('#333333')
.layoutWeight(1)
}
.width('100%')
Text('567')
.fontSize(28)
.fontWeight(FontWeight.Bold)
.fontColor('#E67E22')
Text('较昨日 +12.3%')
.fontSize(12)
.fontColor('#E67E22')
}
.alignItems(HorizontalAlign.Start)
.width('100%')
.padding(20)
.backgroundColor(Color.White)
.borderRadius(12)
.shadow({
radius: 8,
color: '#20000000',
offsetX: 0,
offsetY: 2
})
}
GridItem() {
Column({ space: 15 }) {
Row() {
Text('⭐')
.fontSize(24)
Text('用户评分')
.fontSize(16)
.fontWeight(FontWeight.Medium)
.fontColor('#333333')
.layoutWeight(1)
}
.width('100%')
Text('4.8')
.fontSize(28)
.fontWeight(FontWeight.Bold)
.fontColor('#9B59B6')
Text('共 2,345 条评价')
.fontSize(12)
.fontColor('#9B59B6')
}
.alignItems(HorizontalAlign.Start)
.width('100%')
.padding(20)
.backgroundColor(Color.White)
.borderRadius(12)
.shadow({
radius: 8,
color: '#20000000',
offsetX: 0,
offsetY: 2
})
}
}
.columnsTemplate('1fr 1fr')
.rowsTemplate('1fr 1fr')
.columnsGap(15)
.rowsGap(15)
.width('100%')
.height(200)
}
.width('100%')
.backgroundColor('#F8F9FA')
.padding(20)
.borderRadius(12)
}
.layoutWeight(1)
.padding({ left: 20, right: 20 })
}
// 商品网格
@Builder
buildProductGrid() {
Column({ space: 15 }) {
Text('🛍️ 热门商品')
.fontSize(18)
.fontWeight(FontWeight.Medium)
.fontColor('#333333')
.alignSelf(ItemAlign.Start)
.margin({ left: 20 })
Grid() {
ForEach(this.products, (product: ProductItemData) => {
GridItem() {
Column({ space: 12 }) {
// 商品图片
Text(product.image)
.fontSize(48)
.width('100%')
.height(120)
.textAlign(TextAlign.Center)
.backgroundColor('#F5F5F5')
.borderRadius(8)
// 商品信息
Column({ space: 6 }) {
Text(product.name)
.fontSize(14)
.fontWeight(FontWeight.Medium)
.fontColor('#333333')
.maxLines(2)
.textOverflow({ overflow: TextOverflow.Ellipsis })
Row({ space: 5 }) {
Text('⭐')
.fontSize(12)
Text(product.rating.toString())
.fontSize(12)
.fontColor('#FF9800')
Text(`(${product.sales})`)
.fontSize(12)
.fontColor('#999999')
}
.width('100%')
Text(`¥${product.price}`)
.fontSize(16)
.fontWeight(FontWeight.Bold)
.fontColor('#E74C3C')
}
.alignItems(HorizontalAlign.Start)
.width('100%')
}
.width('100%')
.padding(12)
.backgroundColor(Color.White)
.borderRadius(12)
.shadow({
radius: 8,
color: '#20000000',
offsetX: 0,
offsetY: 2
})
}
.onClick(() => {
console.log(`查看商品: ${product.name}`)
})
})
}
.columnsTemplate('1fr 1fr')
.columnsGap(15)
.rowsGap(15)
.width('100%')
.layoutWeight(1)
.padding({ left: 20, right: 20 })
}
.layoutWeight(1)
}
// 照片网格(瀑布流)
@Builder
buildPhotoGrid() {
Column({ space: 15 }) {
Text('📸 精美相册')
.fontSize(18)
.fontWeight(FontWeight.Medium)
.fontColor('#333333')
.alignSelf(ItemAlign.Start)
.margin({ left: 20 })
Grid() {
ForEach(this.photos, (photo: PhotoItemData) => {
GridItem() {
Column({ space: 8 }) {
// 照片
Text(photo.url)
.fontSize(40)
.width('100%')
.height(photo.height)
.textAlign(TextAlign.Center)
.backgroundColor('#F0F0F0')
.borderRadius(8)
// 照片标题
Text(photo.title)
.fontSize(14)
.fontColor('#333333')
.fontWeight(FontWeight.Medium)
.textAlign(TextAlign.Center)
}
.width('100%')
.padding(10)
.backgroundColor(Color.White)
.borderRadius(12)
.shadow({
radius: 5,
color: '#20000000',
offsetX: 0,
offsetY: 2
})
}
.onClick(() => {
console.log(`查看照片: ${photo.title}`)
})
})
}
.columnsTemplate('1fr 1fr')
.columnsGap(10)
.rowsGap(10)
.width('100%')
.layoutWeight(1)
.padding({ left: 20, right: 20 })
}
.layoutWeight(1)
}
// 自定义网格
@Builder
buildCustomGrid() {
Column({ space: 20 }) {
// 不规则网格
Column({ space: 10 }) {
Text('🎨 创意布局')
.fontSize(18)
.fontWeight(FontWeight.Medium)
.fontColor('#333333')
Grid() {
// 大卡片 - 占2x2
GridItem() {
Column({ space: 15 }) {
Text('🎯')
.fontSize(48)
Text('主要功能')
.fontSize(18)
.fontWeight(FontWeight.Bold)
.fontColor(Color.White)
Text('这是一个重要的功能区域')
.fontSize(14)
.fontColor('#E0E0E0')
.textAlign(TextAlign.Center)
}
.width('100%')
.height('100%')
.padding(20)
.backgroundColor('#667eea')
.borderRadius(15)
.shadow({
radius: 10,
color: '#30000000',
offsetX: 0,
offsetY: 5
})
}
.columnStart(0)
.columnEnd(1)
.rowStart(0)
.rowEnd(1)
// 小卡片1
GridItem() {
Column({ space: 8 }) {
Text('📊')
.fontSize(24)
Text('统计')
.fontSize(14)
.fontWeight(FontWeight.Medium)
.fontColor('#333333')
}
.width('100%')
.height('100%')
.padding(15)
.backgroundColor('#4ECDC4')
.borderRadius(12)
}
.columnStart(2)
.columnEnd(2)
.rowStart(0)
.rowEnd(0)
// 小卡片2
GridItem() {
Column({ space: 8 }) {
Text('⚙️')
.fontSize(24)
Text('设置')
.fontSize(14)
.fontWeight(FontWeight.Medium)
.fontColor('#333333')
}
.width('100%')
.height('100%')
.padding(15)
.backgroundColor('#45B7D1')
.borderRadius(12)
}
.columnStart(2)
.columnEnd(2)
.rowStart(1)
.rowEnd(1)
// 横向卡片
GridItem() {
Row({ space: 15 }) {
Text('📈')
.fontSize(32)
Column({ space: 5 }) {
Text('数据分析')
.fontSize(16)
.fontWeight(FontWeight.Bold)
.fontColor('#333333')
Text('查看详细报表')
.fontSize(12)
.fontColor('#666666')
}
.alignItems(HorizontalAlign.Start)
.layoutWeight(1)
}
.width('100%')
.height('100%')
.padding(15)
.backgroundColor('#96CEB4')
.borderRadius(12)
}
.columnStart(0)
.columnEnd(2)
.rowStart(2)
.rowEnd(2)
}
.columnsTemplate('1fr 1fr 1fr')
.rowsTemplate('1fr 1fr 1fr')
.columnsGap(10)
.rowsGap(10)
.width('100%')
.height(300)
}
.width('100%')
.backgroundColor('#F8F9FA')
.padding(20)
.borderRadius(12)
// 动态网格
Column({ space: 10 }) {
Row() {
Text('🔄 动态网格')
.fontSize(18)
.fontWeight(FontWeight.Medium)
.fontColor('#333333')
.layoutWeight(1)
Button('➕ 添加')
.height(32)
.fontSize(12)
.backgroundColor('#27AE60')
.borderRadius(16)
.onClick(() => {
this.addGridItem()
})
}
.width('100%')
Grid() {
ForEach(this.gridItems, (item: GridItemData, index: number) => {
GridItem() {
Stack({ alignContent: Alignment.TopEnd }) {
Column({ space: 8 }) {
Text(item.icon)
.fontSize(24)
Text(item.title)
.fontSize(12)
.fontColor('#333333')
}
.width('100%')
.height(80)
.padding(10)
.backgroundColor(item.color)
.borderRadius(8)
// 删除按钮
Text('✕')
.fontSize(12)
.fontColor(Color.White)
.width(20)
.height(20)
.textAlign(TextAlign.Center)
.backgroundColor('#E74C3C')
.borderRadius(10)
.margin({ top: 5, right: 5 })
.onClick(() => {
this.removeGridItem(index)
})
}
}
})
}
.columnsTemplate('1fr 1fr 1fr')
.columnsGap(10)
.rowsGap(10)
.width('100%')
.height(200)
}
.width('100%')
.backgroundColor('#F8F9FA')
.padding(20)
.borderRadius(12)
}
.layoutWeight(1)
.padding({ left: 20, right: 20 })
}
// 添加网格项
addGridItem() {
const newItem: GridItemData = {
id: this.gridItems.length + 1,
title: `项目${this.gridItems.length + 1}`,
icon: ['🎯', '⭐', '🔥', '💎', '🚀'][Math.floor(Math.random() * 5)],
color: ['#FF6B6B', '#4ECDC4', '#45B7D1', '#96CEB4', '#FFEAA7'][Math.floor(Math.random() * 5)]
}
this.gridItems.push(newItem)
}
// 删除网格项
removeGridItem(index: number) {
this.gridItems.splice(index, 1)
}
}// module.json5 配置
{
"module": {
"name": "entry",
"type": "entry",
"description": "$string:module_desc",
"mainElement": "EntryAbility",
"deviceTypes": [
"phone",
"tablet"
],
"deliveryWithInstall": true,
"installationFree": false,
"pages": "$profile:main_pages",
"abilities": [
{
"name": "EntryAbility",
"srcEntry": "./ets/entryability/EntryAbility.ts",
"description": "$string:EntryAbility_desc",
"icon": "$media:icon",
"label": "$string:EntryAbility_label",
"startWindowIcon": "$media:icon",
"startWindowBackground": "$color:start_window_background"
}
]
}
}运行后的界面将展示:
通过这个Demo,我们学习了:
Grid组件作为现代移动应用中最重要的布局组件之一,掌握其各种用法对于创建整齐美观的界面至关重要。从简单的功能网格到复杂的瀑布流布局,每一个细节都体现着应用的专业性和用户体验。
希望这个示例能够帮助到正在学习HarmonyOS开发的你!下一期我们将探索更多有趣的UI组件,敬请期待!如果你有任何问题或建议,欢迎在评论区留言交流。
🌟 如果这篇文章对你有帮助,请点赞支持!🌟
让我们一起在HarmonyOS的世界里创造更多可能!
© 2025 坚果派·红目香薰 | 用心分享,用技术创造价值