创建网格(Grid/GridItem)

目录

1、概述

2、布局与约束

3、设置排列方式

3.1设置行列数量与占比

3.2、设置子组件所占行列数

3.3、设置主轴方向

 3.4、在网格布局中显示数据

3.5、设置行列间距

4、构建可滚动的网格布局

5、实现简单的日历功能

6、性能优化


1、概述

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

        ArkUI提供了Grid容器组件和子组件GridItem,用于构建网格布局。Grid用于设置网格布局相关参数,GridItem定义子组件相关特征。Grid组件支持使用条件渲染、循环渲染、懒加载等渲染控制方式生成子组件。

2、布局与约束

        Grid组件为网格容器,其中容器内每一个条目对应一个GridItem组件,如下图所示。

图1 Grid与GridItem组件关系

说明

Grid的子组件必须是GridItem组件。

        网格布局是一种二维布局。Grid组件支持自定义行列数和每行每列尺寸占比、设置子组件横跨几行或者几列,同时提供了垂直和水平布局能力。当网格容器组件尺寸发生变化时,所有子组件以及间距会等比例调整,从而实现网格布局的自适应能力。根据Grid的这些布局能力,可以构建出不同样式的网格布局,如下图所示。

图2 网格布局

        如果Grid组件设置了宽高属性,则其尺寸为设置值。如果没有设置宽高属性,Grid组件的尺寸默认适应其父组件的尺寸。

Grid组件根据行列数量与占比属性的设置,可以分为三种布局情况:

  • 行、列数量与占比同时设置:Grid只展示固定行列数的元素,其余元素不展示,且Grid不可滚动。(推荐使用该种布局方式)
  • 只设置行、列数量与占比中的一个:元素按照设置的方向进行排布,超出的元素可通过滚动的方式展示。
  • 行列数量与占比都不设置:元素在布局方向上排布,其行列数由布局方向、单个网格的宽高等多个属性共同决定。超出行列容纳范围的元素不展示,且Grid不可滚动。

3、设置排列方式

3.1设置行列数量与占比

        通过设置行列数量与尺寸占比可以确定网格布局的整体排列方式。Grid组件提供了rowsTemplate和columnsTemplate属性用于设置网格布局行列数量与尺寸占比。

        rowsTemplate和columnsTemplate属性值是一个由多个空格和'数字+fr'间隔拼接的字符串,fr的个数即网格布局的行或列数,fr前面的数值大小,用于计算该行或列在网格布局宽度上的占比,最终决定该行或列的宽度。

图3 行列数量占比示例

        如上图所示,构建的是一个三行三列的的网格布局,其在垂直方向上分为三等份,每行占一份;在水平方向上分为四等份,第一列占一份,第二列占两份,第三列占一份。

        只要将rowsTemplate的值为'1fr 1fr 1fr',同时将columnsTemplate的值为'1fr 2fr 1fr',即可实现上述网格布局。

@Entry
@Component
struct GridLayoutPage1 {@State message: string = 'Hello World'build() {Row() {Column() {Grid() {GridItem() {Text(`1`).gridTextStyle("#1067c8ff")}GridItem() {Text(`2`).gridTextStyle("#2067c8ff")}GridItem() {Text(`3`).gridTextStyle("#3067c8ff")}GridItem() {Text(`4`).gridTextStyle("#4067c8ff")}GridItem() {Text(`5`).gridTextStyle("#5067c8ff")}GridItem() {Text(`6`).gridTextStyle("#6067c8ff")}GridItem() {Text(`7`).gridTextStyle("#7067c8ff")}GridItem() {Text(`8`).gridTextStyle("#8067c8ff")}GridItem() {Text(`9`).gridTextStyle("#9067c8ff")}}.rowsTemplate('1fr 1fr 1fr').columnsTemplate('1fr 2fr 1fr')}.width('100%')}.height('40%')}
}@Extend(Text) function gridTextStyle(value: ResourceColor) {.backgroundColor(value).width('100%').height('100%').fontSize(22).textAlign(TextAlign.Center)
}

        效果如下:

 

