1# Relative Layout (RelativeContainer) 2 3 4## Overview 5 6During application development, nesting components – same or different – is common in page layout, especially when the target page is complicated. Yet, nesting components too deeply, or nesting too many components, can be especially expensive. Naturally, optimizing the layout hierarchies can effectively lead to better performance and less time overhead. <!--Del-->For details about how the relative container is more performance-efficient than the list, see [Improving Layout Performance](../performance/reduce-view-nesting-levels.md).<!--DelEnd--> 7 8The relative layout, implemented using the **RelativeContainer** container component, is used to lay out child elements in relative positions. It is applicable to element alignment in complex scenarios. A child element can use the container or another child element as the anchor, based on which its relative position is determined. Below shows a relative layout. The dotted lines in the figure indicate the position dependency. 9 10 11 **Figure 1** Relative layout 12 13 14 15 16A child element does not necessarily adopt the dependency shown above to determine its relative position. For example, Item4 may use Item2 or the **RelativeContainer** parent container as a dependency anchor. 17 18 19## Basic Concepts 20 21- Anchor: element relative to which an element's position is specified. 22 23- Alignment mode: how the current element is aligned with the anchor, which can be top-, center-, or bottom-aligned in the vertical direction or left-, center-, and right-aligned in the horizontal direction. 24 25 26## Setting the Dependency 27 28 29### Setting the Anchor 30 31By setting the anchor, you set a position dependency relationship between a child element and its parent element or sibling elements. In the horizontal direction, you can set the left, middle, and right anchors. In the vertical direction, you can set the top, center, and bottom anchors. 32To specify anchors, you must set IDs for the **RelativeContainer** component and its child elements. The default ID is **\_\_container\_\_**, and the IDs for the remaining child elements are set through the **id** attribute. Components without **id** set can be displayed but cannot be used as anchors by other child components; the relative layout container will generate an ID for them, and the pattern of this ID is not predictable by the application logic. When a mutual or circular dependency occurs, none of the child components in the container are drawn. If anchors are set for more than two positions in a single direction but the anchor positions are reversed, the size of the child component is 0, which means that the child component is not drawn. 33 34>**NOTE** 35> 36>When using anchors, pay attention to the relative positions of child elements to avoid misplacement or blocking. 37 38- The ID of the **RelativeContainer** parent component is **__container__**. 39 40 ```ts 41 let AlignRus: Record<string, Record<string, string | VerticalAlign | HorizontalAlign>> = { 42 'top': { 'anchor': '__container__', 'align': VerticalAlign.Top }, 43 'left': { 'anchor': '__container__', 'align': HorizontalAlign.Start } 44 } 45 let AlignRue: Record<string, Record<string, string | VerticalAlign | HorizontalAlign>> = { 46 'top': { 'anchor': '__container__', 'align': VerticalAlign.Top }, 47 'right': { 'anchor': '__container__', 'align': HorizontalAlign.End } 48 } 49 let Mleft: Record<string, number> = { 'left': 20 } 50 let BWC: Record<string, number | string> = { 'width': 2, 'color': '#6699FF' } 51 52 @Entry 53 @Component 54 struct Index { 55 build() { 56 RelativeContainer() { 57 Row() { 58 Text('row1') 59 } 60 .justifyContent(FlexAlign.Center) 61 .width(100) 62 .height(100) 63 .backgroundColor('#a3cf62') 64 .alignRules(AlignRus) 65 .id("row1") 66 67 Row() { 68 Text('row2') 69 } 70 .justifyContent(FlexAlign.Center) 71 .width(100) 72 .height(100) 73 .backgroundColor('#00ae9d') 74 .alignRules(AlignRue) 75 .id("row2") 76 }.width(300).height(300) 77 .margin(Mleft) 78 .border(BWC) 79 } 80 } 81 ``` 82 83  84 85- Example of using a sibling element as the anchor: 86 87 ```ts 88 let AlignRus: Record<string, Record<string, string | VerticalAlign | HorizontalAlign>> = { 89 'top': { 'anchor': '__container__', 'align': VerticalAlign.Top }, 90 'left': { 'anchor': '__container__', 'align': HorizontalAlign.Start } 91 } 92 let RelConB: Record<string, Record<string, string | VerticalAlign | HorizontalAlign>> = { 93 'top': { 'anchor': 'row1', 'align': VerticalAlign.Bottom }, 94 'left': { 'anchor': 'row1', 'align': HorizontalAlign.Start } 95 } 96 let Mleft: Record<string, number> = { 'left': 20 } 97 let BWC: Record<string, number | string> = { 'width': 2, 'color': '#6699FF' } 98 99 @Entry 100 @Component 101 struct Index { 102 build() { 103 RelativeContainer() { 104 Row() { 105 Text('row1') 106 } 107 .justifyContent(FlexAlign.Center) 108 .width(100) 109 .height(100) 110 .backgroundColor('#00ae9d') 111 .alignRules(AlignRus) 112 .id("row1") 113 114 Row() { 115 Text('row2') 116 } 117 .justifyContent(FlexAlign.Center) 118 .width(100) 119 .height(100) 120 .backgroundColor('#a3cf62') 121 .alignRules(RelConB) 122 .id("row2") 123 }.width(300).height(300) 124 .margin(Mleft) 125 .border(BWC) 126 } 127 } 128 ``` 129 130  131 132- Make sure the anchors of a child component do not depend on each other. 133 134 ```ts 135 @Entry 136 @Component 137 struct Index { 138 build() { 139 Row() { 140 RelativeContainer() { 141 Row(){Text('row1')}.justifyContent(FlexAlign.Center).width(100).height(100) 142 .backgroundColor('#a3cf62') 143 .alignRules({ 144 top: {anchor: "__container__", align: VerticalAlign.Top}, 145 left: {anchor: "__container__", align: HorizontalAlign.Start} 146 }) 147 .id("row1") 148 149 Row(){Text('row2')}.justifyContent(FlexAlign.Center).width(100) 150 .backgroundColor('#00ae9d') 151 .alignRules({ 152 top: {anchor: "__container__", align: VerticalAlign.Top}, 153 right: {anchor: "__container__", align: HorizontalAlign.End}, 154 bottom: {anchor: "row1", align: VerticalAlign.Center}, 155 }) 156 .id("row2") 157 158 Row(){Text('row3')}.justifyContent(FlexAlign.Center).height(100) 159 .backgroundColor('#0a59f7') 160 .alignRules({ 161 top: {anchor: "row1", align: VerticalAlign.Bottom}, 162 left: {anchor: "row1", align: HorizontalAlign.Start}, 163 right: {anchor: "row2", align: HorizontalAlign.Start} 164 }) 165 .id("row3") 166 167 Row(){Text('row4')}.justifyContent(FlexAlign.Center) 168 .backgroundColor('#2ca9e0') 169 .alignRules({ 170 top: {anchor: "row3", align: VerticalAlign.Bottom}, 171 left: {anchor: "row1", align: HorizontalAlign.Center}, 172 right: {anchor: "row2", align: HorizontalAlign.End}, 173 bottom: {anchor: "__container__", align: VerticalAlign.Bottom} 174 }) 175 .id("row4") 176 } 177 .width(300).height(300) 178 .margin({left: 50}) 179 .border({width:2, color: "#6699FF"}) 180 } 181 .height('100%') 182 } 183 } 184 ``` 185  186 187### Setting Alignment Relative to the Anchor 188 189After an anchor is set, you can use **align** to set the alignment mode relative to the anchor. 190 191Alignment modes in the horizontal direction can be left, center, or right, achieved by the **HorizontalAlign.Start**, **HorizontalAlign.Center**, and **HorizontalAlign.End** attributes, respectively. 192 193 194 195Alignment modes in the vertical direction can be top, center, or bottom, achieved by the **VerticalAlign.Top**, **VerticalAlign.Center**, and **VerticalAlign.Bottom** attributes, respectively. 196 197 198 199### Setting Offset 200 201After being aligned relative to the anchor, a child component may be still not at its target position. In this case, you can set the offset. 202 203 ```ts 204@Entry 205@Component 206struct Index { 207 build() { 208 Row() { 209 RelativeContainer() { 210 Row() { 211 Text('row1') 212 } 213 .justifyContent(FlexAlign.Center) 214 .width(100) 215 .height(100) 216 .backgroundColor('#a3cf62') 217 .alignRules({ 218 top: { anchor: "__container__", align: VerticalAlign.Top }, 219 left: { anchor: "__container__", align: HorizontalAlign.Start } 220 }) 221 .id("row1") 222 223 Row() { 224 Text('row2') 225 } 226 .justifyContent(FlexAlign.Center) 227 .width(100) 228 .backgroundColor('#00ae9d') 229 .alignRules({ 230 top: { anchor: "__container__", align: VerticalAlign.Top }, 231 right: { anchor: "__container__", align: HorizontalAlign.End }, 232 bottom: { anchor: "row1", align: VerticalAlign.Center }, 233 }) 234 .offset({ 235 x: -40, 236 y: -20 237 }) 238 .id("row2") 239 240 Row() { 241 Text('row3') 242 } 243 .justifyContent(FlexAlign.Center) 244 .height(100) 245 .backgroundColor('#0a59f7') 246 .alignRules({ 247 top: { anchor: "row1", align: VerticalAlign.Bottom }, 248 left: { anchor: "row1", align: HorizontalAlign.End }, 249 right: { anchor: "row2", align: HorizontalAlign.Start } 250 }) 251 .offset({ 252 x: -10, 253 y: -20 254 }) 255 .id("row3") 256 257 Row() { 258 Text('row4') 259 } 260 .justifyContent(FlexAlign.Center) 261 .backgroundColor('#2ca9e0') 262 .alignRules({ 263 top: { anchor: "row3", align: VerticalAlign.Bottom }, 264 bottom: { anchor: "__container__", align: VerticalAlign.Bottom }, 265 left: { anchor: "__container__", align: HorizontalAlign.Start }, 266 right: { anchor: "row1", align: HorizontalAlign.End } 267 }) 268 .offset({ 269 x: -10, 270 y: -30 271 }) 272 .id("row4") 273 274 Row() { 275 Text('row5') 276 } 277 .justifyContent(FlexAlign.Center) 278 .backgroundColor('#30c9f7') 279 .alignRules({ 280 top: { anchor: "row3", align: VerticalAlign.Bottom }, 281 bottom: { anchor: "__container__", align: VerticalAlign.Bottom }, 282 left: { anchor: "row2", align: HorizontalAlign.Start }, 283 right: { anchor: "row2", align: HorizontalAlign.End } 284 }) 285 .offset({ 286 x: 10, 287 y: 20 288 }) 289 .id("row5") 290 291 Row() { 292 Text('row6') 293 } 294 .justifyContent(FlexAlign.Center) 295 .backgroundColor('#ff33ffb5') 296 .alignRules({ 297 top: { anchor: "row3", align: VerticalAlign.Bottom }, 298 bottom: { anchor: "row4", align: VerticalAlign.Bottom }, 299 left: { anchor: "row3", align: HorizontalAlign.Start }, 300 right: { anchor: "row3", align: HorizontalAlign.End } 301 }) 302 .offset({ 303 x: -15, 304 y: 10 305 }) 306 .backgroundImagePosition(Alignment.Bottom) 307 .backgroundImageSize(ImageSize.Cover) 308 .id("row6") 309 } 310 .width(300).height(300) 311 .margin({ left: 50 }) 312 .border({ width: 2, color: "#6699FF" }) 313 } 314 .height('100%') 315 } 316} 317 ``` 318  319 320## Aligning Components in Multiple Layouts 321 322You can set components in multiple layout components, such as **Row**, **Column**, **Flex**, and **Stack**, to be aligned based on the relative layout rules. 323 324 ```ts 325@Entry 326@Component 327struct Index { 328 @State value: number = 0 329 330 build() { 331 Row() { 332 333 RelativeContainer() { 334 Row() 335 .width(100) 336 .height(100) 337 .backgroundColor('#a3cf62') 338 .alignRules({ 339 top: { anchor: "__container__", align: VerticalAlign.Top }, 340 left: { anchor: "__container__", align: HorizontalAlign.Start } 341 }) 342 .id("row1") 343 344 Column() 345 .width('50%') 346 .height(30) 347 .backgroundColor('#00ae9d') 348 .alignRules({ 349 top: { anchor: "__container__", align: VerticalAlign.Top }, 350 left: { anchor: "__container__", align: HorizontalAlign.Center } 351 }) 352 .id("row2") 353 354 Flex({ direction: FlexDirection.Row }) { 355 Text('1').width('20%').height(50).backgroundColor('#0a59f7') 356 Text('2').width('20%').height(50).backgroundColor('#2ca9e0') 357 Text('3').width('20%').height(50).backgroundColor('#0a59f7') 358 Text('4').width('20%').height(50).backgroundColor('#2ca9e0') 359 } 360 .padding(10) 361 .backgroundColor('#30c9f7') 362 .alignRules({ 363 top: { anchor: "row2", align: VerticalAlign.Bottom }, 364 left: { anchor: "__container__", align: HorizontalAlign.Start }, 365 bottom: { anchor: "__container__", align: VerticalAlign.Center }, 366 right: { anchor: "row2", align: HorizontalAlign.Center } 367 }) 368 .id("row3") 369 370 Stack({ alignContent: Alignment.Bottom }) { 371 Text('First child, show in bottom').width('90%').height('100%').backgroundColor('#a3cf62').align(Alignment.Top) 372 Text('Second child, show in top').width('70%').height('60%').backgroundColor('#00ae9d').align(Alignment.Top) 373 } 374 .margin({ top: 5 }) 375 .alignRules({ 376 top: { anchor: "row3", align: VerticalAlign.Bottom }, 377 left: { anchor: "__container__", align: HorizontalAlign.Start }, 378 bottom: { anchor: "__container__", align: VerticalAlign.Bottom }, 379 right: { anchor: "row3", align: HorizontalAlign.End } 380 }) 381 .id("row4") 382 383 } 384 .width(300).height(300) 385 .margin({ left: 50 }) 386 .border({ width: 2, color: "#6699FF" }) 387 } 388 .height('100%') 389 } 390} 391 ``` 392  393 394## Component Size 395 396The size of a child component is not affected by the relative layout rules. If two or more **alignRule** values are set for a child component in one direction, avoid setting the size in this direction. Otherwise, the component size determined by **alignRule** may conflict with the size you set. 397 398 ```ts 399@Entry 400@Component 401struct Index { 402 build() { 403 Row() { 404 RelativeContainer() { 405 Row() { 406 Text('row1') 407 } 408 .justifyContent(FlexAlign.Center) 409 .width(100) 410 .height(100) 411 .backgroundColor('#a3cf62') 412 .alignRules({ 413 top: { anchor: "__container__", align: VerticalAlign.Top }, 414 left: { anchor: "__container__", align: HorizontalAlign.Start } 415 }) 416 .id("row1") 417 418 Row() { 419 Text('row2') 420 } 421 .justifyContent(FlexAlign.Center) 422 .width(100) 423 .backgroundColor('#00ae9d') 424 .alignRules({ 425 top: { anchor: "__container__", align: VerticalAlign.Top }, 426 right: { anchor: "__container__", align: HorizontalAlign.End }, 427 bottom: { anchor: "row1", align: VerticalAlign.Center }, 428 }) 429 .id("row2") 430 431 Row() { 432 Text('row3') 433 } 434 .justifyContent(FlexAlign.Center) 435 .height(100) 436 .backgroundColor('#0a59f7') 437 .alignRules({ 438 top: { anchor: "row1", align: VerticalAlign.Bottom }, 439 left: { anchor: "row1", align: HorizontalAlign.End }, 440 right: { anchor: "row2", align: HorizontalAlign.Start } 441 }) 442 .id("row3") 443 444 Row() { 445 Text('row4') 446 }.justifyContent(FlexAlign.Center) 447 .backgroundColor('#2ca9e0') 448 .alignRules({ 449 top: { anchor: "row3", align: VerticalAlign.Bottom }, 450 bottom: { anchor: "__container__", align: VerticalAlign.Bottom }, 451 left: { anchor: "__container__", align: HorizontalAlign.Start }, 452 right: { anchor: "row1", align: HorizontalAlign.End } 453 }) 454 .id("row4") 455 456 Row() { 457 Text('row5') 458 }.justifyContent(FlexAlign.Center) 459 .backgroundColor('#30c9f7') 460 .alignRules({ 461 top: { anchor: "row3", align: VerticalAlign.Bottom }, 462 bottom: { anchor: "__container__", align: VerticalAlign.Bottom }, 463 left: { anchor: "row2", align: HorizontalAlign.Start }, 464 right: { anchor: "row2", align: HorizontalAlign.End } 465 }) 466 .id("row5") 467 468 Row() { 469 Text('row6') 470 } 471 .justifyContent(FlexAlign.Center) 472 .backgroundColor('#ff33ffb5') 473 .alignRules({ 474 top: { anchor: "row3", align: VerticalAlign.Bottom }, 475 bottom: { anchor: "row4", align: VerticalAlign.Bottom }, 476 left: { anchor: "row3", align: HorizontalAlign.Start }, 477 right: { anchor: "row3", align: HorizontalAlign.End } 478 }) 479 .id("row6") 480 .backgroundImagePosition(Alignment.Bottom) 481 .backgroundImageSize(ImageSize.Cover) 482 } 483 .width(300).height(300) 484 .margin({ left: 50 }) 485 .border({ width: 2, color: "#6699FF" }) 486 } 487 .height('100%') 488 } 489} 490 ``` 491  492