ArkUI 网格Grid构建行列布局,合并单元格,构建计算器界面
ArkUI提供了Grid和GridItem组件实现网格布局,支持行列占比设置、主轴方向控制、单元格合并等功能。Grid通过rowsTemplate和columnsTemplate定义行列数量与占比,若不设置则可通过layoutDirection指定主轴方向。GridItem可设置跨行跨列,通过onGetRectByIndex回调实现类似计算器按键的不规则布局。Grid组件支持条件渲染、循环渲染和懒
网格(Grid)
网格布局是由“行”和“列”分割的单元格所组成,网格布局具有较强的页面均分能力,子组件占比控制能力,是一种重要自适应布局,其使用场景有九宫格图片展示、日历、计算器等。
ArkUI提供了Grid容器组件和子组件GridItem,用于构建网格布局。Grid用于设置网格布局相关参数,GridItem定义子组件相关特征。Grid组件支持使用条件渲染、循环渲染、懒加载等方式生成子组件。
Grid组件为网格容器,其子组件必须是GridItem组件,两者的关系如下图所示。

基本使用
在使用Grid和GridItem进行布局时需要设置行和列的数量以及占比,通过.rowsTemplate("1fr 1fr 1fr")和.columnsTemplate('1fr 2fr 1fr')和进行列数量和占比设置,其中有几个fr就表示几列或者几行,前面的数字表示单元格占比。
如下图所示

代码如下
@Entry
@Component
struct Index {
@State gridItemList: number[] = [1, 2, 3, 4, 5, 6, 7, 8, 9]
build() {
Column() {
Grid() {
ForEach(this.gridItemList, (item: number) => {
GridItem() {
Row()
.width("100%").height("100%").backgroundColor('#A4C2E2')
}
})
}
.columnsTemplate('1fr 2fr 1fr') //3列,占比为1:2:1
.rowsTemplate("1fr 1fr 1fr") //3行,占比1:1:1
.columnsGap(10) //列间距
.rowsGap(10) //行间距
}.width("100%")
.backgroundColor("#dedede")
.padding(10)
}
}
[!Warning]
如果
Grid组件设置了宽高属性,则其尺寸为设置值。如果没有设置宽高属性,Grid组件的尺寸默认适应其父组件的尺寸。行、列数量与占比同时设置:
Grid只展示固定行列数的元素,其余元素不展示,且Grid不可滚动。(推荐使用该种布局方式)只设置行、列数量与占比中的一个:元素按照设置的方向进行排布,超出的元素可通过滚动的方式展示。
行列数量与占比都不设置:元素在布局方向上排布,其行列数由布局方向、单个网格的宽高等多个属性共同决定。超出行列容纳范围的元素不展示,且
Grid不可滚动。
采用下面配置测试以上情况,将Grid父组件的尺寸设置为300x300,Grid宽度自适应父组件高度,每一个GridItem尺寸设置为86.6x86.6,行间距、列间距设置为10,测试结果如下:

设置主轴排列方向
使用Grid构建网格布局时,若没有设置行列数量与占比,可以通过layoutDirection设置网格布局的主轴方向,决定子组件的排列方式,此时可以结合minCount和maxCount属性来约束主轴方向上的网格数量。
- 当前
layoutDirection设置为Row时,先从左到右排列,排满一行再排下一行。 - 当前
layoutDirection设置为Column时,先从上到下排列,排满一列再排下一列,
如上图所示。此时,将maxCount属性设为3,表示主轴方向上最大显示的网格单元数量为3。

