鸿蒙原生ArkTS布局方式之Grid+scrollBar滚动条布局深度解析
项目演示


一、引言
在移动应用开发中,网格布局(Grid Layout)是一种非常常见的布局方式,广泛应用于图片画廊、商品列表、数据展示等场景。随着用户对应用体验要求的不断提高,滚动条的样式和交互也成为影响用户体验的重要因素。
HarmonyOS NEXT作为华为新一代智能终端操作系统,提供了丰富的UI组件和布局能力。其中,Grid组件和scrollBar相关属性的组合使用,为开发者提供了强大的网格滚动布局解决方案。
本文将深入探讨鸿蒙原生ArkTS布局方式之Grid+scrollBar滚动条布局,从概念介绍、API详解、代码实现到性能优化,全面解析这一核心技术。
二、Grid组件概述
2.1 Grid组件定义与作用
Grid组件是HarmonyOS ArkUI框架中用于实现网格布局的核心容器组件。它将子组件按照行列的方式排列,形成规则的网格结构。
Grid组件的主要特点:
- 规则排列:子组件按照行列规则排列,形成整齐的网格结构
- 灵活配置:支持自定义列数、行数、间距等属性
- 自动滚动:当内容超出容器范围时,自动支持滚动功能
- 响应式布局:支持根据屏幕尺寸动态调整列数和布局
Grid组件的应用场景:
- 图片画廊:如相册应用中的照片网格展示
- 商品列表:电商应用中的商品网格展示
- 数据表格:数据密集型应用中的数据展示
- 仪表盘:智能家居控制面板的布局
2.2 Grid组件核心属性
2.2.1 列配置属性
columnsTemplate
用于定义网格的列模板,决定网格的列数和每列的宽度分配方式。
Grid() {
// GridItem子组件
}
.columnsTemplate('1fr 1fr 1fr') // 3列等宽分布
columnsGap
用于设置列与列之间的间距。
Grid() {
// GridItem子组件
}
.columnsGap(10) // 列间距10vp
2.2.2 行配置属性
rowsGap
用于设置行与行之间的间距。
Grid() {
// GridItem子组件
}
.rowsGap(10) // 行间距10vp
rowHeight
用于设置每行的高度。
Grid() {
// GridItem子组件
}
.rowHeight(100) // 每行高度100vp
2.2.3 尺寸与滚动属性
width
设置Grid容器的宽度。
Grid() {
// GridItem子组件
}
.width('100%') // 宽度占满父容器
height
设置Grid容器的高度,这是触发滚动的关键属性。
Grid() {
// GridItem子组件
}
.height(500) // 固定高度500vp,超出部分可滚动
重要提示:Grid组件只有设置了固定高度(如500vp)或百分比高度,并且内容高度超过容器高度时,才会触发滚动效果。如果不设置高度,Grid会自适应内容高度,不会产生滚动。
2.3 GridItem组件
GridItem是Grid组件的子组件,用于表示网格中的每个单元格。
Grid() {
GridItem() {
// 单元格内容
Column() {
Text('网格项')
.fontSize(16);
}
}
.height(100) // 设置单元格高度
.backgroundColor('#e3f2fd') // 设置背景色
}
三、scrollBar滚动条属性详解
3.1 scrollBar属性概述
scrollBar属性是滚动组件(包括Grid、List、Scroll、WaterFlow)的通用属性,用于控制滚动条的显示状态。
API Level支持: 从API version 8开始支持
属性类型: BarState枚举
BarState枚举值:
| 枚举值 | 说明 |
|---|---|
| BarState.Auto | 滚动条自动显示/隐藏(滚动时显示,停止时隐藏) |
| BarState.On | 始终显示滚动条 |
| BarState.Off | 始终隐藏滚动条 |
3.2 scrollBar属性使用方式
Grid() {
// GridItem子组件
}
.height(500)
.scrollBar(BarState.Auto) // 滚动时显示,停止时隐藏
3.3 scrollBarWidth属性
用于设置滚动条的宽度。
API Level支持: 从API version 11开始支持
Grid() {
// GridItem子组件
}
.height(500)
.scrollBar(BarState.Auto)
.scrollBarWidth(8) // 滚动条宽度8vp
3.4 scrollBarColor属性
用于设置滚动条滑块的颜色。
API Level支持: 从API version 11开始支持
Grid() {
// GridItem子组件
}
.height(500)
.scrollBar(BarState.Auto)
.scrollBarColor('#2196f3') // 滚动条颜色为蓝色
3.5 scrollBarMargin属性
用于设置滚动条与组件边缘的距离。
API Level支持: 从API version 20开始支持
Grid() {
// GridItem子组件
}
.height(500)
.scrollBar(BarState.Auto)
.scrollBarMargin({ top: 10, bottom: 10 }) // 上下边距各10vp
3.6 滚动事件
Grid组件支持多种滚动事件,用于监听滚动状态变化。
3.6.1 onScrollStart
滚动开始时触发。
API Level支持: 从API version 11开始支持
Grid() {
// GridItem子组件
}
.height(500)
.onScrollStart(() => {
console.info('滚动开始');
})
3.6.2 onScrollStop
滚动停止时触发。
API Level支持: 从API version 11开始支持
Grid() {
// GridItem子组件
}
.height(500)
.onScrollStop(() => {
console.info('滚动停止');
})
3.6.3 onReachStart
滚动到起始位置时触发。
API Level支持: 从API version 11开始支持
Grid() {
// GridItem子组件
}
.height(500)
.onReachStart(() => {
console.info('已滚动到顶部');
})
3.6.4 onReachEnd
滚动到末尾位置时触发。
API Level支持: 从API version 11开始支持
Grid() {
// GridItem子组件
}
.height(500)
.onReachEnd(() => {
console.info('已滚动到底部');
})
3.6.5 onDidScroll
滚动过程中触发,返回当前滚动偏移量。
API Level支持: 从API version 12开始支持
Grid() {
// GridItem子组件
}
.height(500)
.onDidScroll((scrollOffset: number, scrollState: ScrollState) => {
console.info(`当前滚动偏移量: ${scrollOffset}`);
console.info(`滚动状态: ${scrollState}`);
})
四、Grid+scrollBar布局完整实现示例
4.1 示例场景描述
本示例实现一个大型网格滚动显示场景,包含以下功能:
- 展示100个网格项的4列网格布局
- 支持滚动条显示状态切换(Auto/On/Off)
- 支持滚动条颜色切换
- 展示滚动条宽度自定义效果
4.2 完整代码实现
/**
* @Entry 装饰器标记这是一个应用的入口页面
* @Component 装饰器标记这是一个自定义组件
*
* 本示例展示鸿蒙原生ArkTS布局方式之Grid + scrollBar滚动条布局
* 场景:大型网格滚动显示
* 核心技术:Grid组件 + scrollBar属性 + height属性配合实现滚动效果
*/
@Entry
@Component
struct GridScrollBarExample {
/**
* @State 装饰器标记状态变量,当变量值改变时会触发UI刷新
* 模拟大型网格数据,创建100个网格项
*/
@State gridData: number[] = this.createGridData();
/**
* @State 滚动条显示状态,默认为Auto
* BarState.Auto:滚动时显示,停止时隐藏
* BarState.On:始终显示滚动条
* BarState.Off:始终隐藏滚动条
*/
@State currentBarState: BarState = BarState.Auto;
/**
* @State 滚动条颜色数组,用于切换演示
*/
@State barColors: string[] = ['#2196f3', '#4caf50', '#ff9800', '#f44336'];
/**
* @State 当前选中的滚动条颜色索引
*/
@State currentColorIndex: number = 0;
/**
* @State 当前选中的滚动条状态索引
*/
@State currentStateIndex: number = 0;
/**
* 滚动条状态名称数组,用于按钮显示
*/
private barStateNames: string[] = ['Auto', 'On', 'Off'];
/**
* 滚动条状态值数组
*/
private barStateValues: BarState[] = [BarState.Auto, BarState.On, BarState.Off];
/**
* 创建网格数据
* ArkTS不支持Array.from,需要手动创建数组
*/
private createGridData(): number[] {
let data: number[] = [];
for (let i = 0; i < 100; i++) {
data.push(i + 1);
}
return data;
}
/**
* 切换滚动条状态
*/
private toggleBarState(): void {
this.currentStateIndex = (this.currentStateIndex + 1) % this.barStateValues.length;
this.currentBarState = this.barStateValues[this.currentStateIndex];
}
/**
* 切换滚动条颜色
*/
private toggleBarColor(): void {
this.currentColorIndex = (this.currentColorIndex + 1) % this.barColors.length;
}
/**
* build()方法是组件的构建函数,用于描述UI结构
*/
build() {
/**
* 使用Column作为根容器,采用垂直布局
* height('100%')和width('100%')使容器占满整个屏幕
*/
Column() {
/**
* 页面标题区域
* 设置背景色和内边距,增强视觉效果
*/
Text('Grid + ScrollBar 滚动条布局示例')
.fontSize(20)
.fontWeight(FontWeight.Bold)
.padding({ top: 20, bottom: 15 })
.width('100%')
.textAlign(TextAlign.Center)
.backgroundColor('#f0f0f0');
/**
* 控制面板区域
* 提供交互式按钮,演示滚动条状态和颜色切换
*/
Row() {
/**
* 滚动条状态切换按钮
*/
Column() {
Text('滚动条状态')
.fontSize(14)
.fontWeight(FontWeight.Medium)
.margin({ bottom: 8 });
Text(`当前: ${this.barStateNames[this.currentStateIndex]}`)
.fontSize(12)
.opacity(0.7)
.margin({ bottom: 8 });
Button('切换状态')
.width(120)
.height(40)
.backgroundColor('#2196f3')
.fontColor('#ffffff')
.borderRadius(8)
.onClick(() => {
this.toggleBarState();
});
}
.flexGrow(1)
.alignItems(HorizontalAlign.Center);
/**
* 分隔线
*/
Divider()
.vertical(true)
.width(1)
.color('#e0e0e0');
/**
* 滚动条颜色切换按钮
*/
Column() {
Text('滚动条颜色')
.fontSize(14)
.fontWeight(FontWeight.Medium)
.margin({ bottom: 8 });
/**
* 颜色指示器
*/
Row() {
Text('当前颜色:')
.fontSize(12)
.opacity(0.7);
Blank()
.width(10);
Stack() {
Text('')
.width(20)
.height(20)
.backgroundColor(this.barColors[this.currentColorIndex])
.borderRadius(4);
}
.margin({ bottom: 8 });
}
.width('100%')
.justifyContent(FlexAlign.Center);
Button('切换颜色')
.width(120)
.height(40)
.backgroundColor('#2196f3')
.fontColor('#ffffff')
.borderRadius(8)
.onClick(() => {
this.toggleBarColor();
});
}
.flexGrow(1)
.alignItems(HorizontalAlign.Center);
}
.width('100%')
.padding({ top: 15, bottom: 15, left: 20, right: 20 })
.backgroundColor('#ffffff');
/**
* Grid组件:网格布局容器
*
* 关键属性说明:
* 1. height('500vp'):设置固定高度,这是触发滚动的关键条件
* - 当Grid内容高度超过容器高度时,才会出现滚动条
* - 如果不设置固定高度,Grid会自适应内容高度,不会产生滚动
*
* 2. scrollBar(BarState.Auto):控制滚动条显示状态
* - BarState.Auto:滚动条自动显示/隐藏(滚动时显示,停止时隐藏)
* - BarState.On:始终显示滚动条
* - BarState.Off:始终隐藏滚动条
*
* 3. scrollBarWidth():设置滚动条宽度
*
* 4. scrollBarColor():设置滚动条滑块颜色
*
* 5. columnsTemplate:定义列模板,设置4列等宽分布
* - '1fr 1fr 1fr 1fr' 表示4列,每列占用相等的空间
*
* 6. rowsGap:设置行间距
* 7. columnsGap:设置列间距
*/
Grid() {
/**
* 使用ArkUI的ForEach渲染函数遍历gridData数组
* ForEach语法:ForEach(数据源, 项生成器, 键生成器)
* 键生成器用于优化渲染性能,确保每个项有唯一标识
*/
ForEach(
this.gridData,
(item: number, index: number) => {
/**
* GridItem:网格中的每个单元格
* 设置高度、背景色、对齐方式等属性
*/
GridItem() {
/**
* 每个网格项内部使用Column布局,显示序号和标签
*/
Column() {
/**
* 显示网格项序号
* 使用较大字体和粗体,突出显示
*/
Text(`${item}`)
.fontSize(24)
.fontWeight(FontWeight.Bold)
.margin({ bottom: 5 });
/**
* 显示网格项标签
* 使用较小字体,辅助说明
*/
Text('网格项')
.fontSize(12)
.opacity(0.7);
}
/**
* 设置网格项内部内容居中对齐
*/
.justifyContent(FlexAlign.Center)
.alignItems(HorizontalAlign.Center)
}
/**
* 设置GridItem的高度
* 使用100vp固定高度,使每个网格项大小一致
*/
.height(100)
/**
* 根据索引计算背景色,实现斑马纹效果
* 偶数索引使用浅蓝色,奇数索引使用浅灰色
*/
.backgroundColor(index % 2 === 0 ? '#e3f2fd' : '#f5f5f5')
/**
* 设置圆角,使网格项边角圆润
*/
.borderRadius(8);
},
(item: number) => `${item}`
);
}
/**
* 设置Grid容器固定高度为500vp
* 这是实现滚动效果的关键:当内容高度超过500vp时,自动出现滚动条
*/
.height(500)
/**
* 设置Grid宽度为100%,占满父容器宽度
*/
.width('100%')
/**
* 设置网格列模板:4列等宽分布
*/
.columnsTemplate('1fr 1fr 1fr 1fr')
/**
* 设置列间距为10vp
*/
.columnsGap(10)
/**
* 设置行间距为10vp
*/
.rowsGap(10)
/**
* 设置Grid内边距,使内容与边缘保持一定距离
*/
.padding(10)
/**
* 设置滚动条显示状态,绑定到@State变量,支持动态切换
*/
.scrollBar(this.currentBarState)
/**
* 设置滚动条宽度为8vp
*/
.scrollBarWidth(8)
/**
* 设置滚动条滑块颜色,绑定到@State变量,支持动态切换
*/
.scrollBarColor(this.barColors[this.currentColorIndex])
/**
* 设置Grid背景色为白色
*/
.backgroundColor('#ffffff')
/**
* 设置Grid圆角,使整体外观更美观
*/
.borderRadius(12)
/**
* 添加外边距,使Grid与其他元素保持距离
*/
.margin({ top: 15 });
/**
* 底部说明区域
* 展示布局要点和技术说明
*/
Column() {
Text('布局要点说明:')
.fontSize(16)
.fontWeight(FontWeight.Bold)
.margin({ top: 15, bottom: 10 });
Text('1. Grid组件必须设置固定高度(height属性)才能触发滚动')
.fontSize(14)
.margin({ bottom: 5 })
.opacity(0.8);
Text('2. scrollBar属性控制滚动条显示状态(Auto/On/Off)')
.fontSize(14)
.margin({ bottom: 5 })
.opacity(0.8);
Text('3. scrollBarWidth和scrollBarColor自定义滚动条样式')
.fontSize(14)
.margin({ bottom: 5 })
.opacity(0.8);
Text('4. columnsTemplate定义列布局,如"1fr 1fr 1fr 1fr"表示4列等宽')
.fontSize(14)
.opacity(0.8);
Text('5. 使用ForEach渲染大量数据,键生成器确保渲染性能')
.fontSize(14)
.opacity(0.8);
}
/**
* 设置底部说明区域的宽度和内边距
*/
.width('100%')
.padding({ left: 15, right: 15, bottom: 20 });
}
/**
* 设置根Column容器占满整个屏幕
*/
.height('100%')
.width('100%')
/**
* 设置背景色为浅灰色,使页面更美观
*/
.backgroundColor('#f5f5f5');
}
}
五、Grid+scrollBar布局原理深度解析
5.1 滚动触发机制
Grid组件的滚动功能是基于容器尺寸和内容尺寸的比较实现的:
- 容器尺寸:由
height属性决定,如.height(500)表示容器高度为500vp - 内容尺寸:由GridItem的数量、高度和间距共同决定
- 滚动触发条件:当内容尺寸 > 容器尺寸时,自动启用滚动功能
内容高度计算公式:
内容高度 = (GridItem数量 / 列数) × (GridItem高度 + 行间距) + 内边距
示例计算:
GridItem数量 = 100
列数 = 4
GridItem高度 = 100vp
行间距 = 10vp
内边距 = 10vp
行数 = 100 / 4 = 25行
内容高度 = 25 × (100 + 10) + 20 = 2770vp
容器高度 = 500vp
滚动区域 = 2770vp - 500vp = 2270vp
5.2 滚动条渲染原理
滚动条的渲染涉及以下关键参数:
5.2.1 滑块高度计算
滑块高度与内容总量和容器尺寸相关:
滑块高度 = 容器高度 × (容器高度 / 内容高度)
5.2.2 滑块位置计算
滑块位置与当前滚动偏移量相关:
滑块位置 = 滚动偏移量 × ((容器高度 - 滑块高度) / (内容高度 - 容器高度))
5.3 BarState状态机制
5.3.1 BarState.Auto
在Auto模式下,滚动条的显示和隐藏由系统自动控制:
- 显示时机:当用户开始滚动时,滚动条渐显
- 隐藏时机:当用户停止滚动一段时间后(通常为1-2秒),滚动条渐隐
- 实现原理:系统通过定时器监控滚动状态,在滚动停止后延迟隐藏
5.3.2 BarState.On
在On模式下,滚动条始终显示:
- 适用场景:需要用户明确感知滚动区域的场景
- 实现原理:滚动条的opacity始终为1,不随滚动状态变化
5.3.3 BarState.Off
在Off模式下,滚动条始终隐藏:
- 适用场景:全屏沉浸式体验、自定义滚动指示器等场景
- 实现原理:滚动条的opacity始终为0,或不渲染滚动条组件
六、API Level相关特性说明
6.1 API Level概述
API Level是HarmonyOS中用于标识API版本的数值,不同的API Level对应不同的系统版本和功能支持。开发者在使用API时,需要根据目标设备的API Level选择合适的API。
6.2 scrollBar相关API的API Level支持
| 属性/事件 | API Level |
|---|---|
| scrollBar | 8+ |
| scrollBarColor | 11+ |
| scrollBarWidth | 11+ |
| scrollBarMargin | 20+ |
| onScrollStart | 11+ |
| onScrollStop | 11+ |
| onReachStart | 11+ |
| onReachEnd | 11+ |
| onDidScroll | 12+ |
6.3 API Level 24兼容性说明
对于API Level 24的目标设备,上述所有scrollBar相关API均已支持。开发者可以放心使用以下特性:
- scrollBar属性控制滚动条显示状态
- scrollBarWidth设置滚动条宽度
- scrollBarColor设置滚动条颜色
- scrollBarMargin设置滚动条边距(仅支持top/bottom)
- 所有滚动事件监听
6.4 scrollBarMargin属性详解
scrollBarMargin属性用于设置滚动条与组件边缘的距离,仅支持top和bottom两个方向:
Grid() {
// GridItem子组件
}
.height(500)
.scrollBar(BarState.Auto)
.scrollBarMargin({
top: 10,
bottom: 10
})
注意:scrollBarMargin属性仅支持top和bottom方向的边距设置,不支持left和right方向。
七、常见问题与解决方案
7.1 滚动条不显示问题
问题描述:设置了scrollBar属性,但滚动条不显示
可能原因及解决方案:
| 原因 | 解决方案 |
|---|---|
| Grid未设置固定高度 | 设置.height(500)等固定高度 |
| 内容高度未超过容器高度 | 增加GridItem数量或高度 |
| scrollBar设置为BarState.Off | 修改为BarState.Auto或BarState.On |
调试代码示例:
Grid() {
ForEach(this.gridData, (item) => {
GridItem() {
Text(`${item}`)
}
.height(100);
}, (item) => `${item}`);
}
.height(500) // 必须设置固定高度
.scrollBar(BarState.Auto) // 使用Auto或On状态
7.2 滚动条样式不生效问题
问题描述:设置了scrollBarWidth和scrollBarColor,但样式不生效
可能原因及解决方案:
| 原因 | 解决方案 |
|---|---|
| API Level版本过低 | 确保API Level >= 11 |
| 属性顺序错误 | scrollBar样式属性应在scrollBar属性之后设置 |
| 颜色值格式错误 | 使用正确的颜色格式,如’#2196f3’或Color.Blue |
正确代码示例:
Grid() {
// GridItem子组件
}
.height(500)
.scrollBar(BarState.Auto) // 先设置滚动条状态
.scrollBarWidth(8) // 再设置宽度
.scrollBarColor('#2196f3') // 最后设置颜色
7.3 ForEach渲染性能问题
问题描述:大量数据渲染时出现卡顿
解决方案:
- 使用键生成器:确保ForEach的第三个参数(键生成器)返回唯一值
- 控制数据量:通过分页加载等方式控制单次渲染的数据量
- 优化GridItem:减少GridItem内部的嵌套层级和复杂组件
优化代码示例:
Grid() {
ForEach(
this.gridData,
(item: number) => {
GridItem() {
// 简化GridItem内容
Text(`${item}`)
.fontSize(24);
}
.height(100);
},
(item: number) => `${item}` // 键生成器返回唯一值
);
}
.height(500)
.scrollBar(BarState.Auto);
7.4 滚动事件不触发问题
问题描述:设置了onScrollStart、onScrollStop等事件,但不触发
解决方案:
- 确认API Level:确保API Level >= 11
- 确认滚动触发条件:内容高度必须超过容器高度
- 检查事件语法:确保事件回调函数语法正确
正确代码示例:
Grid() {
// GridItem子组件
}
.height(500)
.onScrollStart(() => {
console.info('滚动开始');
})
.onScrollStop(() => {
console.info('滚动停止');
});
7.5 箭头函数参数类型标注问题
问题描述:在ForEach或事件回调中使用箭头函数参数类型标注时报错
解决方案:ArkTS支持在箭头函数参数中使用类型标注,但需要注意语法正确性:
// 正确用法
ForEach(
this.gridData,
(item: number, index: number) => {
// 正确的类型标注方式
},
(item: number) => `${item}`
);
// 事件回调
.onClick(() => {
// 无参数时不需要类型标注
});
7.6 Array.from不支持问题
问题描述:使用Array.from创建数组时报错
解决方案:ArkTS不支持Array.from方法,需要手动创建数组:
// 错误用法
@State gridData: number[] = Array.from({ length: 100 }, (_, i) => i + 1);
// 正确用法
private createGridData(): number[] {
let data: number[] = [];
for (let i = 0; i < 100; i++) {
data.push(i + 1);
}
return data;
}
@State gridData: number[] = this.createGridData();
7.7 textAlign字符串参数问题
问题描述:使用textAlign(‘center’)时报错
解决方案:textAlign属性需要使用TextAlign枚举值:
// 错误用法
.textAlign('center')
// 正确用法
.textAlign(TextAlign.Center)
7.8 Column组件alignItems属性问题
问题描述:使用Column组件的alignItems(FlexAlign.Center)时报错
解决方案:Column组件的alignItems属性需要使用HorizontalAlign枚举:
// 错误用法
Column() {
// 内容
}
.alignItems(FlexAlign.Center);
// 正确用法
Column() {
// 内容
}
.alignItems(HorizontalAlign.Center);
对齐枚举总结:
- Column组件:justifyContent使用FlexAlign,alignItems使用HorizontalAlign
- Row组件:justifyContent使用FlexAlign,alignItems使用VerticalAlign
八、性能优化策略
8.1 虚拟滚动优化
Grid组件内置虚拟滚动机制,只渲染可见区域的GridItem,显著提升性能。
虚拟滚动工作原理:
- 计算可见区域:根据容器尺寸和滚动位置,计算当前可见的GridItem范围
- 渲染可见项:只渲染可见范围内的GridItem
- 复用组件:当GridItem滚出可见区域时,回收组件资源;当新的GridItem滚入时,复用已回收的组件
虚拟滚动配置:
Grid() {
ForEach(
this.gridData,
(item) => {
GridItem() {
// GridItem内容
}
},
(item) => `${item}`
);
}
.height(500)
// 虚拟滚动默认启用,无需额外配置
8.2 数据加载优化
分页加载:
@State gridData: number[] = [];
@State pageIndex: number = 1;
private pageSize: number = 20;
private loadMoreData(): void {
let newData: number[] = [];
let startIndex = (this.pageIndex - 1) * this.pageSize;
for (let i = startIndex; i < startIndex + this.pageSize; i++) {
newData.push(i + 1);
}
this.gridData = this.gridData.concat(newData);
this.pageIndex++;
}
build() {
Grid() {
ForEach(
this.gridData,
(item) => {
GridItem() {
Text(`${item}`)
}
.height(100);
},
(item) => `${item}`
);
}
.height(500)
.scrollBar(BarState.Auto)
.onReachEnd(() => {
// 滚动到底部时加载更多数据
this.loadMoreData();
});
}
8.3 GridItem优化
减少嵌套层级:
// 优化前:多层嵌套
GridItem() {
Column() {
Row() {
Text('内容')
}
}
}
// 优化后:减少嵌套
GridItem() {
Text('内容')
}
使用@Builder提取公共组件:
@Builder
GridItemBuilder(item: number) {
Text(`${item}`)
.fontSize(24)
.fontWeight(FontWeight.Bold);
}
build() {
Grid() {
ForEach(
this.gridData,
(item) => {
GridItem() {
this.GridItemBuilder(item);
}
.height(100);
},
(item) => `${item}`
);
}
.height(500);
}
8.4 样式优化
避免频繁的样式计算:
// 优化前:每次渲染都计算颜色
.backgroundColor(index % 2 === 0 ? '#e3f2fd' : '#f5f5f5')
// 优化后:使用预定义的颜色数组
private colors: string[] = ['#e3f2fd', '#f5f5f5'];
.backgroundColor(this.colors[index % 2])
九、实战案例:图片画廊应用
9.1 案例概述
本案例实现一个图片画廊应用,展示如何使用Grid+scrollBar布局实现图片网格展示和滚动功能。
9.2 功能需求
- 展示图片的网格布局
- 支持滚动浏览
- 显示滚动条
- 支持图片点击查看详情
9.3 代码实现
@Entry
@Component
struct PhotoGallery {
@State photos: string[] = this.createPhotoData();
@State selectedPhoto: string = '';
private createPhotoData(): string[] {
let data: string[] = [];
for (let i = 1; i <= 30; i++) {
data.push(`photo_${i}`);
}
return data;
}
private onPhotoClick(photo: string): void {
this.selectedPhoto = photo;
// 可以在这里打开详情页面或对话框
console.info(`点击了图片: ${photo}`);
}
build() {
Column() {
Text('图片画廊')
.fontSize(20)
.fontWeight(FontWeight.Bold)
.padding({ top: 20, bottom: 15 })
.width('100%')
.textAlign(TextAlign.Center)
.backgroundColor('#f0f0f0');
Grid() {
ForEach(
this.photos,
(photo: string, index: number) => {
GridItem() {
Column() {
Text(photo)
.fontSize(16)
.fontWeight(FontWeight.Medium);
Text(`第${index + 1}张`)
.fontSize(12)
.opacity(0.7);
}
.justifyContent(FlexAlign.Center)
.alignItems(HorizontalAlign.Center)
.width('100%')
.height(120)
.backgroundColor(index % 2 === 0 ? '#e3f2fd' : '#fff3e0')
.borderRadius(8)
.onClick(() => {
this.onPhotoClick(photo);
});
}
},
(photo: string) => photo
);
}
.height('100%')
.width('100%')
.columnsTemplate('1fr 1fr 1fr')
.columnsGap(10)
.rowsGap(10)
.padding(10)
.scrollBar(BarState.Auto)
.scrollBarWidth(6)
.scrollBarColor('#2196f3');
}
.height('100%')
.width('100%')
.backgroundColor('#f5f5f5');
}
}
十、总结与展望
10.1 核心要点总结
Grid组件:
- 用于实现网格布局的核心容器组件
- 需要设置固定高度才能触发滚动
- 支持自定义列数、行高、间距等属性
scrollBar属性:
- 控制滚动条的显示状态(Auto/On/Off)
- scrollBarWidth设置滚动条宽度(API Level 11+)
- scrollBarColor设置滚动条颜色(API Level 11+)
- scrollBarMargin设置滚动条边距(API Level 20+,仅支持top/bottom)
- 支持多种滚动事件监听(API Level 11+)
布局要点:
- Grid容器必须设置固定高度
- 内容高度超过容器高度时自动触发滚动
- 使用ForEach渲染大量数据时必须提供键生成器
- Column组件的alignItems使用HorizontalAlign枚举
- Row组件的alignItems使用VerticalAlign枚举
ArkTS语法注意事项:
- 不支持Array.from,需要手动创建数组
- textAlign属性需要使用TextAlign枚举值
- 箭头函数参数可以使用类型标注
10.2 未来发展趋势
随着HarmonyOS NEXT的不断发展,Grid+scrollBar布局将迎来更多优化:
- 性能提升:虚拟滚动机制将更加高效,支持更大数据量
- 样式定制:滚动条样式将支持更多自定义选项
- 交互增强:支持更多滚动手势和交互方式
- 响应式布局:Grid组件将更好地支持多设备适配
10.3 学习建议
- 深入理解布局原理:掌握Grid组件的布局计算和滚动触发机制
- 实践API使用:通过实际项目练习scrollBar相关属性的使用
- 关注性能优化:学习虚拟滚动和数据加载优化技巧
- 参考官方文档:定期查阅HarmonyOS官方文档,了解最新API特性
附录:API参考
Grid组件属性
| 属性名 | 类型 | 说明 | API Level |
|---|---|---|---|
| columnsTemplate | string | 列模板定义 | 8+ |
| columnsGap | number | 列间距 | 8+ |
| rowsGap | number | 行间距 | 8+ |
| rowHeight | Length | 行高度 | 8+ |
| height | Length | 容器高度 | 8+ |
| width | Length | 容器宽度 | 8+ |
scrollBar相关属性
| 属性名 | 类型 | 说明 | API Level |
|---|---|---|---|
| scrollBar | BarState | 滚动条显示状态 | 8+ |
| scrollBarWidth | number | 滚动条宽度 | 11+ |
| scrollBarColor | ResourceColor | 滚动条颜色 | 11+ |
| scrollBarMargin | EdgeInsets | 滚动条边距(仅支持top/bottom) | 20+ |
滚动事件
| 事件名 | 说明 | API Level |
|---|---|---|
| onScrollStart | 滚动开始时触发 | 11+ |
| onScrollStop | 滚动停止时触发 | 11+ |
| onReachStart | 滚动到起始位置时触发 | 11+ |
| onReachEnd | 滚动到末尾位置时触发 | 11+ |
| onDidScroll | 滚动过程中触发 | 12+ |
BarState枚举
| 枚举值 | 说明 |
|---|---|
| BarState.Auto | 自动显示/隐藏 |
| BarState.On | 始终显示 |
| BarState.Off | 始终隐藏 |
TextAlign枚举
| 枚举值 | 说明 |
|---|---|
| TextAlign.Center | 居中对齐 |
| TextAlign.Start | 起始对齐 |
| TextAlign.End | 末尾对齐 |
HorizontalAlign枚举
| 枚举值 | 说明 |
|---|---|
| HorizontalAlign.Center | 水平居中 |
| HorizontalAlign.Start | 水平起始 |
| HorizontalAlign.End | 水平末尾 |
VerticalAlign枚举
| 枚举值 | 说明 |
|---|---|
| VerticalAlign.Center | 垂直居中 |
| VerticalAlign.Top | 垂直顶部 |
| VerticalAlign.Bottom | 垂直底部 |
FlexAlign枚举
| 枚举值 | 说明 |
|---|---|
| FlexAlign.Center | 居中 |
| FlexAlign.Start | 起始 |
| FlexAlign.End | 末尾 |
| FlexAlign.SpaceBetween | 两端对齐 |
| FlexAlign.SpaceAround | 均匀分布 |
更多推荐




所有评论(0)