1# 线性布局 (Row/Column) 2 3 4## 概述 5 6线性布局(LinearLayout)是开发中最常用的布局,通过线性容器[Row](../reference/apis-arkui/arkui-ts/ts-container-row.md)和[Column](../reference/apis-arkui/arkui-ts/ts-container-column.md)构建。线性布局是其他布局的基础,其子元素在线性方向上(水平方向和垂直方向)依次排列。线性布局的排列方向由所选容器组件决定,Column容器内子元素按照垂直方向排列,Row容器内子元素按照水平方向排列。根据不同的排列方向,开发者可选择使用Row或Column容器创建线性布局。 7 8 9 **图1** Column容器内子元素排列示意图 10 11 12 13 14 **图2** Row容器内子元素排列示意图 15 16 17 18 19## 基本概念 20 21- 布局容器:具有布局能力的容器组件,可以承载其他元素作为其子元素,布局容器会对其子元素进行尺寸计算和布局排列。 22 23- 布局子元素:布局容器内部的元素。 24 25- 主轴:线性布局容器在布局方向上的轴线,子元素默认沿主轴排列。Row容器主轴为水平方向,Column容器主轴为垂直方向。 26 27- 交叉轴:垂直于主轴方向的轴线。Row容器交叉轴为垂直方向,Column容器交叉轴为水平方向。 28 29- 间距:布局子元素的间距。 30 31 32## 布局子元素在排列方向上的间距 33 34在布局容器内,可以通过space属性设置排列方向上子元素的间距,使各子元素在排列方向上有等间距效果。 35 36 37### Column容器内排列方向上的间距 38 39 **图3** Column容器内排列方向的间距图 40 41 42 43```ts 44Column({ space: 20 }) { 45 Text('space: 20').fontSize(15).fontColor(Color.Gray).width('90%') 46 Row().width('90%').height(50).backgroundColor(0xF5DEB3) 47 Row().width('90%').height(50).backgroundColor(0xD2B48C) 48 Row().width('90%').height(50).backgroundColor(0xF5DEB3) 49}.width('100%') 50``` 51 52 53 54 55 56### Row容器内排列方向上的间距 57 58 **图4** Row容器内排列方向的间距图 59 60 61 62 63```ts 64Row({ space: 35 }) { 65 Text('space: 35').fontSize(15).fontColor(Color.Gray) 66 Row().width('10%').height(150).backgroundColor(0xF5DEB3) 67 Row().width('10%').height(150).backgroundColor(0xD2B48C) 68 Row().width('10%').height(150).backgroundColor(0xF5DEB3) 69}.width('90%') 70``` 71 72 73 74 75## 布局子元素在交叉轴上的对齐方式 76 77在布局容器内,可以通过alignItems属性设置子元素在交叉轴(排列方向的垂直方向)上的对齐方式。且在各类尺寸屏幕中,表现一致。其中,交叉轴为垂直方向时,取值为[VerticalAlign](../reference/apis-arkui/arkui-ts/ts-appendix-enums.md#verticalalign)类型,水平方向取值为[HorizontalAlign](../reference/apis-arkui/arkui-ts/ts-appendix-enums.md#horizontalalign)类型。 78 79alignSelf属性用于控制单个子元素在容器交叉轴上的对齐方式,其优先级高于alignItems属性,如果设置了alignSelf属性,则在单个子元素上会覆盖alignItems属性。 80 81 82### Column容器内子元素在水平方向上的排列 83 84 **图5** Column容器内子元素在水平方向上的排列图 85 86 87 88- HorizontalAlign.Start:子元素在水平方向左对齐。 89 90 ```ts 91 Column({}) { 92 Column() { 93 }.width('80%').height(50).backgroundColor(0xF5DEB3) 94 95 Column() { 96 }.width('80%').height(50).backgroundColor(0xD2B48C) 97 98 Column() { 99 }.width('80%').height(50).backgroundColor(0xF5DEB3) 100 }.width('100%').alignItems(HorizontalAlign.Start).backgroundColor('rgb(242,242,242)') 101 ``` 102 103  104 105- HorizontalAlign.Center:子元素在水平方向居中对齐。 106 107 ```ts 108 Column({}) { 109 Column() { 110 }.width('80%').height(50).backgroundColor(0xF5DEB3) 111 112 Column() { 113 }.width('80%').height(50).backgroundColor(0xD2B48C) 114 115 Column() { 116 }.width('80%').height(50).backgroundColor(0xF5DEB3) 117 }.width('100%').alignItems(HorizontalAlign.Center).backgroundColor('rgb(242,242,242)') 118 ``` 119 120  121 122- HorizontalAlign.End:子元素在水平方向右对齐。 123 124 ```ts 125 Column({}) { 126 Column() { 127 }.width('80%').height(50).backgroundColor(0xF5DEB3) 128 129 Column() { 130 }.width('80%').height(50).backgroundColor(0xD2B48C) 131 132 Column() { 133 }.width('80%').height(50).backgroundColor(0xF5DEB3) 134 }.width('100%').alignItems(HorizontalAlign.End).backgroundColor('rgb(242,242,242)') 135 ``` 136 137  138 139 140### Row容器内子元素在垂直方向上的排列 141 142 **图6** Row容器内子元素在垂直方向上的排列图 143 144 145 146- VerticalAlign.Top:子元素在垂直方向顶部对齐。 147 148 ```ts 149 Row({}) { 150 Column() { 151 }.width('20%').height(30).backgroundColor(0xF5DEB3) 152 153 Column() { 154 }.width('20%').height(30).backgroundColor(0xD2B48C) 155 156 Column() { 157 }.width('20%').height(30).backgroundColor(0xF5DEB3) 158 }.width('100%').height(200).alignItems(VerticalAlign.Top).backgroundColor('rgb(242,242,242)') 159 ``` 160 161  162 163- VerticalAlign.Center:子元素在垂直方向居中对齐。 164 165 ```ts 166 Row({}) { 167 Column() { 168 }.width('20%').height(30).backgroundColor(0xF5DEB3) 169 170 Column() { 171 }.width('20%').height(30).backgroundColor(0xD2B48C) 172 173 Column() { 174 }.width('20%').height(30).backgroundColor(0xF5DEB3) 175 }.width('100%').height(200).alignItems(VerticalAlign.Center).backgroundColor('rgb(242,242,242)') 176 ``` 177 178  179 180- VerticalAlign.Bottom:子元素在垂直方向底部对齐。 181 182 ```ts 183 Row({}) { 184 Column() { 185 }.width('20%').height(30).backgroundColor(0xF5DEB3) 186 187 Column() { 188 }.width('20%').height(30).backgroundColor(0xD2B48C) 189 190 Column() { 191 }.width('20%').height(30).backgroundColor(0xF5DEB3) 192 }.width('100%').height(200).alignItems(VerticalAlign.Bottom).backgroundColor('rgb(242,242,242)') 193 ``` 194 195  196 197 198## 布局子元素在主轴上的排列方式 199 200在布局容器内,可以通过justifyContent属性设置子元素在容器主轴上的排列方式。可以从主轴起始位置开始排布,也可以从主轴结束位置开始排布,或者均匀分割主轴的空间。 201 202 203### Column容器内子元素在垂直方向上的排列 204 205 **图7** Column容器内子元素在垂直方向上的排列图 206 207 208 209- justifyContent(FlexAlign.Start):元素在垂直方向首端对齐,第一个元素与行首对齐,同时后续的元素与前一个对齐。 210 211 ```ts 212 Column({}) { 213 Column() { 214 }.width('80%').height(50).backgroundColor(0xF5DEB3) 215 216 Column() { 217 }.width('80%').height(50).backgroundColor(0xD2B48C) 218 219 Column() { 220 }.width('80%').height(50).backgroundColor(0xF5DEB3) 221 }.width('100%').height(300).backgroundColor('rgb(242,242,242)').justifyContent(FlexAlign.Start) 222 ``` 223 224  225 226- justifyContent(FlexAlign.Center):元素在垂直方向中心对齐,第一个元素与行首的距离与最后一个元素与行尾距离相同。 227 228 ```ts 229 Column({}) { 230 Column() { 231 }.width('80%').height(50).backgroundColor(0xF5DEB3) 232 233 Column() { 234 }.width('80%').height(50).backgroundColor(0xD2B48C) 235 236 Column() { 237 }.width('80%').height(50).backgroundColor(0xF5DEB3) 238 }.width('100%').height(300).backgroundColor('rgb(242,242,242)').justifyContent(FlexAlign.Center) 239 ``` 240 241  242 243- justifyContent(FlexAlign.End):元素在垂直方向尾部对齐,最后一个元素与行尾对齐,其他元素与后一个对齐。 244 245 ```ts 246 Column({}) { 247 Column() { 248 }.width('80%').height(50).backgroundColor(0xF5DEB3) 249 250 Column() { 251 }.width('80%').height(50).backgroundColor(0xD2B48C) 252 253 Column() { 254 }.width('80%').height(50).backgroundColor(0xF5DEB3) 255 }.width('100%').height(300).backgroundColor('rgb(242,242,242)').justifyContent(FlexAlign.End) 256 ``` 257 258  259 260- justifyContent(FlexAlign.SpaceBetween):垂直方向均匀分配元素,相邻元素之间距离相同。第一个元素与行首对齐,最后一个元素与行尾对齐。 261 262 ```ts 263 Column({}) { 264 Column() { 265 }.width('80%').height(50).backgroundColor(0xF5DEB3) 266 267 Column() { 268 }.width('80%').height(50).backgroundColor(0xD2B48C) 269 270 Column() { 271 }.width('80%').height(50).backgroundColor(0xF5DEB3) 272 }.width('100%').height(300).backgroundColor('rgb(242,242,242)').justifyContent(FlexAlign.SpaceBetween) 273 ``` 274 275  276 277- justifyContent(FlexAlign.SpaceAround):垂直方向均匀分配元素,相邻元素之间距离相同。第一个元素到行首的距离和最后一个元素到行尾的距离是相邻元素之间距离的一半。 278 279 ```ts 280 Column({}) { 281 Column() { 282 }.width('80%').height(50).backgroundColor(0xF5DEB3) 283 284 Column() { 285 }.width('80%').height(50).backgroundColor(0xD2B48C) 286 287 Column() { 288 }.width('80%').height(50).backgroundColor(0xF5DEB3) 289 }.width('100%').height(300).backgroundColor('rgb(242,242,242)').justifyContent(FlexAlign.SpaceAround) 290 ``` 291 292  293 294- justifyContent(FlexAlign.SpaceEvenly):垂直方向均匀分配元素,相邻元素之间的距离、第一个元素与行首的间距、最后一个元素到行尾的间距都完全一样。 295 296 ```ts 297 Column({}) { 298 Column() { 299 }.width('80%').height(50).backgroundColor(0xF5DEB3) 300 301 Column() { 302 }.width('80%').height(50).backgroundColor(0xD2B48C) 303 304 Column() { 305 }.width('80%').height(50).backgroundColor(0xF5DEB3) 306 }.width('100%').height(300).backgroundColor('rgb(242,242,242)').justifyContent(FlexAlign.SpaceEvenly) 307 ``` 308 309  310 311 312### Row容器内子元素在水平方向上的排列 313 314 **图8** Row容器内子元素在水平方向上的排列图 315 316 317 318- justifyContent(FlexAlign.Start):元素在水平方向首端对齐,第一个元素与行首对齐,同时后续的元素与前一个对齐。 319 320 ```ts 321 Row({}) { 322 Column() { 323 }.width('20%').height(30).backgroundColor(0xF5DEB3) 324 325 Column() { 326 }.width('20%').height(30).backgroundColor(0xD2B48C) 327 328 Column() { 329 }.width('20%').height(30).backgroundColor(0xF5DEB3) 330 }.width('100%').height(200).backgroundColor('rgb(242,242,242)').justifyContent(FlexAlign.Start) 331 ``` 332 333  334 335- justifyContent(FlexAlign.Center):元素在水平方向中心对齐,第一个元素与行首的距离与最后一个元素与行尾距离相同。 336 337 ```ts 338 Row({}) { 339 Column() { 340 }.width('20%').height(30).backgroundColor(0xF5DEB3) 341 342 Column() { 343 }.width('20%').height(30).backgroundColor(0xD2B48C) 344 345 Column() { 346 }.width('20%').height(30).backgroundColor(0xF5DEB3) 347 }.width('100%').height(200).backgroundColor('rgb(242,242,242)').justifyContent(FlexAlign.Center) 348 ``` 349 350  351 352- justifyContent(FlexAlign.End):元素在水平方向尾部对齐,最后一个元素与行尾对齐,其他元素与后一个对齐。 353 354 ```ts 355 Row({}) { 356 Column() { 357 }.width('20%').height(30).backgroundColor(0xF5DEB3) 358 359 Column() { 360 }.width('20%').height(30).backgroundColor(0xD2B48C) 361 362 Column() { 363 }.width('20%').height(30).backgroundColor(0xF5DEB3) 364 }.width('100%').height(200).backgroundColor('rgb(242,242,242)').justifyContent(FlexAlign.End) 365 ``` 366 367  368 369- justifyContent(FlexAlign.SpaceBetween):水平方向均匀分配元素,相邻元素之间距离相同。第一个元素与行首对齐,最后一个元素与行尾对齐。 370 371 ```ts 372 Row({}) { 373 Column() { 374 }.width('20%').height(30).backgroundColor(0xF5DEB3) 375 376 Column() { 377 }.width('20%').height(30).backgroundColor(0xD2B48C) 378 379 Column() { 380 }.width('20%').height(30).backgroundColor(0xF5DEB3) 381 }.width('100%').height(200).backgroundColor('rgb(242,242,242)').justifyContent(FlexAlign.SpaceBetween) 382 ``` 383 384  385 386- justifyContent(FlexAlign.SpaceAround):水平方向均匀分配元素,相邻元素之间距离相同。第一个元素到行首的距离和最后一个元素到行尾的距离是相邻元素之间距离的一半。 387 388 ```ts 389 Row({}) { 390 Column() { 391 }.width('20%').height(30).backgroundColor(0xF5DEB3) 392 393 Column() { 394 }.width('20%').height(30).backgroundColor(0xD2B48C) 395 396 Column() { 397 }.width('20%').height(30).backgroundColor(0xF5DEB3) 398 }.width('100%').height(200).backgroundColor('rgb(242,242,242)').justifyContent(FlexAlign.SpaceAround) 399 ``` 400 401  402 403- justifyContent(FlexAlign.SpaceEvenly):水平方向均匀分配元素,相邻元素之间的距离、第一个元素与行首的间距、最后一个元素到行尾的间距都完全一样。 404 405 ```ts 406 Row({}) { 407 Column() { 408 }.width('20%').height(30).backgroundColor(0xF5DEB3) 409 410 Column() { 411 }.width('20%').height(30).backgroundColor(0xD2B48C) 412 413 Column() { 414 }.width('20%').height(30).backgroundColor(0xF5DEB3) 415 }.width('100%').height(200).backgroundColor('rgb(242,242,242)').justifyContent(FlexAlign.SpaceEvenly) 416 ``` 417 418  419 420 421## 自适应拉伸 422 423在线性布局下,常用空白填充组件[Blank](../reference/apis-arkui/arkui-ts/ts-basic-components-blank.md),在容器主轴方向自动填充空白空间,达到自适应拉伸效果。Row和Column作为容器,只需要添加宽高为百分比,当屏幕宽高发生变化时,会产生自适应效果。 424 425 426```ts 427@Entry 428@Component 429struct BlankExample { 430 build() { 431 Column() { 432 Row() { 433 Text('Bluetooth').fontSize(18) 434 Blank() 435 Toggle({ type: ToggleType.Switch, isOn: true }) 436 }.backgroundColor(0xFFFFFF).borderRadius(15).padding({ left: 12 }).width('100%') 437 }.backgroundColor(0xEFEFEF).padding(20).width('100%') 438 } 439} 440``` 441 442 **图9** 竖屏 443 444 445 446 **图10** 横屏 447 448 449 450 451## 自适应缩放 452 453自适应缩放是指子元素随容器尺寸的变化而按照预设的比例自动调整尺寸,适应各种不同大小的设备。在线性布局中,可以使用以下两种方法实现自适应缩放。 454 455 456- 父容器尺寸确定时,使用layoutWeight属性设置子元素和兄弟元素在主轴上的权重,忽略元素本身尺寸设置,使它们在任意尺寸的设备下自适应占满剩余空间。 457 458 ```ts 459 @Entry 460 @Component 461 struct layoutWeightExample { 462 build() { 463 Column() { 464 Text('1:2:3').width('100%') 465 Row() { 466 Column() { 467 Text('layoutWeight(1)') 468 .textAlign(TextAlign.Center) 469 }.layoutWeight(1).backgroundColor(0xF5DEB3).height('100%') 470 471 Column() { 472 Text('layoutWeight(2)') 473 .textAlign(TextAlign.Center) 474 }.layoutWeight(2).backgroundColor(0xD2B48C).height('100%') 475 476 Column() { 477 Text('layoutWeight(3)') 478 .textAlign(TextAlign.Center) 479 }.layoutWeight(3).backgroundColor(0xF5DEB3).height('100%') 480 481 }.backgroundColor(0xffd306).height('30%') 482 483 Text('2:5:3').width('100%') 484 Row() { 485 Column() { 486 Text('layoutWeight(2)') 487 .textAlign(TextAlign.Center) 488 }.layoutWeight(2).backgroundColor(0xF5DEB3).height('100%') 489 490 Column() { 491 Text('layoutWeight(5)') 492 .textAlign(TextAlign.Center) 493 }.layoutWeight(5).backgroundColor(0xD2B48C).height('100%') 494 495 Column() { 496 Text('layoutWeight(3)') 497 .textAlign(TextAlign.Center) 498 }.layoutWeight(3).backgroundColor(0xF5DEB3).height('100%') 499 }.backgroundColor(0xffd306).height('30%') 500 } 501 } 502 } 503 ``` 504 505 **图11** 横屏 506 507  508 509 **图12** 竖屏 510 511  512 513- 父容器尺寸确定时,使用百分比设置子元素和兄弟元素的宽度,使他们在任意尺寸的设备下保持固定的自适应占比。 514 515 ```ts 516 @Entry 517 @Component 518 struct WidthExample { 519 build() { 520 Column() { 521 Row() { 522 Column() { 523 Text('left width 20%') 524 .textAlign(TextAlign.Center) 525 }.width('20%').backgroundColor(0xF5DEB3).height('100%') 526 527 Column() { 528 Text('center width 50%') 529 .textAlign(TextAlign.Center) 530 }.width('50%').backgroundColor(0xD2B48C).height('100%') 531 532 Column() { 533 Text('right width 30%') 534 .textAlign(TextAlign.Center) 535 }.width('30%').backgroundColor(0xF5DEB3).height('100%') 536 }.backgroundColor(0xffd306).height('30%') 537 } 538 } 539 } 540 ``` 541 542 **图13** 横屏 543 544  545 546 **图14** 竖屏 547 548  549 550 551## 自适应延伸 552 553自适应延伸是指在不同尺寸设备下,当页面的内容超出屏幕大小而无法完全显示时,可以通过滚动条进行拖动展示。这种方法适用于线性布局中内容无法一屏展示的场景。通常有以下两种实现方式。 554 555- [在List中添加滚动条](arkts-layout-development-create-list.md#添加滚动条):当List子项过多一屏放不下时,可以将每一项子元素放置在不同的组件中,通过滚动条进行拖动展示。可以通过scrollBar属性设置滚动条的常驻状态,edgeEffect属性设置拖动到内容最末端的回弹效果。 556 557- 使用Scroll组件:在线性布局中,开发者可以进行垂直方向或者水平方向的布局。当一屏无法完全显示时,可以在Column或Row组件的外层包裹一个可滚动的容器组件Scroll来实现可滑动的线性布局。 558 垂直方向布局中使用Scroll组件: 559 560 ```ts 561 @Entry 562 @Component 563 struct ScrollExample { 564 scroller: Scroller = new Scroller(); 565 private arr: number[] = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]; 566 567 build() { 568 Scroll(this.scroller) { 569 Column() { 570 ForEach(this.arr, (item?:number|undefined) => { 571 if(item){ 572 Text(item.toString()) 573 .width('90%') 574 .height(150) 575 .backgroundColor(0xFFFFFF) 576 .borderRadius(15) 577 .fontSize(16) 578 .textAlign(TextAlign.Center) 579 .margin({ top: 10 }) 580 } 581 }, (item:number) => item.toString()) 582 }.width('100%') 583 } 584 .backgroundColor(0xDCDCDC) 585 .scrollable(ScrollDirection.Vertical) // 滚动方向为垂直方向 586 .scrollBar(BarState.On) // 滚动条常驻显示 587 .scrollBarColor(Color.Gray) // 滚动条颜色 588 .scrollBarWidth(10) // 滚动条宽度 589 .edgeEffect(EdgeEffect.Spring) // 滚动到边沿后回弹 590 } 591 } 592 ``` 593 594  595 596 水平方向布局中使用Scroll组件: 597 598 599 ```ts 600 @Entry 601 @Component 602 struct ScrollExample { 603 scroller: Scroller = new Scroller(); 604 private arr: number[] = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]; 605 606 build() { 607 Scroll(this.scroller) { 608 Row() { 609 ForEach(this.arr, (item?:number|undefined) => { 610 if(item){ 611 Text(item.toString()) 612 .height('90%') 613 .width(150) 614 .backgroundColor(0xFFFFFF) 615 .borderRadius(15) 616 .fontSize(16) 617 .textAlign(TextAlign.Center) 618 .margin({ left: 10 }) 619 } 620 }) 621 }.height('100%') 622 } 623 .backgroundColor(0xDCDCDC) 624 .scrollable(ScrollDirection.Horizontal) // 滚动方向为水平方向 625 .scrollBar(BarState.On) // 滚动条常驻显示 626 .scrollBarColor(Color.Gray) // 滚动条颜色 627 .scrollBarWidth(10) // 滚动条宽度 628 .edgeEffect(EdgeEffect.Spring) // 滚动到边沿后回弹 629 } 630 } 631 ``` 632 633  634