166.[HarmonyOS NEXT 实战案例四:Grid] 可滚动网格布局基础篇
[HarmonyOS NEXT 实战案例四:Grid] 可滚动网格布局基础篇
项目已开源,开源地址: https://gitcode.com/nutpi/HarmonyosNextCaseStudyTutorial , 欢迎fork & star
效果演示
1. 引言
在移动应用开发中,网格布局是一种常见且实用的UI布局方式,特别适合展示图片、卡片等内容。当网格内容较多时,需要结合滚动功能,让用户能够流畅地浏览所有内容。本教程将详细讲解HarmonyOS NEXT中可滚动网格布局的实现方法,通过一个应用商店首页的案例,帮助开发者掌握Grid组件与Scroller的结合使用技巧。
2. 可滚动网格布局概述
2.1 什么是可滚动网格布局?
可滚动网格布局是指使用Grid组件作为容器,并通过Scroller控制器实现内容滚动的布局方式。当网格内容超出屏幕显示范围时,用户可以通过滑动操作查看更多内容。这种布局方式特别适合展示大量同类型但又各自独立的内容,如应用列表、商品展示、图片库等。
2.2 Grid与Scroller的关系
在HarmonyOS NEXT中,Grid是网格容器组件,用于创建网格布局;而Scroller是滚动控制器,可以绑定到Grid等容器组件上,控制其滚动行为。两者结合使用,可以实现内容丰富、交互流畅的可滚动网格界面。
组件/控制器 | 作用 | 主要特性 |
---|---|---|
Grid | 网格容器组件 | 行列布局、间距控制、模板定义 |
GridItem | 网格子项组件 | 内容展示、事件处理、样式定义 |
Scroller | 滚动控制器 | 滚动控制、事件监听、滚动位置管理 |
3. 案例分析:应用商店首页
本教程以一个应用商店首页为例,展示如何实现可滚动网格布局。该页面包含顶部搜索栏、应用分类标签、推荐应用网格列表和底部导航栏。
3.1 页面结构概览
Column
├── 顶部搜索栏 (Row)
├── 应用分类标签 (Row + ForEach)
├── 推荐应用标题 (Row)
├── 推荐应用网格 (Grid + ForEach + GridItem)
└── 底部导航栏 (Row)
3.2 数据模型定义
在实现可滚动网格布局之前,首先需要定义数据模型,用于存储和管理网格中显示的内容。在本案例中,我们定义了两个接口:Category(应用分类)和FeaturedApp(推荐应用)。
interface Category {
id: number,
name: string,
icon: Resource,
color: string
}
interface FeaturedApp {
id: number,
name: string,
developer: string,
icon: Resource,
rating: number,
downloads: string,
size: string,
category: string,
isFree: boolean,
screenshots: Resource[]
}
这两个接口定义了应用分类和推荐应用的数据结构,包含了展示所需的各种属性。在组件中,我们使用@State装饰器定义了categories和featuredApps两个状态变量,用于存储实际数据。
4. 实现可滚动网格布局
4.1 创建滚动控制器
首先,需要创建一个Scroller实例,用于控制Grid组件的滚动行为:
private scroller: Scroller = new Scroller()
4.2 构建网格容器
在build方法中,我们使用Grid组件创建网格容器,并将scroller绑定到Grid上:
Grid(this.scroller) {
// 网格内容
}
.columnsTemplate('1fr') // 单列布局
.rowsGap(16)
.width('100%')
.layoutWeight(1)
.padding({ left: 16, right: 16, bottom: 16 })
.backgroundColor('#F8F8F8')
.onScrollIndex((first: number) => {
console.log(`当前显示的第一个应用索引: ${first}`)
})
这里我们设置了Grid的列模板为'1fr'(单列布局),行间距为16,宽度为100%,并使用layoutWeight(1)使Grid占据剩余空间。同时,我们还设置了内边距和背景色,并添加了onScrollIndex事件监听,用于记录当前显示的第一个应用索引。
4.3 创建网格项
在Grid容器中,我们使用ForEach循环遍历featuredApps数组,为每个应用创建一个GridItem:
ForEach(this.featuredApps, (app:FeaturedApp) => {
GridItem() {
Column() {
// 应用图标和基本信息
Row() {
// 应用图标
Image(app.icon)
.width(60)
.height(60)
.borderRadius(12)
.shadow({
radius: 4,
color: 'rgba(0, 0, 0, 0.2)',
offsetX: 0,
offsetY: 2
})
// 应用信息
Column() {
// 应用名称
Text(app.name)
.fontSize(16)
.fontWeight(FontWeight.Bold)
.fontColor('#333333')
.maxLines(1)
.textOverflow({ overflow: TextOverflow.Ellipsis })
// 开发者
Text(app.developer)
.fontSize(12)
.fontColor('#666666')
.margin({ top: 2 })
// 星级评分
this.StarRating(app.rating)
// 下载量和大小
Row() {
Text(app.downloads)
.fontSize(10)
.fontColor('#999999')
Text('•')
.fontSize(10)
.fontColor('#999999')
.margin({ left: 4, right: 4 })
Text(app.size)
.fontSize(10)
.fontColor('#999999')
}
.margin({ top: 4 })
}
.alignItems(HorizontalAlign.Start)
.layoutWeight(1)
.margin({ left: 12 })
// 获取/购买按钮
Button(app.isFree ? '获取' : '购买')
.fontSize(14)
.fontColor('#FFFFFF')
.backgroundColor('#007AFF')
.borderRadius(16)
.width(60)
.height(32)
}
.width('100%')
.alignItems(VerticalAlign.Top)
// 应用截图
Row() {
ForEach(app.screenshots.slice(0, 3), (screenshot:Resource, index) => {
Image(screenshot)
.width(80)
.height(140)
.objectFit(ImageFit.Cover)
.borderRadius(8)
.margin({ right: index < 2 ? 8 : 0 })
})
}
.width('100%')
.margin({ top: 16 })
// 分类标签
Row() {
Text(app.category)
.fontSize(10)
.fontColor('#007AFF')
.backgroundColor('rgba(0, 122, 255, 0.1)')
.padding({ left: 8, right: 8, top: 4, bottom: 4 })
.borderRadius(8)
if (!app.isFree) {
Text('付费')
.fontSize(10)
.fontColor('#FF9500')
.backgroundColor('rgba(255, 149, 0, 0.1)')
.padding({ left: 8, right: 8, top: 4, bottom: 4 })
.borderRadius(8)
.margin({ left: 8 })
}
Blank()
}
.width('100%')
.margin({ top: 12 })
}
.width('100%')
.padding(16)
.backgroundColor('#FFFFFF')
.borderRadius(16)
.shadow({
radius: 8,
color: 'rgba(0, 0, 0, 0.1)',
offsetX: 0,
offsetY: 2
})
}
.onClick(() => {
console.log(`点击应用: ${app.name}`)
})
})
每个GridItem包含一个Column,用于垂直排列应用信息。在Column中,我们依次展示应用的图标和基本信息、应用截图和分类标签。同时,我们还为GridItem添加了点击事件处理。
4.4 自定义构建器:星级评分
为了复用星级评分的UI逻辑,我们创建了一个自定义构建器StarRating:
@Builder
StarRating(rating: number) {
Row() {
ForEach([1,2,3,4,5], (star:number) => {
Image(star <= rating ? $r('app.media.heart_filled') : $r('app.media.heart_outline'))
.width(12)
.height(12)
.fillColor(star <= rating ? '#FFD700' : '#E0E0E0')
})
Text(rating.toString())
.fontSize(12)
.fontColor('#666666')
.margin({ left: 4 })
}
}
这个构建器接收一个rating参数,根据评分值显示对应数量的星星,并在右侧显示具体评分数值。
5. Grid组件关键属性解析
5.1 列模板与行间距
.columnsTemplate('1fr') // 单列布局
.rowsGap(16) // 行间距
- columnsTemplate:定义网格的列模板,'1fr'表示单列布局,每列占据可用空间的一份。
- rowsGap:定义行与行之间的间距,单位为vp。
5.2 滚动事件监听
.onScrollIndex((first: number) => {
console.log(`当前显示的第一个应用索引: ${first}`)
})
- onScrollIndex:当网格滚动时触发,参数first表示当前显示的第一个网格项的索引。
6. 滚动控制器(Scroller)的使用
6.1 创建与绑定
private scroller: Scroller = new Scroller()
// 在build方法中绑定到Grid
Grid(this.scroller) {
// 网格内容
}
6.2 常用方法与属性
方法/属性 | 说明 | 示例 |
---|---|---|
scrollTo | 滚动到指定位置 | scroller.scrollTo({xOffset: 0, yOffset: 100}) |
scrollEdge | 滚动到边缘 | scroller.scrollEdge(Edge.Top) |
scrollPage | 按页滚动 | scroller.scrollPage({next: true}) |
currentOffset | 获取当前滚动偏移量 | let offset = scroller.currentOffset() |
7. 布局技巧与最佳实践
7.1 网格布局设计原则
- 内容优先:根据内容特性选择合适的网格布局方式。
- 一致性:保持网格项的视觉一致性,包括大小、间距、样式等。
- 响应式:考虑不同屏幕尺寸下的显示效果,适当调整列数和大小。
- 交互反馈:为网格项添加适当的点击反馈,提升用户体验。
7.2 性能优化技巧
- 懒加载:对于大量数据,可以结合onScrollIndex实现懒加载。
- 合理分页:避免一次加载过多数据,可以实现分页加载。
- 图片优化:使用合适大小的图片,避免加载过大的图片资源。
7.3 常见问题解决方案
问题 | 解决方案 |
---|---|
网格项大小不一致 | 使用固定的宽高比,或者在GridItem中设置minHeight |
滚动不流畅 | 减少网格项的复杂度,优化图片加载 |
网格项内容溢出 | 使用maxLines和textOverflow控制文本显示 |
8. 总结
在下一篇教程中,我们将深入探讨可滚动网格布局的进阶技巧,包括多列布局、动态调整列数、网格项动画效果等内容,敬请期待!
- 0回答
- 4粉丝
- 0关注
- 168.[HarmonyOS NEXT 实战案例四:Grid] 可滚动网格布局高级篇
- 167.[HarmonyOS NEXT 实战案例四:Grid] 可滚动网格布局进阶篇
- 160.[HarmonyOS NEXT 实战案例二:Grid] 照片相册网格布局:基础篇
- 172.[HarmonyOS NEXT 实战案例六:Grid] 响应式网格布局 - 基础篇
- 169.[HarmonyOS NEXT 实战案例五:Grid] 动态网格布局基础篇
- 178.[HarmonyOS NEXT 实战案例八:Grid] 瀑布流网格布局基础篇
- 184.[HarmonyOS NEXT 实战案例十:Grid] 仪表板网格布局基础篇
- [HarmonyOS NEXT 实战案例四] 天气应用网格布局(下)
- [HarmonyOS NEXT 实战案例四] 天气应用网格布局(上)
- 163.[HarmonyOS NEXT 实战案例三:Grid] 不规则网格布局基础篇:打造新闻应用首页
- 171.[HarmonyOS NEXT 实战案例五:Grid] 动态网格布局高级篇
- 162.[HarmonyOS NEXT 实战案例二:Grid] 照片相册网格布局:高级篇
- 174.[HarmonyOS NEXT 实战案例六:Grid] 响应式网格布局 - 高级篇
- 180.[HarmonyOS NEXT 实战案例八:Grid] 瀑布流网格布局高级篇
- 161. [HarmonyOS NEXT 实战案例二:Grid] 照片相册网格布局:进阶篇