常见情形
在很多手机商城的页面中会出现类似网格状一样的情况,例如:
-
京东
这里呢是采用Grid组件中的控制滚动,里面的rowsTemplate属性为一行且不对列的行数属性进行操作,这样的话就可以控制水平滑动了。
2.淘宝
这里就是极其简单的2*4的网格布局。
3.hao123
这里类似淘宝。
基本用法
Grid组件适用于布局由很多的行和列所组成、行列部分需要合并、需要滚动的场景。如下:
组件结构:
Grid(){
GridItem(){
//展示的内容
}
GridItem(){
//展示的内容
}
}
说明:1.Grid的子组件必须是GridItem组件,展示的内容放在GridItem中
2.GridItem只有一个子组件,跟初始代码块中build()一样,有且只能有一个子组件
3.Grid组件若是没有设置宽高,会默认适应其父组件的尺寸
样例:
@Entry
@Component
struct Index {
nums: number[] = Array.from({ length: 10 })//定义数组
build() {
Column() {
Grid() {
ForEach(this.nums, (item: number, index: number) => {//ForEach循环渲染
GridItem() {
Text(index.toString())//调用索引对GridItem进行编号
.fontSize(30)
.padding(5)
.backgroundColor(Color.Yellow)
}
})
}
}
.width("100%")
.height("100%")
}
运行结果:
由于没有对齐进行行列分布,所以所有GridItem()内的内容都展示在一行,下面让我来介绍一下Grid组件中常用的属性
基础属性
1.columnsTemplate 该属性用于设置网格布局的列数量
示例写法: .columnsTemplate('1fr 1fr 2fr')
从中fr出现的次数表示分成了几列,前面的数字则表示当前列所占用的份数
2.rowsTemplate 该属性用于设置网格布局的行数量
示例写法: .rowsTemplate('1fr 1fr 2fr')
从中fr出现的次数表示分成了几行,前面的数字则表示当前行所占用的份数
3.columnsGap 该属性用于控制列与列之间的间距
示例写法: .columnsGap(10)
4.rowsGap 该属性用于控制行与行1之间的间距
示例写法: .rowsGap(10)
练一练:
@Entry
@Component
struct TestPage {
build() {
Grid() {
this.GridItemBuilder('1', Color.Blue)
this.GridItemBuilder('2', Color.Blue)
this.GridItemBuilder('3', Color.Blue)
this.GridItemBuilder('4', Color.Blue)
this.GridItemBuilder('5', Color.Blue)
this.GridItemBuilder('6', Color.Blue)
}
.rowsTemplate('1fr 1fr 1fr')
.columnsTemplate('1fr 2fr 1fr')
.rowsGap(10)
.columnsGap(10)
.width('100%')
.height(300)
}
@Builder
GridItemBuilder(title: string, bgColor: ResourceColor) {
GridItem() {
Text(title)
.fontColor(Color.White)
.fontSize(30)
}
.backgroundColor('#0094ff')
}
}
这边解答采用了@Builder将GridItem进行了封装,这样看起来清晰很多。
合并行列
像下面左边的图片我们可以通过分配列占的份数来让他变宽,但下面右边的图片中的合并应该怎么样来做呢?这边则需要用到一些GridItem属性,让我来为大家讲解。
GridItem属性:
-
rowStart(number) 指定当前元素的起始行号
-
rowEnd(number) 指定当前元素的终点行号
-
columnStart(number) 指定当前元素的起始列号
-
columnEnd (number) 指定当前元素的终点行号
!!!这里的起始行号和列号是从1开始,比如你写的是四列,那么列号就是1,2,3,4
首先,我们先对所有元素进行编号,我这里就是直接用forEach中索引标记
然后,我们需要通过索引找到我们需要进行合并网格,这边我拿索引为2和3的网格举个例子。显然易见,这两个网格是列合并,行是没有变化,所以只需要找到其中一个,添加起始列号和终点列号就可以完成合并。
以此类推,索引4和8的网格是行合并,起始和终点行号分别为2,3,索引8,9,10就是类似2,3的列合并,起始和终点列号为2和4。
完整代码:
@Entry
@Component
struct GridPage03 {
nums: number[] = Array.from({ length: 12 })
build() {
Grid() {
ForEach(this.nums, (item: number, index: number) => {
if (index === 2) {
GridItem() {
Text(index + '')
.fontColor(Color.White)
.fontSize(30)
}
.backgroundColor('#9dc3e6')
.columnStart(3)
.columnEnd(4)
} else if (index === 3) {
GridItem() {
Text(index + '')
.fontColor(Color.White)
.fontSize(30)
}
.backgroundColor('#9dc3e6')
.rowStart(2)
.rowEnd(3)
} else {
GridItem() {
Text(index + '')
.fontColor(Color.White)
.fontSize(30)
}
.backgroundColor('#9dc3e6')
}
})
}
.columnsTemplate('1fr 1fr 1fr 1fr')
.rowsTemplate('1fr 1fr 1fr')
.width('100%')
.height(260)
.rowsGap(10)
.columnsGap(10)
.padding(10)
}
}
第二种方法:GridLayoutOptions
这个接口非常的新,也是刚更新不久,官方文档:developer.huawei.com/consumer/cn…
我们先来看下最常用的两个参数吧!
-
regularSize[number,number] 大小规则的GridItem在Grid中所占的行数和列数 ,目前呢只支持一行一列,也就是[1,1]
-
onGetRectByIndex 类型:(index:number)=>[rowStart,columnStart,rowSpan,columnSpan]
这里就是先通过索引找对应的GridItem,然后通过中括号里的四个参数来进行合并行列。
- rowStart 表达的含义跟第一种方法一样,表示当前元素行起始位置
- columnStart 也是如此,表示当前元素列起始位置
- rowSpan 这里Span表示跨度的意思,所以就是占用的行数
- columnSpan 表示占用的列数
完整代码:
@Entry
@Component
struct Index {
@State nums: string[] = ['0', '1', '2', '3', '4', '5']
layoutOption: GridLayoutOptions = {
regularSize: [1, 1],
onGetRectByIndex: (index: number) => {
if (index == 0) {
return [0, 0, 1, 1]
} else if (index == 1) {
return [0, 1, 2, 2]
} else if (index == 2) {
return [0, 3, 3, 3]
} else if (index == 3) {
return [3, 0, 3, 3]
} else if (index == 4) {
return [4, 3, 2, 2]
} else {
return [4, 5, 2, 1]
}
}
}
build() {
Grid(undefined, this.layoutOption) {
ForEach(this.nums, (item: string) => {
GridItem() {
Text(item)
.fontSize(16)
.backgroundColor('#f9ce93')
.width('100%')
.height("100%")
.textAlign(TextAlign.Center)
}
.height("100%")
.width('100%')
})
}
.columnsTemplate('1fr 1fr 1fr 1fr 1fr 1fr')
.rowsTemplate('1fr 1fr 1fr 1fr 1fr 1fr')
.columnsGap(10)
.rowsGap(10)
.width('90%')
.backgroundColor('#fcf0e2')
.height(300)
}
}
设置滚动
像文案开头京东那种就是可以滑动的网格布局,这里原理也是非常的简单,Grid中滑动不需要用到scroller控制器,只需要以下操作。
- 水平滚动:设置的是rowsTemplate,Grid的滚动方向为水平方向。
- 垂直滚动:设置的是columnsTemplate,Grid的滚动方向为垂直方向。
!!!这两不要同时设置,不然就滑动不了了
试一试:
@Entry
@Component
struct Day01_09_Grid05 {
// 长度为 10 每一项都为 undefined 的数组
list: string[] = Array.from({ length: 30 })
build() {
Column() {
Grid() {
ForEach(this.list, (item: string, index) => {
GridItem() {
Text((index + 1).toString())
.newExtend()
}
.padding(5)
.height('30%')
.width('25%')
})
}
.columnsTemplate('1fr 1fr 1fr') // 竖向滚动
// .rowsTemplate('1fr 1fr 1fr') // 横向滚动
.rowsGap(10)
.width('100%')
.height(300)
.border({ width: 1 })
.padding(5)
}
.width('100%')
.height('100%')
}
}
@Extend(Text)
function newExtend() {
.backgroundColor('#0094ff')
.width('100%')
.height('100%')
.fontSize(30)
.fontColor(Color.White)
.textAlign(TextAlign.Center)
}
当然大家会发现我们的滚动条有点丑,先别急我下面会讲!!
用代码控制滚动
这里很明显是用控制器和按钮来控制滑动了,先讲一下核心步骤吧。
-
创建 Scroller 对象
-
设置给 Grid
-
调用 Scroller 对象的 scrollPage 方法
练一练:// 创建 Scroller 对象 scroller: Scroller = new Scroller() // 设置给 Grid Grid(this.scroller) { // ... } // 通过代码控制 this.scroller.scrollPage({ next:true // 下一页 next:false // 上一页 })
答案:
@Entry
@Component
struct Index {
nums:number[]=Array.from({length:200})
scroller:Scroller=new Scroller()
build() {
Column(){
Grid(this.scroller){
ForEach(this.nums,(item:number,index:number)=>{
GridItem(){
Text((index+1).toString())
}
.backgroundColor('#0094ff')
.width("25%")
})
}
.padding(10)
.rowsTemplate('1fr 1fr 1fr 1fr')
.rowsGap(10)
.columnsGap(10)
.height(450)
Row(){
Button('上一页')
.width(100)
.onClick(()=>{
this.scroller.scrollPage({
next:false
})
})
Button('下一页')
.width(100)
.onClick(()=>{
this.scroller.scrollPage({
next:true
})
})
}
.width("100%")
.justifyContent(FlexAlign.SpaceAround)
}
.width("100%")
.height("100%")
}
}
自定义滚动条
使用属性调整
-
scrollBar 设置滚动条状态
BarState.off 关闭
BarState.on 常驻
BarState.auto 按需显示
-
scrollBarColor 设置滚动条的颜色
.scrollBarWidth(20) // 宽度 .scrollBarColor(Color.Orange) // 滚颜色
.scrollBar(BarState.Off) // 关闭
自定义组件
主要就是三个参数如下:
-
scroller 可控制组建的控制器
-
direction:ScrollBarDirection.Vertical/Horizontal 滚动条的方向
-
state 滚动条的状态
// 和 Grid 共用同一个 Scroller
scroller: Scroller = new Scroller()
// 和 Grid 共用同一个 Scroller
Grid(this.scroller){
// 略
}
// 和 Grid 共用同一个 Scroller
// 创建 ScrollBar 组件并设置属性
ScrollBar({
scroller: this.scroller,
direction: ScrollBarDirection.Horizontal // 方向
}) {
// 滚动内容 设置外观即可
Text()
}
// 设置外观
最后
小编在之前的鸿蒙系统扫盲中,有很多朋友给我留言,不同的角度的问了一些问题,我明显感觉到一点,那就是许多人参与鸿蒙开发,但是又不知道从哪里下手,因为体系杂乱无章,教授的人也多,无从选择。有很多小伙伴不知道学习哪些鸿蒙开发技术?不知道需要重点掌握哪些鸿蒙应用开发知识点?而且学习时频繁踩坑,最终浪费大量时间。所以有一份实用的鸿蒙(HarmonyOS NEXT)文档用来跟着学习是非常有必要的。
为了确保高效学习,建议规划清晰的学习路线,涵盖以下关键阶段:
希望这一份鸿蒙学习文档能够给大家带来帮助~
GitCode - 全球开发者的开源社区,开源代码托管平台
鸿蒙(HarmonyOS NEXT)最新学习路线
该路线图包含基础技能、就业必备技能、多媒体技术、六大电商APP、进阶高级技能、实战就业级设备开发,不仅补充了华为官网未涉及的解决方案
路线图适合人群:
IT开发人员:想要拓展职业边界
零基础小白:鸿蒙爱好者,希望从0到1学习,增加一项技能。
技术提升/进阶跳槽:发展瓶颈期,提升职场竞争力,快速掌握鸿蒙技术
2.视频教程+学习PDF文档
(鸿蒙语法ArkTS、TypeScript、ArkUI教程……)
纯血版鸿蒙全套学习文档(面试、文档、全套视频等)
鸿蒙APP开发必备
总结
参与鸿蒙开发,你要先认清适合你的方向,如果是想从事鸿蒙应用开发方向的话,可以参考本文的学习路径,简单来说就是:为了确保高效学习,建议规划清晰的学习路线