1# 线性布局 2 3线性布局(LinearLayout)是开发中最常用的布局。线性布局的子组件在线性方向上(水平方向和垂直方向)依次排列。 4 5通过线性容器[Row](../reference/arkui-ts/ts-container-row.md)和[Column](../reference/arkui-ts/ts-container-column.md)实现线性布局。Column容器内子组件按照垂直方向排列,Row组件中,子组件按照水平方向排列。 6 7## 线性布局的排列 8 9线性布局的排列方向由所选容器组件决定。根据不同的排列方向,选择使用Row或Column容器创建线性布局,通过调整space,alignItems,justifyContent属性调整子组件的间距,水平垂直方向的对齐方式。 101. 通过space参数设置主轴(排列方向)上子组件的间距。达到各子组件在排列方向上的等间距效果。 112. 通过alignItems属性设置子组件在交叉轴(排列方向的垂直方向)的对齐方式。且在各类尺寸屏幕中,表现一致。其中,交叉轴为垂直方向时,取值为[VerticalAlign类型](../reference/arkui-ts/ts-appendix-enums.md#verticalalign),水平方向取值为[HorizontalAlign类型](../reference/arkui-ts/ts-appendix-enums.md#horizontalalign)。 123. 通过justifyContent属性设置子组件在主轴(排列方向)上的对齐方式。实现布局的自适应均分能力。取值为[FlexAlign类型](../reference/arkui-ts/ts-appendix-enums.md#flexalign)。 13 14具体使用以及效果如下表所示: 15 16|属性名|描述|Row效果图|Column效果图| 17|------|---------------------------|----------------------------|---------------------------| 18|space |- 横向布局中各子组件的在水平方向的间距<br> - 纵向布局中个子组件垂直方向间距|  |  | 19|alignItems |容器排列方向的垂直方向上,子组件在父容器中的对齐方式| || 20|justifyContent |容器排列方向上,子组件在父容器中的对齐方式 | || 21 22## 自适应拉伸 23 24在线性布局下,常用空白填充组件[Blank](../reference/arkui-ts/ts-basic-components-blank.md),在容器主轴方向自动填充空白空间,达到自适应拉伸效果。 25 26```ts 27@Entry 28@Component 29struct BlankExample { 30 build() { 31 Column() { 32 Row() { 33 Text('Bluetooth').fontSize(18) 34 Blank() 35 Toggle({ type: ToggleType.Switch, isOn: true }) 36 }.backgroundColor(0xFFFFFF).borderRadius(15).padding({ left: 12 }).width('100%') 37 }.backgroundColor(0xEFEFEF).padding(20).width('100%') 38 } 39} 40``` 41 42 43 44## 自适应缩放 45 46自适应缩放是指在各种不同大小设备中,子组件按照预设的比例,尺寸随容器尺寸的变化而变化。在线性布局中有下列方法实现: 47 481. 父容器尺寸确定时,设置了layoutWeight属性的子组件与兄弟元素占主轴尺寸按照权重进行分配,忽略元素本身尺寸设置,在任意尺寸设备下,自适应占满剩余空间。 49 50 ```ts 51 @Entry 52 @Component 53 struct layoutWeightExample { 54 build() { 55 Column() { 56 Text('1:2:3').width('100%') 57 Row() { 58 Column() { 59 Text('layoutWeight(1)') 60 .textAlign(TextAlign.Center) 61 }.layoutWeight(2).backgroundColor(0xffd306).height('100%') 62 63 Column() { 64 Text('layoutWeight(2)') 65 .textAlign(TextAlign.Center) 66 }.layoutWeight(4).backgroundColor(0xffed97).height('100%') 67 68 Column() { 69 Text('layoutWeight(6)') 70 .textAlign(TextAlign.Center) 71 }.layoutWeight(6).backgroundColor(0xffd306).height('100%') 72 73 }.backgroundColor(0xffd306).height('30%') 74 75 Text('2:5:3').width('100%') 76 Row() { 77 Column() { 78 Text('layoutWeight(2)') 79 .textAlign(TextAlign.Center) 80 }.layoutWeight(2).backgroundColor(0xffd306).height('100%') 81 82 Column() { 83 Text('layoutWeight(5)') 84 .textAlign(TextAlign.Center) 85 }.layoutWeight(5).backgroundColor(0xffed97).height('100%') 86 87 Column() { 88 Text('layoutWeight(3)') 89 .textAlign(TextAlign.Center) 90 }.layoutWeight(3).backgroundColor(0xffd306).height('100%') 91 }.backgroundColor(0xffd306).height('30%') 92 } 93 } 94 } 95 ``` 96 97  98 99 1003. 父容器尺寸确定时,使用百分比设置子组件以及兄弟组件的width宽度,可以保证各自元素在任意尺寸下的自适应占比。 101 102 ```ts 103 @Entry 104 @Component 105 struct WidthExample { 106 build() { 107 Column() { 108 Row() { 109 Column() { 110 Text('left width 20%') 111 .textAlign(TextAlign.Center) 112 }.width('20%').backgroundColor(0xffd306).height('100%') 113 114 Column() { 115 Text('center width 50%') 116 .textAlign(TextAlign.Center) 117 }.width('50%').backgroundColor(0xffed97).height('100%') 118 119 Column() { 120 Text('right width 30%') 121 .textAlign(TextAlign.Center) 122 }.width('30%').backgroundColor(0xffd306).height('100%') 123 }.backgroundColor(0xffd306).height('30%') 124 } 125 } 126 } 127 ``` 128 129  130 131 上例中,在任意大小的设备中,子组件的宽度占比固定。 132 133## 定位能力 134- 相对定位 135 136 使用组件的[offset属性](../reference/arkui-ts/ts-universal-attributes-location.md)可以实现相对定位,设置元素相对于自身的偏移量。设置该属性,不影响父容器布局,仅在绘制时进行位置调整。使用线性布局和offset可以实现大部分布局的开发。 137 138 ```ts 139 @Entry 140 @Component 141 struct OffsetExample { 142 @Styles eleStyle() { 143 .size({ width: 120, height: '50' }) 144 .backgroundColor(0xbbb2cb) 145 .border({ width: 1 }) 146 } 147 148 build() { 149 Column({ space: 20 }) { 150 Row() { 151 Text('1').size({ width: '15%', height: '50' }).backgroundColor(0xdeb887).border({ width: 1 }).fontSize(16) 152 Text('2 offset(15, 30)') 153 .eleStyle() 154 .fontSize(16) 155 .align(Alignment.Start) 156 .offset({ x: 15, y: 30 }) 157 Text('3').size({ width: '15%', height: '50' }).backgroundColor(0xdeb887).border({ width: 1 }).fontSize(16) 158 Text('4 offset(-10%, 20%)') 159 .eleStyle() 160 .fontSize(16) 161 .offset({ x: '-5%', y: '20%' }) 162 }.width('90%').height(150).border({ width: 1, style: BorderStyle.Dashed }) 163 } 164 .width('100%') 165 .margin({ top: 25 }) 166 } 167 } 168 ``` 169 170  171 172 173- 绝对定位 174 175 线性布局中可以使用组件的[positon属性](../reference/arkui-ts/ts-universal-attributes-location.md)实现绝对布局(AbsoluteLayout),设置元素左上角相对于父容器左上角偏移位置。对于不同尺寸的设备,使用绝对定位的适应性会比较差,在屏幕的适配上有缺陷。 176 177 ```ts 178 @Entry 179 @Component 180 struct PositionExample { 181 @Styles eleStyle(){ 182 .backgroundColor(0xbbb2cb) 183 .border({ width: 1 }) 184 .size({ width: 120, height: 50 }) 185 } 186 187 build() { 188 Column({ space: 20 }) { 189 // 设置子组件左上角相对于父组件左上角的偏移位置 190 Row() { 191 Text('position(30, 10)') 192 .eleStyle() 193 .fontSize(16) 194 .position({ x: 10, y: 10 }) 195 196 Text('position(50%, 70%)') 197 .eleStyle() 198 .fontSize(16) 199 .position({ x: '50%', y: '70%' }) 200 201 Text('position(10%, 90%)') 202 .eleStyle() 203 .fontSize(16) 204 .position({ x: '10%', y: '80%' }) 205 }.width('90%').height('100%').border({ width: 1, style: BorderStyle.Dashed }) 206 } 207 .width('90%').margin(25) 208 } 209 } 210 ``` 211 212  213 214 215## 自适应延伸 216 217自适应延伸是在不同尺寸设备下,当页面显示内容个数不一并延伸到屏幕外时,可通过滚动条拖动展示。适用于线性布局中内容无法一屏展示的场景。常见以下两类实现方法。 218 219 220- List组件 221 222 List子项过多一屏放不下时,未展示的子项通过滚动条拖动显示。通过scrollBar属性设置滚动条的常驻状态,edgeEffect属性设置拖动到极限的回弹效果。 223 224 225 纵向List: 226 ```ts 227 @Entry 228 @Component 229 struct ListExample1 { 230 @State arr: string[] = ["0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "10", "11", "12", "13", "14", "15"] 231 @State alignListItem: ListItemAlign = ListItemAlign.Start 232 233 build() { 234 Column() { 235 List({ space: 20, initialIndex: 0 }) { 236 ForEach(this.arr, (item) => { 237 ListItem() { 238 Text('' + item) 239 .width('100%') 240 .height(100) 241 .fontSize(16) 242 .textAlign(TextAlign.Center) 243 .borderRadius(10) 244 .backgroundColor(0xFFFFFF) 245 } 246 .border({ width: 2, color: Color.Green }) 247 }, item => item) 248 } 249 .border({ width: 2, color: Color.Red, style: BorderStyle.Dashed }) 250 .scrollBar(BarState.On) // 滚动条常驻 251 .edgeEffect(EdgeEffect.Spring) // 滚动到边缘再拖动回弹效果 252 253 }.width('100%').height('100%').backgroundColor(0xDCDCDC).padding(20) 254 } 255 } 256 ``` 257 258  259 260 261 横向List: 262 263 ```ts 264 @Entry 265 @Component 266 struct ListExample2 { 267 @State arr: string[] = ["0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "10", "11", "12", "13", "14", "15"] 268 @State alignListItem: ListItemAlign = ListItemAlign.Start 269 270 build() { 271 Column() { 272 List({ space: 20, initialIndex: 0 }) { 273 ForEach(this.arr, (item) => { 274 ListItem() { 275 Text('' + item) 276 .height('100%') 277 .width(100) 278 .fontSize(16) 279 .textAlign(TextAlign.Center) 280 .borderRadius(10) 281 .backgroundColor(0xFFFFFF) 282 } 283 .border({ width: 2, color: Color.Green }) 284 }, item => item) 285 } 286 .border({ width: 2, color: Color.Red, style: BorderStyle.Dashed }) 287 .scrollBar(BarState.On) // 滚动条常驻 288 .edgeEffect(EdgeEffect.Spring) // 滚动到边缘再拖动回弹效果 289 .listDirection(Axis.Horizontal) // 列表水平排列 290 }.width('100%').height('100%').backgroundColor(0xDCDCDC).padding(20) 291 } 292 } 293 ``` 294 295  296 297- Scroll组件 298 299 线性布局中,当子组件的布局尺寸超过父组件的尺寸时,内容可以滚动。在Column或者Row外层包裹一个可滚动的容器组件Scroll实现。 300 301 纵向Scroll: 302 303 ```ts 304 @Entry 305 @Component 306 struct ScrollExample { 307 scroller: Scroller = new Scroller(); 308 private arr: number[] = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]; 309 310 build() { 311 Scroll(this.scroller) { 312 Column() { 313 ForEach(this.arr, (item) => { 314 Text(item.toString()) 315 .width('90%') 316 .height(150) 317 .backgroundColor(0xFFFFFF) 318 .borderRadius(15) 319 .fontSize(16) 320 .textAlign(TextAlign.Center) 321 .margin({ top: 10 }) 322 }, item => item) 323 }.width('100%') 324 } 325 .backgroundColor(0xDCDCDC) 326 .scrollable(ScrollDirection.Vertical) // 滚动方向纵向 327 .scrollBar(BarState.On) // 滚动条常驻显示 328 .scrollBarColor(Color.Gray) // 滚动条颜色 329 .scrollBarWidth(30) // 滚动条宽度 330 .edgeEffect(EdgeEffect.Spring) // 滚动到边沿后回弹 331 } 332 } 333 ``` 334 335  336 337 横向Scroll: 338 339 ```ts 340 @Entry 341 @Component 342 struct ScrollExample { 343 scroller: Scroller = new Scroller(); 344 private arr: number[] = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]; 345 346 build() { 347 Scroll(this.scroller) { 348 Row() { 349 ForEach(this.arr, (item) => { 350 Text(item.toString()) 351 .height('90%') 352 .width(150) 353 .backgroundColor(0xFFFFFF) 354 .borderRadius(15) 355 .fontSize(16) 356 .textAlign(TextAlign.Center) 357 .margin({ left: 10 }) 358 }, item => item) 359 }.height('100%') 360 } 361 .backgroundColor(0xDCDCDC) 362 .scrollable(ScrollDirection.Horizontal) // 滚动方向横向 363 .scrollBar(BarState.On) // 滚动条常驻显示 364 .scrollBarColor(Color.Gray) // 滚动条颜色 365 .scrollBarWidth(30) // 滚动条宽度 366 .edgeEffect(EdgeEffect.Spring) // 滚动到边沿后回弹 367 } 368 } 369 ``` 370  371