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