HarmonyOS:使用Grid构建网格
一、概述
网格布局是由“行”和“列”分割的单元格所组成,通过指定“项目”所在的单元格做出各种各样的布局。网格布局具有较强的页面均分能力,子组件占比控制能力,是一种重要自适应布局,其使用场景有九宫格图片展示、日历、计算器等。
ArkUI提供了Grid容器组件和子组件GridItem,用于构建网格布局。Grid用于设置网格布局相关参数,GridItem定义子组件相关特征。Grid组件支持使用条件渲染、循环渲染、懒加载等方式生成子组件。
二、布局与约束
Grid组件为网格容器,其中容器内各条目对应一个GridItem组件,如下图所示。
Grid与GridItem组件关系
说明
Grid的子组件必须是GridItem组件。
网格布局是一种二维布局。Grid组件支持自定义行列数和每行每列尺寸占比、设置子组件横跨几行或者几列,同时提供了垂直和水平布局能力。当网格容器组件尺寸发生变化时,所有子组件以及间距会等比例调整,从而实现网格布局的自适应能力。根据Grid的这些布局能力,可以构建出不同样式的网格布局,如下图所示。
如果Grid组件设置了宽高属性,则其尺寸为设置值。如果没有设置宽高属性,Grid组件的尺寸默认适应其父组件的尺寸。
Grid组件根据行列数量与占比属性的设置,可以分为三种布局情况:
- 行、列数量与占比同时设置:Grid只展示固定行列数的元素,其余元素不展示,且Grid不可滚动。(推荐使用该种布局方式)
- 只设置行、列数量与占比中的一个:元素按照设置的方向进行排布,超出的元素可通过滚动的方式展示。
- 行列数量与占比都不设置:元素在布局方向上排布,其行列数由布局方向、单个网格的宽高等多个属性共同决定。超出行列容纳范围的元素不展示,且Grid不可滚动。
三、设置排列方式
3.1 设置行列数量与占比
通过设置行列数量与尺寸占比可以确定网格布局的整体排列方式。Grid组件提供了rowsTemplate和columnsTemplate属性用于设置网格布局行列数量与尺寸占比。
rowsTemplate和columnsTemplate属性值是一个由多个空格和’数字+fr’间隔拼接的字符串,fr的个数即网格布局的行或列数,fr前面的数值大小,用于计算该行或列在网格布局宽度上的占比,最终决定该行或列宽度。
行列数量占比示例
如上图所示,构建的是一个三行三列的网格布局,其在垂直方向上分为三等份,每行占一份;在水平方向上分为四等份,第一列占一份,第二列占两份,第三列占一份。
只要将rowsTemplate的值为’1fr 1fr 1fr’,同时将columnsTemplate的值为’1fr 2fr 1fr’,即可实现上述网格布局。
Grid() {...
}
.rowsTemplate('1fr 1fr 1fr')
.columnsTemplate('1fr 2fr 1fr')
说明
当Grid组件设置了rowsTemplate或columnsTemplate时,Grid的layoutDirection、maxCount、minCount、cellLength属性不生效,属性说明可参考Grid-属性。
示例效果图
示例效果图
TestGridDemo.ets代码
class ItemBean {id: string = '';name: string = '';value: string = '';constructor(id: string, name: string, value: string) {this.id = id;this.name = name;this.value = value;}
}@Component
struct GridDemo1 {private dataList: Array<ItemBean> = [new ItemBean("1001", "1", "1"),new ItemBean("1002", "2", "2"),new ItemBean("1003", "3", "3"),new ItemBean("1004", "4", "4"),new ItemBean("1005", "5", "5"),new ItemBean("1006", "6", "6")]build() {Column() {Grid() {ForEach(this.dataList, (item: ItemBean) => {GridItem() {Text(item.name).fontSize(40).fontColor(Color.White).textAlign(TextAlign.Center)}.backgroundColor(Color.Blue)}, (item: ItemBean) => item.id)}.backgroundColor(Color.White).columnsGap(8).rowsGap(8)//构建的是一个三行三列的网格布局.rowsTemplate('1fr 1fr 1fr')// 垂直方向上分为三等份,每行占一份.columnsTemplate('1fr 2fr 1fr')// 水平方向上分为四等份,第一列占一份,第二列占两份,第三列占一份.height(300)}}
}@Entry
@Component
struct TestGridDemo {@State message: string = 'Hello World';build() {Scroll() {Column() {GridDemo1()}.margin({ top: 30 })}.backgroundColor(Color.White).scrollable(ScrollDirection.Vertical).scrollBar(BarState.Auto).scrollBarColor(Color.Gray).align(Alignment.TopStart).constraintSize({ minHeight: '100%' }).edgeEffect(EdgeEffect.Spring) //设置边缘滑动效果。}
}
3.2 设置子组件所占行列数
除了大小相同的等比例网格布局,由不同大小的网格组成不均匀分布的网格布局场景在实际应用中十分常见,如下图所示。在Grid组件中,可以通过创建Grid时传入合适的GridLayoutOptions实现如图所示的单个网格横跨多行或多列的场景,其中,irregularIndexes和onGetIrregularSizeByIndex可对仅设置rowsTemplate或columnsTemplate的Grid使用;onGetRectByIndex可对同时设置rowsTemplate和columnsTemplate的Grid使用。
不均匀网格布局
例如计算器的按键布局就是常见的不均匀网格布局场景。如下图,计算器中的按键“0”和“=”,按键“0”横跨第一、二两列,按键“=”横跨第五、六两行。使用Grid构建的网格布局,其行列标号从0开始,依次编号。
示例效果图
示例组件代码
@Component
struct GridDemo2 {private dataList: Array<ItemBean> = [new ItemBean("1001", "1", "1"),new ItemBean("1002", "2", "2"),new ItemBean("1003", "3", "3"),new ItemBean("1004", "4", "4"),new ItemBean("1005", "5", "5"),new ItemBean("1006", "6", "6"),new ItemBean("1007", "7", "7"),new ItemBean("1008", "8", "8"),]layoutOptions: GridLayoutOptions = {regularSize: [1, 1],onGetRectByIndex: (index: number) => {if (index == 0) {return [0, 0, 1, 1]}else if (index == 1) {return [0, 1, 1, 1]} else if (index == 2) {return [0, 2, 1, 2]} else if (index == 3) {return [1, 0, 2, 1]} else if (index == 4) {return [1, 1, 1, 1]} else if (index == 5) {return [1, 2, 1, 1]} else if (index == 6) {return [1, 3, 1, 1]}else {return [2, 1, 1, 3]}}}build() {Column() {GridTitle({ title: " 设置子组件所占行列数" })Grid(undefined, this.layoutOptions) {ForEach(this.dataList, (item: ItemBean) => {GridItem() {Text(item.name).fontSize(40).fontColor(Color.Black).textAlign(TextAlign.Center)}.backgroundColor(Color.Gray).width("100%").height('100%')}, (item: ItemBean) => item.id)}.columnsTemplate('1fr 1fr 1fr 1fr').rowsTemplate('1fr 1fr 1fr').columnsGap(8).backgroundColor(Color.Pink).rowsGap(8).height(320)}}
}
计算器
在网格中,可以通过onGetRectByIndex返回的[rowStart,columnStart,rowSpan,columnSpan]来实现跨行跨列布局,其中rowStart和columnStart属性表示指定当前元素起始行号和起始列号,rowSpan和columnSpan属性表示指定当前元素的占用行数和占用列数。
所以“0”按键横跨第一列和第二列,“=”按键横跨第五行和第六行,只要将“0”对应onGetRectByIndex的rowStart和columnStart设为5和0,rowSpan和columnSpan设为1和2,将“=”对应onGetRectByIndex的rowStart和columnStart设为4和3,rowSpan和columnSpan设为2和1即可。
layoutOptions: GridLayoutOptions = {regularSize: [1, 1],onGetRectByIndex: (index: number) => {if (index == key1) { // key1是“0”按键对应的indexreturn [5, 0, 1, 2]} else if (index == key2) { // key2是“=”按键对应的indexreturn [4, 3, 2, 1]}// ...// 这里需要根据具体布局返回其他item的位置}
}Grid(undefined, this.layoutOptions) {// ...
}
.columnsTemplate('1fr 1fr 1fr 1fr')
.rowsTemplate('2fr 1fr 1fr 1fr 1fr 1fr')
3.3 设置主轴方向
使用Grid构建网格布局时,若没有设置行列数量与占比,可以通过layoutDirection设置网格布局的主轴方向,决定子组件的排列方式。此时可以结合minCount和maxCount属性来约束主轴方向上的网格数量。
主轴方向示意图
当前layoutDirection设置为Row时,先从左到右排列,排满一行再排下一行。当前layoutDirection设置为Column时,先从上到下排列,排满一列再排下一列,如上图所示。此时,将maxCount属性设为3,表示主轴方向上最大显示的网格单元数量为3。
Grid() {...
}
.maxCount(3)
.layoutDirection(GridDirection.Row)
说明
- layoutDirection属性仅在不设置rowsTemplate和columnsTemplate时生效,此时元素在layoutDirection方向上排列。
- 仅设置rowsTemplate时,Grid主轴为水平方向,交叉轴为垂直方向。
- 仅设置columnsTemplate时,Grid主轴为垂直方向,交叉轴为水平方向。
四、在网格布局中显示数据
网格布局采用二维布局的方式组织其内部元素,如下图所示。
通用办公服务
Grid组件可以通过二维布局的方式显示一组GridItem子组件。
Grid() {GridItem() {Text('会议')...}GridItem() {Text('签到')...}GridItem() {Text('投票')...}GridItem() {Text('打印')...}
}
.rowsTemplate('1fr 1fr')
.columnsTemplate('1fr 1fr')
对于内容结构相似的多个GridItem,通常更推荐使用ForEach语句中嵌套GridItem的形式,来减少重复代码。
示例效果图
@Component
struct GridTitle {@Prop title: string = ''build() {Text(this.title).fontColor(Color.Black).fontSize(20).fontWeight(FontWeight.Bold).margin({ top: 20, bottom: 10 }).textAlign(TextAlign.Start).width('100%')}
}@Component
struct OfficeService {@State services: Array<string> = ['会议', '投票', '签到', '打印']build() {Column() {GridTitle({ title: "网格布局采用二维布局的方式组织其内部元素" })Grid() {ForEach(this.services, (service: string) => {GridItem() {Text(service)}.backgroundColor(Color.Gray)}, (service: string): string => service)}.rowsTemplate(('1fr 1fr') as string).columnsTemplate(('1fr 1fr') as string).rowsGap(8).columnsGap(8).height(200)}}
}
五、设置行列间距
在两个网格单元之间的网格横向间距称为行间距,网格纵向间距称为列间距,如下图所示。
网格的行列间距
通过Grid的rowsGap和columnsGap可以设置网格布局的行列间距。在图5所示的计算器中,行间距为15vp,列间距为10vp。
Grid() {...
}
.columnsGap(10)
.rowsGap(15)
六、构建可滚动的网格布局
可滚动的网格布局常用在文件管理、购物或视频列表等页面中,如下图所示。在设置Grid的行列数量与占比时,如果仅设置行、列数量与占比中的一个,即仅设置rowsTemplate或仅设置columnsTemplate属性,网格单元按照设置的方向排列,超出Grid显示区域后,Grid拥有可滚动能力。
横向可滚动网格布局
如果设置的是columnsTemplate,Grid的滚动方向为垂直方向;如果设置的是rowsTemplate,Grid的滚动方向为水平方向。
如上图所示的横向可滚动网格布局,只要设置rowsTemplate属性的值且不设置columnsTemplate属性,当内容超出Grid组件宽度时,Grid可横向滚动进行内容展示。
@Entry
@Component
struct Shopping {@State services: Array<string> = ['直播', '进口']build() {Column({ space: 5 }) {Grid() {ForEach(this.services, (service: string, index) => {GridItem() {}.width('25%')}, (service:string):string => service)}.rowsTemplate('1fr 1fr') // 只设置rowsTemplate属性,当内容超出Grid区域时,可水平滚动。.rowsGap(15)}}
}
七、控制滚动位置
与新闻列表的返回顶部场景类似,控制滚动位置功能在网格布局中也很常用,例如下图所示日历的翻页功能。
日历翻页
Grid组件初始化时,可以绑定一个Scroller对象,用于进行滚动控制,例如通过Scroller对象的scrollPage方法进行翻页。
private scroller: Scroller = new Scroller()
在日历页面中,用户在点击“下一页”按钮时,应用响应点击事件,通过指定scrollPage方法的参数next为true,滚动到下一页。
Column({ space: 5 }) {Grid(this.scroller) {}.columnsTemplate('1fr 1fr 1fr 1fr 1fr 1fr 1fr')Row({space: 20}) {Button('上一页').onClick(() => {this.scroller.scrollPage({next: false})})Button('下一页').onClick(() => {this.scroller.scrollPage({next: true})})}
}
八、性能优化
与长列表的处理类似,循环渲染适用于数据量较小的布局场景,当构建具有大量网格项的可滚动网格布局时,推荐使用数据懒加载方式实现按需迭代加载数据,从而提升列表性能。
关于按需加载优化的具体实现可参考数据懒加载章节中的示例。
当使用懒加载方式渲染网格时,为了更好的滚动体验,减少滑动时出现白块,Grid组件中也可通过cachedCount属性设置GridItem的预加载数量,只在懒加载LazyForEach中生效。
设置预加载数量后,会在Grid显示区域前后各缓存cachedCount*列数个GridItem,超出显示和缓存范围的GridItem会被释放。
Grid() {LazyForEach(this.dataSource, () => {GridItem() {}})
}
.cachedCount(3)
说明
cachedCount的增加会增大UI的CPU、内存开销。使用时需要根据实际情况,综合性能和用户体验进行调整。
相关文章:

HarmonyOS:使用Grid构建网格
一、概述 网格布局是由“行”和“列”分割的单元格所组成,通过指定“项目”所在的单元格做出各种各样的布局。网格布局具有较强的页面均分能力,子组件占比控制能力,是一种重要自适应布局,其使用场景有九宫格图片展示、日历、计算器…...

开源Java快速自测工具,可以调用系统内任意一个方法
java快速测试框架,可以调到系统内任意一个方法,告别写单测和controller的困扰。 开源地址:https://gitee.com/missyouch/Easy-JTest 我们在开发时很多时候想要测试下自己的代码,特别是service层或者是更底层的代码,就…...
力扣刷题TOP101: 29.BM36 判断是不是平衡二叉树
目录: 目的 思路 复杂度 记忆秘诀 python代码 目的: 输入一棵节点数为 n 二叉树,判断该二叉树是否是平衡二叉树。 思路 什么是平衡二叉树(AVL 树)? 每个节点的左子树和右子树的高度差不能超过 1。确保…...

【在Linux世界中追寻伟大的One Piece】自旋锁
目录 1 -> 概述 2 -> 原理 3 -> 优缺点及使用场景 3.1 -> 优点 3.2 -> 缺点 3.3 -> 使用场景 4 -> 纯软件自旋锁类似的原理实现 4.1 -> 结论 5 -> 样例代码 1 -> 概述 自旋锁是一种多线程同步机制,用于保护共享资源避免受并…...

前端编辑器JSON HTML等,vue2-ace-editor,vue3-ace-editor
与框架无关 vue2-ace-editor有问题,ace拿不到(brace) 一些组件都是基于ace-builds或者brace包装的 不如直接用下面的,不如直接使用下面的 <template><div ref"editor" class"json-editor"><…...
C++ 中的运算符重载
运算符重载是C中的一种特性,它允许开发者为自定义类型定义或改变标准运算符的行为。通过运算符重载,你可以使得用户定义的类像内置类型一样使用运算符,比如加法、减法、赋值等。 如何在C中进行运算符重载? 重载运算符的语法&#…...

渗透测试工具 -- SQLmap安装教程及使用
随着网络安全问题日益严峻,渗透测试成为了保护信息安全的重要手段。而在渗透测试的众多工具中,SQLmap凭借其强大的自动化SQL注入检测和利用能力,成为了网络安全专家必备的利器。那么,你知道如何高效地使用SQLmap进行漏洞扫描吗&am…...

使用 Database Tools 实现高效数据查询的十大 IntelliJ IDEA 快捷键
得益于 IntelliJ IDEA Ultimate 的 Database Tools(数据库工具)中的专用 SQL 查询控制台,您无需离开 IDE 即可轻松修改连接到您的 Java 应用程序的任何数据库中的数据,以及从这些数据库中提取数据。 查询控制台具有 SQL 语句特定的…...

SpringBoot 整合 RabbitMQ 实现流量消峰
RabbitMQ 即一个消息队列,主要是用来实现应用程序的异步和解耦,同时也能起到消息缓冲,消息分发的作用。 消息中间件在互联网公司的使用中越来越多,刚才还看到新闻阿里将 RocketMQ 捐献给了 Apache,当然了今天的主角还…...

大数据挖掘建模平台案例分享
大数据挖掘建模平台是由泰迪自主研发,面向企业级用户的大数据挖掘建模平台。平台采用可视化操作方式,通过丰富内置算法,帮助用户快速、一站式地进行数据分析及挖掘建模,可应用于处理海量数据、高复杂性的数据挖掘任务,…...
MySQL数据表的管理
1.创建表 语法: create table 表名( 字段名 字段里保存数据的类型【(数据的长度) 约束】, 字段名 字段里保存数据的类型【(数据的长度) 约束】, 字段名 字段里保存数据的类型【(数据的长度) 约束】 ...... ); 注意:数据类型和约束,接下来用…...

SpringBoot【十三(实战篇)】集成在线接口文档Swagger2
一、前言🔥 环境说明:Windows10 Idea2021.3.2 Jdk1.8 SpringBoot 2.3.1.RELEASE 二、如何生成Swagger文档 上一期我们已经能正常访问swagger在线文档,但是文档空空如也,对不对,接下来我就教大家怎么把相关的接口都给…...

【C++初阶】第8课—标准模板库STL(string_2)
文章目录 1. string类对象遍历操作1.1 标准库中的成员函数begin( )和end( )1.2 标准库中的成员函数rbegin( )和rend( )1.3 C11引入的4个标准库中的成员函数 2. string类对象的访问2.1 operator[ ]运算符重载访问字符串字符2.2 公有成员函数at访问字符2.3 公有成员函数back()和f…...
【arm】程序跑飞,SWD端口不可用修复(N32G435CBL7)
项目场景: 国民N32G43X系列,烧录了一个测试程序,在DEBUG中不知什么原因挂掉,然后就无法连接SWD或JLINK。 问题描述 在SWD配置中不可见芯片型号,无法connect,无法烧录。但基本判断是芯片没有损坏。怀疑是程…...
https证书生成、linux 生成https证书、nginx 配置https证书
1. 检查 Certbot 是否已安装 which certbot 2. 安装 Certbot 2.1启用 EPEL 仓库(如果尚未启用): sudo yum install epel-release 2.2 安装 Certbot 和 Nginx 插件: sudo yum install certbot python3-certbot-nginx 2.3验证安…...
Halcon随机贴图生成缺陷图片脚本
halcon随机贴图生成缺陷图片,用于深度学习训练: read_image (Image, C:/Users/61082/Desktop/bentiiamge/omron/S06-1211/ok/ok_images/D246B_CPFNNUBA8LT0SX_AAA_S2412001793_C1216_1733895885320066.jpg) get_image_size (Image, Width, Height) gen_rectangle1 …...

[ZMQ] -- ZMQ通信Protobuf数据结构 1
1、前言背景 工作需要域间实现zmq通信,刚开始需要比较简单的数据结构,比如两个bool,后面可能就需要传输比较大的数据,所以记录下实现流程,至于为啥选择proto数据结构去做大数据传输,可能是地平线也用这个&…...

大数据平台
大数据行业应用持续升温,特别是企业级大数据市场正在进入快速发展时期。越来越多的企业期望实现数据孤岛的打通,整合海量的数据资源,挖掘并沉淀有价值的数据,进而驱动更智能的商业。随着公司数据爆发式增长,原有的数据…...
《C++解锁机器学习特征工程:构建智能数据基石》
在当今机器学习蓬勃发展的浪潮中,特征工程犹如一座坚实的基石,奠定了模型成功的基础。而 C以其卓越的性能和强大的底层控制能力,在实现机器学习特征工程方面发挥着独特且关键的作用。 特征工程的核心目标是从原始数据中提取和构建最具代表性…...

《机器学习》3.7-4.3end if 启发式 uci数据集klda方法——非线性可分的分类器
目录 uci数据集 klda方法——非线性可分的分类器 计算 步骤 1: 选择核函数 步骤 2: 计算核矩阵 步骤 4: 解广义特征值问题 と支持向量机(svm) 目标: 方法: 核技巧的应用: 区别: 使用 OvR MvM 将…...

观成科技:隐蔽隧道工具Ligolo-ng加密流量分析
1.工具介绍 Ligolo-ng是一款由go编写的高效隧道工具,该工具基于TUN接口实现其功能,利用反向TCP/TLS连接建立一条隐蔽的通信信道,支持使用Let’s Encrypt自动生成证书。Ligolo-ng的通信隐蔽性体现在其支持多种连接方式,适应复杂网…...
云原生核心技术 (7/12): K8s 核心概念白话解读(上):Pod 和 Deployment 究竟是什么?
大家好,欢迎来到《云原生核心技术》系列的第七篇! 在上一篇,我们成功地使用 Minikube 或 kind 在自己的电脑上搭建起了一个迷你但功能完备的 Kubernetes 集群。现在,我们就像一个拥有了一块崭新数字土地的农场主,是时…...
【根据当天日期输出明天的日期(需对闰年做判定)。】2022-5-15
缘由根据当天日期输出明天的日期(需对闰年做判定)。日期类型结构体如下: struct data{ int year; int month; int day;};-编程语言-CSDN问答 struct mdata{ int year; int month; int day; }mdata; int 天数(int year, int month) {switch (month){case 1: case 3:…...

TDengine 快速体验(Docker 镜像方式)
简介 TDengine 可以通过安装包、Docker 镜像 及云服务快速体验 TDengine 的功能,本节首先介绍如何通过 Docker 快速体验 TDengine,然后介绍如何在 Docker 环境下体验 TDengine 的写入和查询功能。如果你不熟悉 Docker,请使用 安装包的方式快…...

【机器视觉】单目测距——运动结构恢复
ps:图是随便找的,为了凑个封面 前言 在前面对光流法进行进一步改进,希望将2D光流推广至3D场景流时,发现2D转3D过程中存在尺度歧义问题,需要补全摄像头拍摄图像中缺失的深度信息,否则解空间不收敛…...

华为OD机试-食堂供餐-二分法
import java.util.Arrays; import java.util.Scanner;public class DemoTest3 {public static void main(String[] args) {Scanner in new Scanner(System.in);// 注意 hasNext 和 hasNextLine 的区别while (in.hasNextLine()) { // 注意 while 处理多个 caseint a in.nextIn…...

Keil 中设置 STM32 Flash 和 RAM 地址详解
文章目录 Keil 中设置 STM32 Flash 和 RAM 地址详解一、Flash 和 RAM 配置界面(Target 选项卡)1. IROM1(用于配置 Flash)2. IRAM1(用于配置 RAM)二、链接器设置界面(Linker 选项卡)1. 勾选“Use Memory Layout from Target Dialog”2. 查看链接器参数(如果没有勾选上面…...

Java-41 深入浅出 Spring - 声明式事务的支持 事务配置 XML模式 XML+注解模式
点一下关注吧!!!非常感谢!!持续更新!!! 🚀 AI篇持续更新中!(长期更新) 目前2025年06月05日更新到: AI炼丹日志-28 - Aud…...

2025盘古石杯决赛【手机取证】
前言 第三届盘古石杯国际电子数据取证大赛决赛 最后一题没有解出来,实在找不到,希望有大佬教一下我。 还有就会议时间,我感觉不是图片时间,因为在电脑看到是其他时间用老会议系统开的会。 手机取证 1、分析鸿蒙手机检材&#x…...
C++.OpenGL (10/64)基础光照(Basic Lighting)
基础光照(Basic Lighting) 冯氏光照模型(Phong Lighting Model) #mermaid-svg-GLdskXwWINxNGHso {font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}#mermaid-svg-GLdskXwWINxNGHso .error-icon{fill:#552222;}#mermaid-svg-GLd…...