3.2、设置子组件所占行列数

        除了大小相同的等比例网格布局,由不同大小的网格组成不均匀分布的网格布局场景在实际应用中十分常见,如下图所示。在Grid组件中,通过设置GridItem的rowStart、rowEnd、columnStart和columnEnd可以实现如图所示的单个网格横跨多行或多列的场景。

图4 不均匀网格布局

        例如计算器的按键布局就是常见的不均匀网格布局场景。如下图,计算器中的按键“0”和“=”,按键“0”横跨第一、二两列,按键“=”横跨第五、六两行。使用Grid构建的网格布局,其行列标号从1开始,依次编号。

图5 计算器

        在单个网格单元中,rowStart和rowEnd属性表示指定当前元素起始行号和终点行号,columnStart和columnEnd属性表示指定当前元素的起始列号和终点列号。

        所以“0”按键横跨第一列和第二列,只要将“0”对应GridItem的columnStart和columnEnd设为1和2,将“=”对应GridItem的的rowStart和rowEnd设为5和6即可。

        “=”按键横跨第五行和第六行,只要将将“=”对应GridItem的的rowStart和rowEnd设为5和6即可。

@Entry
@Component
struct CalculatorLayoutPage {@State message: string = 'Hello World'build() {Row() {Column() {Grid() {GridItem() {Text(`0`).gridTextStyle2("#1067c8ff").textAlign(TextAlign.End).padding(2)}.rowStart(0).rowEnd(1).columnStart(0).columnEnd(3)GridItem() {Text(`CE`).gridTextStyle2("#2067c8ff")}GridItem() {Text(`C`).gridTextStyle2("#3067c8ff")}GridItem() {Text(`/`).gridTextStyle2("#4067c8ff")}GridItem() {Text(`X`).gridTextStyle2("#5067c8ff")}GridItem() {Text(`7`).gridTextStyle2("#6067c8ff")}GridItem() {Text(`8`).gridTextStyle2("#7067c8ff")}GridItem() {Text(`9`).gridTextStyle2("#8067c8ff")}GridItem() {Text(`-`).gridTextStyle2("#9067c8ff")}GridItem() {Text(`4`).gridTextStyle2("#A067c8ff")}GridItem() {Text(`5`).gridTextStyle2("#B067c8ff")}GridItem() {Text(`6`).gridTextStyle2("#C067c8ff")}GridItem() {Text(`+`).gridTextStyle2("#D067c8ff")}GridItem() {Text(`1`).gridTextStyle2("#E067c8ff")}GridItem() {Text(`2`).gridTextStyle2("#F067c8ff")}GridItem() {Text(`3`).gridTextStyle2("#F167c8ff")}GridItem() {Text(`=`).gridTextStyle2("#F267c8ff")}.rowStart(5).rowEnd(6).columnStart(3).columnEnd(3)GridItem() {Text(`0`).gridTextStyle2("#F367c8ff")}.columnStart(0).columnEnd(1)GridItem() {Text(`.`).gridTextStyle2("#F467c8ff")}}.margin(12).rowsGap(12).columnsGap(8).rowsTemplate('1fr 1fr 1fr 1fr 1fr 1fr 1fr').columnsTemplate('1fr 1fr 1fr 1fr')}.width('100%')}.height('80%')}
}@Extend(Text) function gridTextStyle2(value: ResourceColor) {.backgroundColor(value).width('100%').height('100%').fontSize(40).textAlign(TextAlign.Center).borderRadius(5)
}

         效果如下:

3.3、设置主轴方向

        使用Grid构建网格布局时,若没有设置行列数量与占比,可以通过layoutDirection可以设置网格布局的主轴方向,决定子组件的排列方式。此时可以结合minCount和maxCount属性来约束主轴方向上的网格数量。

图6 主轴方向示意图

        当前layoutDirection设置为Row时,先从左到右排列,排满一行再排一下一行。当前layoutDirection设置为Column时,先从上到下排列,排满一列再排一下一列,如上图所示。此时,将maxCount属性设为3,表示主轴方向上最大显示的网格单元数量为3。

