1# 网格布局 2 3网格布局(GridLayout)是自适应布局中一种重要的布局,具备较强的页面均分能力,子组件占比控制能力。 4通过[Grid](../reference/arkui-ts/ts-container-grid.md)容器组件和子组件[GridItem](../reference/arkui-ts/ts-container-griditem.md)实现, 5Grid用于设置网格布局相关参数,GridItem定义子组件相关特征。优势如下: 6 71. 容器组件尺寸发生变化时,所有子组件以及间距等比例调整,实现布局的自适应能力。 82. 支持自定义网格布局行数和列数,以及每行每列尺寸占比。 93. 支持设置网格布局中子组件的行列间距。 104. 支持设置子组件横跨几行或者几列。 11 12 13 14## 容器组件Grid设置 15 16### 行列数量占比 17通过Grid的组件的columnsTemplate和rowTemplate属性设置网格布局行列数量与尺寸占比。 18 19下面以columnsTemplate为例,介绍该属性的设置,该属性值是一个由多个空格和'数字+fr'间隔拼接的字符串,fr的个数即网格布局的列数,fr前面的数值大小,用于计算该列在网格布局宽度上的占比,最终决定该列的宽度。 20 21```ts 22struct GridExample { 23 @State Number: Array<string> = ['1', '2', '3', '4'] 24 25 build() { 26 Column({ space: 5 }) { 27 Grid() { 28 ForEach(this.Number, (num: string) => { 29 GridItem() { 30 Text(`列${num}`) 31 .fontSize(16) 32 .textAlign(TextAlign.Center) 33 .backgroundColor(0xd0d0d0) 34 .width('100%') 35 .height('100%') 36 .borderRadius(5) 37 } 38 }) 39 } 40 .columnsTemplate('1fr 1fr 1fr 1fr') 41 .rowsTemplate('1fr') 42 .columnsGap(10) 43 .rowsGap(20) 44 .width('90%') 45 .backgroundColor(0xF0F0F0) 46 .height(100) 47 }.width('100%') 48 } 49} 50``` 51 52定义了四个等分的列,每列宽度相等。 53 54```ts 55struct GridExample { 56 @State Number: Array<string> = ['1', '2', '3', '4'] 57 58 build() { 59 Column({ space: 5 }) { 60 Grid() { 61 ForEach(this.Number, (num: string) => { 62 GridItem() { 63 Text(`列${num}`) 64 .fontSize(16) 65 .textAlign(TextAlign.Center) 66 .backgroundColor(0xd0d0d0) 67 .width('100%') 68 .height('100%') 69 .borderRadius(5) 70 } 71 }) 72 } 73 .columnsTemplate('1fr 2fr 3fr 4fr') 74 .rowsTemplate('1fr') 75 .columnsGap(10) 76 .rowsGap(20) 77 .width('90%') 78 .backgroundColor(0xF0F0F0) 79 .height(100) 80 }.width('100%') 81 } 82} 83``` 84 85定义了四列,每列宽度比值为1:2:3:4。 86 87```ts 88struct GridExample { 89 @State Number: Array<string> = ['1', '2', '3'] 90 91 build() { 92 Column({ space: 5 }) { 93 Grid() { 94 ForEach(this.Number, (num: string) => { 95 GridItem() { 96 Text(`列${num}`) 97 .fontSize(16) 98 .textAlign(TextAlign.Center) 99 .backgroundColor(0xd0d0d0) 100 .width('100%') 101 .height('100%') 102 .borderRadius(5) 103 } 104 }) 105 } 106 .columnsTemplate('4fr 2fr 3fr') 107 .rowsTemplate('1fr') 108 .columnsGap(10) 109 .rowsGap(20) 110 .width('90%') 111 .backgroundColor(0xF0F0F0) 112 .height(100) 113 }.width('100%') 114 } 115} 116``` 117 118定义了三列,每列宽度比值为4:2:3。 119 120效果如下: 121 122 123 124### 排列方式 125 126通过layoutDirection可以设置网格布局的主轴方向,决定子组件的排列方式。 127可选值包括Row,RowReverse, Column, ColumnReverse四种情况。 128效果如下: 129 130 131 132### 行列间距 133 134columnsGap用于设置网格子组件GridItem垂直方向的间距,rowsGap用于设置GridItem水平方向的间距。 135 136```ts 137Grid() 138.columnsTemplate('1fr 1fr 1fr 1fr') 139.columnsGap(10) 140.rowsGap(20) 141``` 142 143 144 145上图中,设置网格布局子组件间的垂直间距为20,水平间距为10。 146 147## 网格子组件GridItem设置 148 149### 设置子组件占的行列数 150 151网格布局的行列标号从1开始,依次编号。 152 153子组件横跨多行时,通过rowStart设置子组件起始行编号,rowEnd设置终点行编号。当rowStart值与rowEnd值相同时,子组件只占一个网格。示例如下: 154 155```ts 156Grid() { 157 GridItem() { 158 Text('5') 159 .fontSize(16) 160 .textAlign(TextAlign.Center) 161 .textStyle() 162 }.rowStart(2).rowEnd(3) // 5子组件从第二行到第三行 163 164 GridItem() { 165 Text('4') 166 .fontSize(16) 167 .textAlign(TextAlign.Center) 168 .textStyle() 169 }.columnStart(4).columnEnd(5) // 4从第四列到第五列 170 171 GridItem() { 172 Text('6') 173 .fontSize(16) 174 .textAlign(TextAlign.Center) 175 .textStyle() 176 }.columnStart(2).columnEnd(4) // 6从第二列到第四列 177 178 GridItem() { 179 Text('9') 180 .fontSize(16) 181 .textAlign(TextAlign.Center) 182 .textStyle() 183 }.columnStart(3).columnEnd(4) // 从第三列到第四列 184} 185.columnsTemplate('1fr 1fr 1fr 1fr 1fr') 186.rowsTemplate('1fr 1fr 1fr') 187.columnsGap(10) 188.rowsGap(20) 189.width('90%') 190.backgroundColor(0xF0F0F0) 191.height('200vp') 192.layoutDirection(GridDirection.Column) 193``` 194 195 196 197## 场景示例 198 199使用grid布局实现一个计算器的排布效果,代码如下: 200 201```ts 202@Entry 203@Component 204struct GridExample { 205 @State Number: Array<string> = ['1', '2', '3', '+', '4', '5', '6', '-', '7', '8', '9', '*', '0', '.', '/'] 206 207 @Styles textStyle(){ 208 .backgroundColor(0xd0d0d0) 209 .width('100%') 210 .height('100%') 211 .borderRadius(5) 212 } 213 214 build() { 215 Column({ space: 5 }) { 216 Grid() { 217 GridItem() { 218 Text('0') 219 .fontSize(30) 220 .textStyle() 221 }.columnStart(1).columnEnd(4) 222 223 GridItem() { 224 Text('清空') 225 .fontSize(16) 226 .textAlign(TextAlign.Center) 227 .textStyle() 228 }.columnStart(1).columnEnd(2) 229 230 GridItem() { 231 Text('回退') 232 .fontSize(16) 233 .textAlign(TextAlign.Center) 234 .textStyle() 235 }.columnStart(3).columnEnd(4) 236 237 ForEach(this.Number, (day: string) => { 238 if (day === '0') { 239 GridItem() { 240 Text(day) 241 .fontSize(16) 242 .textAlign(TextAlign.Center) 243 .textStyle() 244 }.columnStart(1).columnEnd(2) 245 } else { 246 GridItem() { 247 Text(day) 248 .fontSize(16) 249 .textAlign(TextAlign.Center) 250 .textStyle() 251 } 252 } 253 }) 254 } 255 .columnsTemplate('1fr 1fr 1fr 1fr') 256 .rowsTemplate('2fr 1fr 1fr 1fr 1fr 1fr') 257 .columnsGap(10) 258 .rowsGap(15) 259 .width('90%') 260 .backgroundColor(0xF0F0F0) 261 .height('70%') 262 }.width('100%').margin({ top: 5 }) 263 } 264} 265``` 266 267在大屏设备上展示效果如下: 268 269 270 271在小屏设备下展示效果如下: 272 273 274