• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1# 相对布局 (RelativeContainer)
2
3
4## 概述
5
6在应用的开发过程中,经常需要设计复杂界面,此时涉及到多个相同或不同组件之间的嵌套。如果布局组件嵌套深度过深,或者嵌套组件数过多,会带来额外的开销。如果在布局的方式上进行优化,就可以有效的提升性能,减少时间开销。<!--Del-->请参考[优化布局时间](../performance/reduce-view-nesting-levels.md#优化布局时间)了解RelativeContainer相对于List,在布局时间上的性能提升。<!--DelEnd-->
7
8RelativeContainer为采用相对布局的容器,支持容器内部的子元素设置相对位置关系,适用于界面复杂场景的情况,对多个子组件进行对齐和排列。子元素支持指定兄弟元素作为锚点,也支持指定父容器作为锚点,基于锚点做相对位置布局。下图是一个RelativeContainer的概念图,图中的虚线表示位置的依赖关系。
9
10
11  **图1** 相对布局示意图  
12
13![relative-layout](figures/relative-layout.png)
14
15
16子元素并不完全是上图中的依赖关系。比如,Item4可以以Item2为依赖锚点,也可以以RelativeContainer父容器为依赖锚点。
17
18
19## 基本概念
20
21- 锚点:通过锚点设置当前元素基于哪个元素确定位置。
22
23- 对齐方式:通过对齐方式,设置当前元素是基于锚点的上中下对齐,还是基于锚点的左中右对齐。
24
25
26## 设置依赖关系
27
28
29### 锚点设置
30
31锚点设置是指设置子元素相对于父元素或兄弟元素的位置依赖关系。在水平方向上,可以设置left、middle、right的锚点。在竖直方向上,可以设置top、center、bottom的锚点。
32为了明确定义锚点,必须为RelativeContainer及其子元素设置ID,用于指定锚点信息。ID默认为“\_\_container\_\_”,其余子元素的ID通过id属性设置。不设置id的组件能显示,但是不能被其他子组件作为锚点,相对布局容器会为其拼接id,此id的规律无法被应用感知。互相依赖,环形依赖时容器内子组件全部不绘制。同方向上两个以上位置设置锚点,但锚点位置逆序时此子组件大小为0,即不绘制。
33
34>**说明:**
35>
36>在使用锚点时要注意子元素的相对位置关系,避免出现错位或遮挡的情况。
37
38- RelativeContainer父组件为锚点,__container__代表父容器的ID。
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(){Text('row1')}.justifyContent(FlexAlign.Center).width(100).height(100)
58        .backgroundColor("#FF3333")
59        .alignRules(AlignRus)
60        .id("row1")
61
62        Row(){Text('row2')}.justifyContent(FlexAlign.Center).width(100).height(100)
63        .backgroundColor("#FFCC00")
64        .alignRules(AlignRue)
65        .id("row2")
66      }.width(300).height(300)
67      .margin(Mleft)
68      .border(BWC)
69    }
70  }
71  ```
72
73  ![zh-cn_image_0000001562820901](figures/zh-cn_image_0000001562820901.png)
74
75- 以兄弟元素为锚点。
76
77  ```ts
78  let AlignRus:Record<string,Record<string,string|VerticalAlign|HorizontalAlign>> = {
79    'top': { 'anchor': '__container__', 'align': VerticalAlign.Top },
80    'left': { 'anchor': '__container__', 'align': HorizontalAlign.Start }
81  }
82  let RelConB:Record<string,Record<string,string|VerticalAlign|HorizontalAlign>> = {
83    'top': { 'anchor': 'row1', 'align': VerticalAlign.Bottom },
84    'left' : { 'anchor': 'row1', 'align': HorizontalAlign.Start }
85  }
86  let Mleft:Record<string,number> = { 'left': 20 }
87  let BWC:Record<string,number|string> = { 'width': 2, 'color': '#6699FF' }
88
89  @Entry
90  @Component
91  struct Index {
92    build() {
93      RelativeContainer() {
94        Row(){Text('row1')}.justifyContent(FlexAlign.Center).width(100).height(100)
95        .backgroundColor("#FF3333")
96        .alignRules(AlignRus)
97        .id("row1")
98
99        Row(){Text('row2')}.justifyContent(FlexAlign.Center).width(100).height(100)
100        .backgroundColor("#FFCC00")
101        .alignRules(RelConB)
102        .id("row2")
103      }.width(300).height(300)
104      .margin(Mleft)
105      .border(BWC)
106    }
107  }
108  ```
109
110  ![zh-cn_image_0000001562940613](figures/zh-cn_image_0000001562940613.png)
111
112- 子组件锚点可以任意选择,但需注意不要相互依赖。
113
114  ```ts
115  @Entry
116  @Component
117  struct Index {
118    build() {
119      Row() {
120        RelativeContainer() {
121          Row(){Text('row1')}.justifyContent(FlexAlign.Center).width(100).height(100)
122            .backgroundColor('#ff3339ff')
123            .alignRules({
124              top: {anchor: "__container__", align: VerticalAlign.Top},
125              left: {anchor: "__container__", align: HorizontalAlign.Start}
126            })
127            .id("row1")
128
129          Row(){Text('row2')}.justifyContent(FlexAlign.Center).width(100)
130            .backgroundColor('#ff298e1e')
131            .alignRules({
132              top: {anchor: "__container__", align: VerticalAlign.Top},
133              right: {anchor: "__container__", align: HorizontalAlign.End},
134              bottom: {anchor: "row1", align: VerticalAlign.Center},
135            })
136            .id("row2")
137
138          Row(){Text('row3')}.justifyContent(FlexAlign.Center).height(100)
139            .backgroundColor('#ffff6a33')
140            .alignRules({
141              top: {anchor: "row1", align: VerticalAlign.Bottom},
142              left: {anchor: "row1", align: HorizontalAlign.Start},
143              right: {anchor: "row2", align: HorizontalAlign.Start}
144            })
145            .id("row3")
146
147          Row(){Text('row4')}.justifyContent(FlexAlign.Center)
148            .backgroundColor('#ffff33fd')
149            .alignRules({
150              top: {anchor: "row3", align: VerticalAlign.Bottom},
151              left: {anchor: "row1", align: HorizontalAlign.Center},
152              right: {anchor: "row2", align: HorizontalAlign.End},
153              bottom: {anchor: "__container__", align: VerticalAlign.Bottom}
154            })
155            .id("row4")
156        }
157        .width(300).height(300)
158        .margin({left: 50})
159        .border({width:2, color: "#6699FF"})
160      }
161      .height('100%')
162    }
163  }
164  ```
165  ![Simplify-Component-Layout](figures/arkts-simplify-component-layout-image1.png)
166
167### 设置相对于锚点的对齐位置
168
169设置了锚点之后,可以通过align设置相对于锚点的对齐位置。
170
171在水平方向上,对齐位置可以设置为HorizontalAlign.StartHorizontalAlign.CenterHorizontalAlign.End172
173![alignment-relative-anchor-horizontal](figures/alignment-relative-anchor-horizontal.png)
174
175在竖直方向上,对齐位置可以设置为VerticalAlign.TopVerticalAlign.CenterVerticalAlign.Bottom176
177![alignment-relative-anchor-vertical](figures/alignment-relative-anchor-vertical.png)
178
179### 子组件位置偏移
180
181子组件经过相对位置对齐后,位置可能还不是目标位置,开发者可根据需要进行额外偏移设置offset。
182
183  ```ts
184  @Entry
185  @Component
186  struct Index {
187    build() {
188      Row() {
189        RelativeContainer() {
190          Row(){Text('row1')}.justifyContent(FlexAlign.Center).width(100).height(100)
191            .backgroundColor("#FF3333")
192            .alignRules({
193              top: {anchor: "__container__", align: VerticalAlign.Top},
194              left: {anchor: "__container__", align: HorizontalAlign.Start}
195            })
196            .id("row1")
197
198          Row(){Text('row2')}.justifyContent(FlexAlign.Center).width(100)
199            .backgroundColor("#FFCC00")
200            .alignRules({
201              top: {anchor: "__container__", align: VerticalAlign.Top},
202              right: {anchor: "__container__", align: HorizontalAlign.End},
203              bottom: {anchor: "row1", align: VerticalAlign.Center},
204            })
205            .offset({
206              x:-40,
207              y:-20
208            })
209            .id("row2")
210
211          Row(){Text('row3')}.justifyContent(FlexAlign.Center).height(100)
212            .backgroundColor("#FF6633")
213            .alignRules({
214              top: {anchor: "row1", align: VerticalAlign.Bottom},
215              left: {anchor: "row1", align: HorizontalAlign.End},
216              right: {anchor: "row2", align: HorizontalAlign.Start}
217            })
218            .offset({
219              x:-10,
220              y:-20
221            })
222            .id("row3")
223
224          Row(){Text('row4')}.justifyContent(FlexAlign.Center)
225            .backgroundColor("#FF9966")
226            .alignRules({
227              top: {anchor: "row3", align: VerticalAlign.Bottom},
228              bottom: {anchor: "__container__", align: VerticalAlign.Bottom},
229              left: {anchor: "__container__", align: HorizontalAlign.Start},
230              right: {anchor: "row1", align: HorizontalAlign.End}
231            })
232            .offset({
233              x:-10,
234              y:-30
235            })
236            .id("row4")
237
238          Row(){Text('row5')}.justifyContent(FlexAlign.Center)
239            .backgroundColor("#FF66FF")
240            .alignRules({
241              top: {anchor: "row3", align: VerticalAlign.Bottom},
242              bottom: {anchor: "__container__", align: VerticalAlign.Bottom},
243              left: {anchor: "row2", align: HorizontalAlign.Start},
244              right: {anchor: "row2", align: HorizontalAlign.End}
245            })
246            .offset({
247              x:10,
248              y:20
249            })
250            .id("row5")
251
252          Row(){Text('row6')}.justifyContent(FlexAlign.Center)
253            .backgroundColor('#ff33ffb5')
254            .alignRules({
255              top: {anchor: "row3", align: VerticalAlign.Bottom},
256              bottom: {anchor: "row4", align: VerticalAlign.Bottom},
257              left: {anchor: "row3", align: HorizontalAlign.Start},
258              right: {anchor: "row3", align: HorizontalAlign.End}
259            })
260            .offset({
261              x:-15,
262              y:10
263            })
264            .backgroundImagePosition(Alignment.Bottom)
265            .backgroundImageSize(ImageSize.Cover)
266            .id("row6")
267        }
268        .width(300).height(300)
269        .margin({left: 50})
270        .border({width:2, color: "#6699FF"})
271      }
272      .height('100%')
273    }
274  }
275  ```
276  ![Simplify-Component-Layout](figures/arkts-simplify-component-layout-image2.png)
277
278## 多种组件的对齐布局
279
280Row、Column、Flex、Stack等多种布局组件,可按照RelativeContainer组件规则进行对其排布。
281
282  ```ts
283  @Entry
284  @Component
285  struct Index {
286    @State value: number = 0
287    build() {
288      Row() {
289
290        RelativeContainer() {
291          Row().width(100).height(100)
292            .backgroundColor('#ff33ffcc')
293            .alignRules({
294              top: {anchor: "__container__", align: VerticalAlign.Top},
295              left: {anchor: "__container__", align: HorizontalAlign.Start}
296            })
297            .id("row1")
298
299          Column().width('50%').height(30).backgroundColor(0xAFEEEE)
300            .alignRules({
301              top: {anchor: "__container__", align: VerticalAlign.Top},
302              left: {anchor: "__container__", align: HorizontalAlign.Center}
303            }).id("row2")
304
305          Flex({ direction: FlexDirection.Row }) {
306            Text('1').width('20%').height(50).backgroundColor(0xF5DEB3)
307            Text('2').width('20%').height(50).backgroundColor(0xD2B48C)
308            Text('3').width('20%').height(50).backgroundColor(0xF5DEB3)
309            Text('4').width('20%').height(50).backgroundColor(0xD2B48C)
310          }
311          .padding(10)
312          .backgroundColor('#ffedafaf')
313          .alignRules({
314            top: {anchor: "row2", align: VerticalAlign.Bottom},
315            left: {anchor: "__container__", align: HorizontalAlign.Start},
316            bottom: {anchor: "__container__", align: VerticalAlign.Center},
317            right: {anchor: "row2", align: HorizontalAlign.Center}
318          })
319          .id("row3")
320
321          Stack({ alignContent: Alignment.Bottom }) {
322            Text('First child, show in bottom').width('90%').height('100%').backgroundColor(0xd2cab3).align(Alignment.Top)
323            Text('Second child, show in top').width('70%').height('60%').backgroundColor(0xc1cbac).align(Alignment.Top)
324          }
325          .margin({ top: 5 })
326          .alignRules({
327            top: {anchor: "row3", align: VerticalAlign.Bottom},
328            left: {anchor: "__container__", align: HorizontalAlign.Start},
329            bottom: {anchor: "__container__", align: VerticalAlign.Bottom},
330            right: {anchor: "row3", align: HorizontalAlign.End}
331          })
332          .id("row4")
333
334        }
335        .width(300).height(300)
336        .margin({left: 50})
337        .border({width:2, color: "#6699FF"})
338      }
339      .height('100%')
340    }
341  }
342  ```
343  ![Simplify-Component-Layout](figures/arkts-simplify-component-layout-image3.png)
344
345## 组件尺寸
346
347子组件尺寸大小不会受到相对布局规则的影响。若子组件某个方向上设置两个或以上alignRules时最好不设置此方向尺寸大小,否则对齐规则确定的组件尺寸与开发者设置的尺寸可能产生冲突。
348
349  ```ts
350  @Entry
351  @Component
352  struct Index {
353    build() {
354      Row() {
355        RelativeContainer() {
356          Row(){Text('row1')}.justifyContent(FlexAlign.Center)
357            .width(100).height(100)
358            .backgroundColor("#FF3333")
359            .alignRules({
360              top: {anchor: "__container__", align: VerticalAlign.Top},
361              left: {anchor: "__container__", align: HorizontalAlign.Start}
362            })
363            .id("row1")
364
365          Row(){Text('row2')}.justifyContent(FlexAlign.Center).width(100)
366            .backgroundColor("#FFCC00")
367            .alignRules({
368              top: {anchor: "__container__", align: VerticalAlign.Top},
369              right: {anchor: "__container__", align: HorizontalAlign.End},
370              bottom: {anchor: "row1", align: VerticalAlign.Center},
371            })
372            .id("row2")
373
374          Row(){Text('row3')}.justifyContent(FlexAlign.Center).height(100)
375            .backgroundColor("#FF6633")
376            .alignRules({
377              top: {anchor: "row1", align: VerticalAlign.Bottom},
378              left: {anchor: "row1", align: HorizontalAlign.End},
379              right: {anchor: "row2", align: HorizontalAlign.Start}
380            })
381            .id("row3")
382
383          Row(){Text('row4')}.justifyContent(FlexAlign.Center)
384            .backgroundColor("#FF9966")
385            .alignRules({
386              top: {anchor: "row3", align: VerticalAlign.Bottom},
387              bottom: {anchor: "__container__", align: VerticalAlign.Bottom},
388              left: {anchor: "__container__", align: HorizontalAlign.Start},
389              right: {anchor: "row1", align: HorizontalAlign.End}
390            })
391            .id("row4")
392
393          Row(){Text('row5')}.justifyContent(FlexAlign.Center)
394            .backgroundColor("#FF66FF")
395            .alignRules({
396              top: {anchor: "row3", align: VerticalAlign.Bottom},
397              bottom: {anchor: "__container__", align: VerticalAlign.Bottom},
398              left: {anchor: "row2", align: HorizontalAlign.Start},
399              right: {anchor: "row2", align: HorizontalAlign.End}
400            })
401            .id("row5")
402
403          Row(){Text('row6')}.justifyContent(FlexAlign.Center)
404            .backgroundColor('#ff33ffb5')
405            .alignRules({
406              top: {anchor: "row3", align: VerticalAlign.Bottom},
407              bottom: {anchor: "row4", align: VerticalAlign.Bottom},
408              left: {anchor: "row3", align: HorizontalAlign.Start},
409              right: {anchor: "row3", align: HorizontalAlign.End}
410            })
411            .id("row6")
412            .backgroundImagePosition(Alignment.Bottom)
413            .backgroundImageSize(ImageSize.Cover)
414        }
415        .width(300).height(300)
416        .margin({left: 50})
417        .border({width:2, color: "#6699FF"})
418      }
419      .height('100%')
420    }
421  }
422  ```
423  ![Simplify-Component-Layout](figures/arkts-simplify-component-layout-image4.png)
424