@Entry
@Component
struct GridLayoutPage2 {@State array: Array<string> = ['1', '2', '3', '4', '5', '6', '7', '8', '9']build() {Row() {Column() {Grid() {ForEach(this.array, (item: string, index) => {GridItem() {Text(item).gridTextStyle_page2('#67c8ff')}}, item => item)}.rowsGap(12).columnsGap(8).margin(4).maxCount(3).minCount(3).layoutDirection(GridDirection.Column)}.width('100%')}.height('40%')}
}@Extend(Text) function gridTextStyle_page2(value: ResourceColor) {.backgroundColor(value).width('30%').height('30%').fontSize(22).textAlign(TextAlign.Center)
}

        效果如下:

说明

1. layoutDirection属性仅在不设置rowsTemplate和columnsTemplate时生效,此时元素在layoutDirection方向上排列。

2. 仅设置rowsTemplate时,Grid主轴为水平方向,交叉轴为垂直方向。

2. 仅设置columnsTemplate时,Grid主轴为垂直方向,交叉轴为水平方向。

 3.4、在网格布局中显示数据

        网格布局采用二维布局的方式组织其内部元素,如下图所示。

图7 通用办公服务

        Grid组件可以通过二维布局的方式显示一组GridItem子组件。

@Entry
@Component
struct GridLayoutPage3 {@State message: string = 'Hello World'build() {Row() {Column() {Grid() {GridItem() {Text('会议')}.backgroundColor('#1067c8ff')GridItem() {Text('签到')}.backgroundColor('#3067c8ff')GridItem() {Text('培训')}.backgroundColor('#5067c8ff')GridItem() {Text('打印')}.backgroundColor('#7067c8ff')}.rowsTemplate('1fr 1fr').columnsTemplate('1fr 1fr')}.width('100%').height('40%')}.height('100%').alignItems(VerticalAlign.Top)}
}

        对于内容结构相似的多个GridItem,通常更推荐使用循环渲染ForEach语句中嵌套GridItem的形式,来减少重复代码。

@Entry
@Component
struct GridLayoutPage3 {@State message: Bean[] = [{ title: '会议', color: '#1067c8ff' },{ title: '签到', color: '#3067c8ff' },{ title: '培训', color: '#5067c8ff' },{ title: '打印', color: '#7067c8ff' }]build() {Row() {Column() {Grid() {ForEach(this.message, (item: Bean) => {GridItem() {Text(item.title).backgroundColor(item.color).width('100%').height('100%').textAlign(TextAlign.Center)}}, item => JSON.stringify(item))}.rowsTemplate('1fr 1fr').columnsTemplate('1fr 1fr')}.width('100%').height('40%')}.height('100%').alignItems(VerticalAlign.Top)}
}class Bean {title: stringcolor: ResourceColor
}

        效果同上。

3.5、设置行列间距

        在两个网格单元之间的网格横向间距称为行间距,网格纵向间距称为列间距,如下图所示。

图8 网格的行列间距

        通过Grid的rowsGap和columnsGap可以设置网格布局的行列间距。

@Entry
@Component
struct GridLayoutPage3 {@State message: Bean[] = [{ title: '会议', color: '#1067c8ff' },{ title: '签到', color: '#3067c8ff' },{ title: '培训', color: '#5067c8ff' },{ title: '打印', color: '#7067c8ff' }]build() {Row() {Column() {Grid() {ForEach(this.message, (item: Bean) => {GridItem() {Text(item.title).backgroundColor(item.color).width('100%').height('100%').textAlign(TextAlign.Center)}}, item => JSON.stringify(item))}.rowsTemplate('1fr 1fr').columnsTemplate('1fr 1fr').rowsGap(10).columnsGap(10).margin(10)}.width('100%').height('40%').backgroundColor('#eee')}.height('100%').alignItems(VerticalAlign.Top)}
}class Bean {title: stringcolor: ResourceColor
}

        效果如下:

4、构建可滚动的网格布局

        可滚动的网格布局常用在文件管理、购物或视频列表等页面中,如下图所示。在设置Grid的行列数量与占比时,如果仅设置行、列数量与占比中的一个,即仅设置rowsTemplate或仅设置columnsTemplate属性,网格单元按照设置的方向排列,超出Grid显示区域后,Grid拥有可滚动能力。