@Entry
@Component
struct Index {
@State gridItemList: number[] = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12]
build() {
Column() {
Grid() {
ForEach(this.gridItemList, (item: number) => {
GridItem() {
Text(`${item}`)
.width(86.6).height(86.6).backgroundColor('#A4C2E2').textAlign(TextAlign.Center)
}
})
}
.layoutDirection(GridDirection.Row) //主轴水平向右(排完一排再排下一排)
//.layoutDirection(GridDirection.Column) //主轴向下(排完一列再排下一列)
.maxCount(3) //主轴方向的最大个数
.columnsGap(10) //列间距
.rowsGap(10) //行间距
}
.width(300)
.backgroundColor("#dedede")
.padding(10)
}
}
[!Warning]
layoutDirection属性仅在不设置rowsTemplate和columnsTemplate时生效。
合并单元格
在Grid组件中,可以通过创建Grid时传入合适的GridLayoutOptions实现如图所示的单个网格横跨多行或多列的场景。
参数:
-
通过
onGetRectByIndex返回的[rowStart,columnStart,rowSpan,columnSpan]来实现跨行跨列布局。-
rowStart和columnStart属性表示指定当前元素起始行号和起始列号 -
rowSpan和columnSpan属性表示指定当前元素的占用行数和占用列数。
-
示例:
例如计算器的按键布局就是常见的不均匀网格布局场景。如下图,计算器中的按键“0”和“=”,按键“0”横跨标号为0、1列,按键“=”横跨标号为3、4行。每一个GridItem都有一个索引标号,其行列标号从0开始,依次编号。

@Entry
@Component
struct Index {
//按键显示的文本
@State gridItemList: string[] = [
'CE', 'C', '/', 'X',
'7', '8', '9', '-',
'4', '5', '6', '+',
'1', '2', '3', '=',
'0', '.'
]
//滚动条,需要和Grid绑定
private scroller: Scroller = new Scroller()
//网格布局
private gridLayoutOptions: GridLayoutOptions = {
regularSize: [1, 1],
onGetRectByIndex: (index: number) => {
if (index === 15) {
return [4, 0, 1, 2]
}
if (index === 16) {
return [3, 2, 2, 1]
}
return [0, 0, 1, 1]
}
}
build() {
Column({ space: 10 }) {
Row() {
Text("123456")
.textAlign(TextAlign.End)
.fontSize(30)
.fontWeight(FontWeight.Bolder)
.fontColor(Color.White)
}
.width("100%")
.layoutWeight(1)
.justifyContent(FlexAlign.End)
.alignItems(VerticalAlign.Bottom)
.backgroundColor("#ffa0bcb4")
.padding(10)
.borderRadius(10)
Grid(this.scroller, this.gridLayoutOptions) {
ForEach(this.gridItemList, (item: string) => {
GridItem() {
Text(item)
.width("100%")
.height("100%")
.fontColor(Color.White)
.fontSize(26)
.textAlign(TextAlign.Center)
.fontWeight(FontWeight.Bolder)
.backgroundColor(Color.Grey)
.borderRadius(10)
}
})
}
.width("100%")
.height(460)
.columnsGap(10)
.rowsGap(10)
.columnsTemplate('1fr 1fr 1fr 1fr')
.rowsTemplate('1fr 1fr 1fr 1fr 1fr')
}
.width("100%")
.height("100%")
.backgroundColor("#dedede")
.padding(10)
}
}
控制滚动位置
Grid组件初始化时,可以绑定一个Scroller对象,用于进行滚动控制,例如通过Scroller对象的scrollPage方法进行翻页。

@Entry
@Component
struct Index {
@State gridItemList: number[] = []
private scroller: Scroller = new Scroller();
aboutToAppear(): void {
for (let i = 1; i <= 30; i++) {
this.gridItemList.push(i)
}
for (let i = 1; i <= 31; i++) {
this.gridItemList.push(i)
}
}
build() {
Column({ space: 10 }) {
Grid(this.scroller) {
ForEach(this.gridItemList, (item: number) => {
GridItem() {
Text(`${item}`)
.width(30).height(30).backgroundColor('#A4C2E2').textAlign(TextAlign.Center)
}
})
}
.width(300)
.height(200)
.backgroundColor("#dedede")
.columnsTemplate("1fr 1fr 1fr 1fr 1fr 1fr 1fr")
.columnsGap(10) //列间距
.rowsGap(10) //行间距
Row() {
Button("上一页").onClick(() => {
this.scroller.scrollPage({
next: false
})
})
Button("下一页").onClick(() => {
this.scroller.scrollPage({
next: true
})
})
}
}
.padding(10)
}
}
到此,Grid网格布局的使用就介绍完了🎉🎉🎉。
对鸿蒙感兴趣的同学,可以考免费取鸿蒙开发者认证
更多推荐


所有评论(0)