图9 横向可滚动网格布局

        如果设置的是columnsTemplate,Grid的滚动方向为垂直方向;如果设置的是rowsTemplate,Grid的滚动方向为水平方向。

        如上图所示的横向可滚动网格布局,只要设置rowsTemplate属性的值且不设置columnsTemplate属性,当内容超出Grid组件宽度时,Grid可横向滚动进行内容展示。

@Entry
@Component
struct GridScrollLayoutPage {@State services: Array<string> = ['直播', '进口', '国外', '乡里', '本地', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I']color: ResourceColor[] = [Color.Blue, Color.Green, Color.Orange, Color.Pink, Color.Yellow]build() {Column({ space: 5 }) {Grid() {ForEach(this.services, (service: string, index) => {GridItem() {Text(service).backgroundColor(this.color[index % this.color.length]).fontColor(Color.White).width(72).height(72).fontSize(24).borderRadius(8).textAlign(TextAlign.Center).borderRadius(36)}.width('25%')}, service => service)}.rowsTemplate('1fr 1fr') // 只设置rowsTemplate属性,当内容超出Grid区域时,可水平滚动。.rowsGap(15).columnsGap(12).height('25%')}.borderColor(Color.Pink).borderWidth(1).borderRadius(8).margin(8).backgroundColor("#1067c8ff")}
}

5、实现简单的日历功能

import hilog from '@ohos.hilog';@Entry
@Component
struct CalendarLayoutPage {private scroller: Scroller = new Scroller()private headLabel: string[] = ['一', '二', '三', '四', '五', '六', '日']private curDate: Date;@State curDateStr: string = ''@State dateArray: number[] = []aboutToAppear() {let date = new Date();this.curDate = date;this.changeMonthData()}changeMonthData() {let monthLength = this.getMonthLength(this.curDate);this.dateArray = []for (let index = 0; index < monthLength; index++) {this.dateArray.push(index + 1)}this.curDateStr = `${this.curDate.getFullYear()}-${this.curDate.getMonth() + 1}`}private nextMonth() {this.curDate.setMonth(this.curDate.getMonth() + 1)}private prevMonth() {this.curDate.setMonth(this.curDate.getMonth() - 1)}private getMonthLength(date: Date): number {let copyDate = new Date(date.getFullYear(), date.getMonth() + 1, 0)return copyDate.getDate()}build() {Row() {Column() {Text(this.curDateStr).backgroundColor(Color.Pink).fontColor(Color.White).height(48).padding({ left: 24, right: 24 }).borderRadius(24)Row({ space: 8 }) {ForEach(this.headLabel, (item) => {Text(item).fontSize(14).layoutWeight(1).textAlign(TextAlign.Center).height('40%').borderRadius(26).backgroundColor('#67c8ff')}, item => JSON.stringify(item))}.height(52).backgroundColor('#999').margin({top: 24})Grid() {ForEach(this.dateArray, (item) => {GridItem() {Button(item + "").width(52).height(52).borderWidth(1).borderColor('#67c8ff')}}, item => JSON.stringify(item))}.columnsTemplate('1fr 1fr 1fr 1fr 1fr 1fr 1fr').columnsGap(5).rowsGap(5).margin({ top: 12 }).height('40%')Row({ space: 20 }) {Button('上一页').onClick(() => {this.prevMonth()this.changeMonthData()// this.scroller.scrollPage({//   next: false// })})Button('下一页').onClick(() => {this.nextMonth()this.changeMonthData()// this.scroller.scrollPage({//   next: true// })})}}.width('100%').backgroundColor('#eee').borderRadius(24)}.height('100%').alignItems(VerticalAlign.Top).margin({top: 48, left: 12, right: 12})}
}

        通过 @State dateArray来刷新UI,当点击前一页的时候,当前月份减少1,然后改变dateArray的数据,触发UI更新;点击下一页同理。效果如下:

6、性能优化

        与长列表的处理类似,循环渲染适用于数据量较小的布局场景,当构建具有大量网格项的可滚动网格布局时,推荐使用数据懒加载方式实现按需迭代加载数据,从而提升列表性能。

        关于按需加载优化的具体实现可参考数据懒加载章节中的示例。

        当使用懒加载方式渲染网格时,为了更好的滚动体验,减少滑动时出现白块,Grid组件中也可通过cachedCount属性设置GridItem的预加载数量,只在懒加载LazyForEach中生效。

        设置预加载数量后,会在Grid显示区域前后各缓存cachedCount*列数个GridItem,超出显示和缓存范围的GridItem会被释放。

 

Grid() {LazyForEach(this.dataSource, item => {GridItem() {...}})
}
.cachedCount(3)

说明

cachedCount的增加会增大UI的CPU、内存开销。使用时需要根据实际情况,综合性能和用户体验进行调整。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/611988.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

福禄电商平台与客服系统:无代码API连接与集成

无代码开发连接电商与客服系统 在电商和客服系统的运营中&#xff0c;技术门槛是非技术型企业面临的挑战之一。解决这个问题的关键是实现不同系统间的高效连接与集成。福禄提供的无代码开发解决方案让企业能够无需API开发即可实现系统之间的无缝连接和集成&#xff0c;帮助企业…

【SpringCloud】@Validated @Valid 不起作用 2.3.0及以上版本

依赖 <!--valid--> <dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-validation</artifactId></dependency>检查 版本问题&#xff0c;解决成功

【mysql】报错1349 - View‘s SELECT contains a subquery in the FROM clause

操作 创建视图的sql语句中有不支持子查询 mysql创建视图 select * from (select name,age from table_name where 11 and namea ) tb where 11 and type1问题 报错1349 - View’s SELECT contains a subquery in the FROM clause 原因 原因创建视图的sql语句中有不支持子查…

肺癌文献阅读

第一篇 Five-Year Survival Outcomes With Nivolumab Plus Ipilimumab Versus Chemotherapy as First-Line Treatment for Metastatic Non-Small-Cell Lung Cancer in CheckMate 227 IF:45.3 中科院分区:1区 医学 解析&#xff1a;标题就能很好知道实验结论了&#xff0c;学到…

软件测试|MySQL HAVING分组筛选详解

简介 在 MySQL 数据库中&#xff0c;HAVING 子句用于在使用 GROUP BY 子句对结果进行分组后&#xff0c;对分组后的数据进行筛选和过滤。它允许我们对分组后的结果应用聚合函数&#xff0c;并基于聚合函数的结果进行条件过滤&#xff0c;从而得到我们需要的最终结果集。本文将…

条款21:必须返回对象时,别妄想返回其引用

考虑一个表示有理数的类&#xff0c;其中包含一个计算两个有理数相乘的函数: class Rational { public:Rational(int numerator 0, int denominator 1) :n{ numerator }, d{ denominator }{} private:int n, d; // 分子和分母friend const Rational& operator*(const R…

Fiddler抓包 -- 使用教程

基本按钮 开启/停止&#xff1a;左下角的Capturing按钮 过滤&#xff1a;所有进程、浏览器、非浏览器、全都不抓 怎么抓到你想要的包 ①准备好前置操作 ②清空:通过上方的X按钮&#xff0c;或者按Ctrl X ③操作 ④停止抓包 怎么查看抓到的包的内容 状态码&#xff1a;…

K8S如何扩展副本集

Scaling ReplicaSets 扩展副本集 ReplicaSets are scaled up or down by updating the spec.replicas key on the ReplicaSet object stored in Kubernetes. When a ReplicaSet is scaled up, new Pods are submitted to the Kubernetes API using the Pod template defined o…

Web应用防火墙是什么?聊聊领先WAF解决方案

数字化进程的加速发展&#xff0c;Web站点及各类应用的数量呈现爆发式增长态势。与此同时&#xff0c;利用Web漏洞进行攻击的事件也与日俱增&#xff0c;黑客攻击手段不断升级&#xff0c;包括各种拟人化自动化攻击、API攻击以及0day攻击等&#xff0c;给Web应用安全防护带来了…

通过两台linux主机配置ssh实现互相免密登入

一 1.使用Xshell远程连接工工具生成公钥文件 2.生产密钥参数 3.生成公钥对 4.用户密钥信息 5.公钥注册 二 1.关闭服务端防火墙 ---systemctl stop firewalld 2.检查是否有/root/.ssh目录&#xff0c;没有则创建有则打开/root/.ssh/authorized_keys文件将密钥粘贴创建/ro…

数据结构之Radix和Trie

数据结构可视化演示链接&#xff0c;也就是视频中的网址 Radix树&#xff1a;压缩后的Trie树 Radix叫做基数树&#xff08;压缩树&#xff09;&#xff0c;就是有相同前缀的字符串&#xff0c;其前缀可以作为一个公共的父节点。同时在具体存储上&#xff0c;Radix树的处理是以…

13.Kubernetes应用部署完整流程:从Dockerfile到Ingress发布完整流程

本文以一个简单的Go应用Demo来演示Kubernetes应用部署的完整流程 1、Dockerfile多阶段构建 Dockerfile多阶段构建 [root@docker github]# git clone https://gitee.com/yxydde/http-dump.git [root@docker github]# cd http-dump/ [root@docker http-dump]# cat Dockerfile …

C#高级语法 Attribute特性详解和类型,方法,变量附加特性讲解

文章目录 前言相关资料Attribute特性个人原理理解特性的声明与使用类型特性运行结果&#xff1a; 找到类的Attribute属性方法特性和变量特性代码封装测试类TestService1TestService2TestService3 测试代码运行结果 对封装的代码进行优化封装代码测试代码运行结果&#xff08;和…

66、python - 代码仓库介绍

上一节,我们可以用自己手写的算法以及手动搭建的神经网络完成预测了,不知各位同学有没有自己尝试来预测一只猫或者一只狗,看看准确度如何? 本节应一位同学的建议,来介绍下 python 代码仓库的目录结构,以及每一部分是做什么? 我们这个小课的代码实战仓库链接为:cv_lea…

mysql中使用IN的注意事项

目录 前言注意事项 前言 在写sql语句过程中&#xff0c;难免会使用IN条件查询&#xff0c;那你知道使用IN要注意那些事项呢?下面我们就来一列举 注意事项 使用IN查询是否会使用索引 答&#xff1a;有时会使用&#xff0c;有时就不会使用。当IN 的范围小时会使用索引查询&…

MongDB集群部署和升级方案

******集群部署部分****** 主机信息mongodb集群 192.168.1.46 192.168.1.47 192.168.1.48 192.168.1.49 192.168.1.50 192.168.1.51 规划 sharding 1 192.168.1.46 192.168.1.47 192.168.1.48 端口 28111 sharding 2 192.168.1.49 192.168.1.50 192…

JavaScript与Swift的异同,python像vb6

其实很多主流的编程语言都是大同小异,魔改了一下罢了。 JavaScript与Swift一样&#xff0c;是动态语言类型&#xff0c;即不用指定变量类型&#xff0c;会根据赋值的内容动态的判断出它的类型。与Swift不同的是&#xff0c;JavaScript定义变量的时候&#xff0c;也不需要指定变…

【已解决】c语言为什么函数运算顺序从右往左

本博文主要源于笔者正在调试的c程序&#xff0c;c语言的函数运算顺序一直是从右往左int a 5;add(a,a);如果按照正常思维就是(5,5),运行结果确是(6,5),这是为什么呢 问题起源 对c语言的函数运算顺序产生怀疑 问题解释原因 函数从右到左依次入栈&#xff0c;出栈时可以很方便…

12.1SPI驱动框架

SPI硬件基础 总线拓扑结构 引脚含义 DO(MOSI)&#xff1a;Master Output, Slave Input&#xff0c; SPI主控用来发出数据&#xff0c;SPI从设备用来接收数据 DI(MISO) &#xff1a;Master Input, Slave Output&#xff0c; SPI主控用来发出数据&#xff0c;SPI从设备用来接收…

SpringMVC配置文件上传解析器实现文件上传项目实例

SpringMVC配置文件上传解析器实现文件上传项目实例 1、在pom.xml文件中添加相关依赖 <!--文件上传--> <dependency><groupId>commons-fileupload</groupId><artifactId>commons-fileupload</artifactId><version>1.3.1</versio…