1# FoldSplitContainer
2
3
4FoldSplitContainer分栏布局,实现折叠屏二分栏、三分栏在展开态、悬停态以及折叠态的区域控制。
5
6
7> **说明:**
8>
9> 该组件从API Version 12开始支持。后续版本如有新增内容,则采用上角标单独标记该内容的起始版本。
10
11## 导入模块
12
13```ts
14import { FoldSplitContainer } from '@kit.ArkUI';
15```
16
17## 子组件
18
1920
21## FoldSplitContainer
22
23FoldSplitContainer({
24  primary: Callback<void>,
25  secondary: Callback<void>,
26  extra?: Callback<void>,
27  expandedLayoutOptions?: ExpandedRegionLayoutOptions,
28  hoverModeLayoutOptions?: HoverModeRegionLayoutOptions,
29  foldedLayoutOptions?: FoldedRegionLayoutOptions,
30  animationOptions?: AnimateParam,
31  onHoverStatusChange?: onHoverStatusChangeHandler
32})
33
34**装饰器类型:**\@Component
35
36**原子化服务API:** 从API version 12开始,该接口支持在原子化服务中使用。
37
38**系统能力:** SystemCapability.ArkUI.ArkUI.Full
39
40| 名称 | 类型 | 必填 | 装饰器类型 | 说明 |
41| -------- | -------- | -------- | -------- | -------- |
42| primary | ()=>void | 否 | @BuilderParam | 主要区域回调函数。 |
43| secondary | ()=>void | 否 | @BuilderParam | 次要区域回调函数。 |
44| extra | ()=>void | 否 | @BuilderParam | 扩展区域回调函数,不传入的情况,没有对应区域。 |
45| expandedLayoutOptions | [ExpandedRegionLayoutOptions](#expandedregionlayoutoptions) | 否 | @Prop | 展开态布局信息。 |
46| hoverModeLayoutOptions | [HoverModeRegionLayoutOptions](#hovermoderegionlayoutoptions) | 否 | @Prop | 悬停态布局信息。 |
47| foldedLayoutOptions | [FoldedRegionLayoutOptions](#foldedregionlayoutoptions) | 否 | @Prop | 折叠态布局信息。 |
48| animationOptions | [AnimateParam](ts-explicit-animation.md#animateparam对象说明) \| null | 否 | @Prop | 设置动画效果相关的参数,null表示表示关闭动效。 |
49| onHoverStatusChange | [onHoverStatusChangeHandler](#onhoverstatuschangehandler) | 否 | - | 折叠屏进入或退出悬停模式时触发的回调函数。 |
50
51## ExpandedRegionLayoutOptions
52
53展开态布局信息。
54
55**原子化服务API:** 从API version 12开始,该接口支持在原子化服务中使用。
56
57**系统能力:** SystemCapability.ArkUI.ArkUI.Full
58
59| 名称 | 类型 | 必填 | 说明 |
60| -------- | -------- | -------- | -------- |
61| isExtraRegionPerpendicular | boolean | 否 | 扩展区域是否从上到下贯穿整个组件,当且仅当extra有效时此字段才生效。默认值:true。 |
62| verticalSplitRatio | number | 否 | 主要区域与次要区域之间的高度比例。默认值:PresetSplitRatio.LAYOUT_1V1。 |
63| horizontalSplitRatio | number | 否 | 主要区域与扩展区域之间的宽度比例,当且仅当extra有效时此字段才生效。默认值:PresetSplitRatio.LAYOUT_3V2。 |
64| extraRegionPosition | [ExtraRegionPosition](#extraregionposition) | 否 | 扩展区域的位置信息,当且仅当isExtraRegionPerpendicular = false有效时此字段才生效。默认值:ExtraRegionPosition.top。 |
65
66## HoverModeRegionLayoutOptions
67
68悬停态布局信息。
69
70**原子化服务API:** 从API version 12开始,该接口支持在原子化服务中使用。
71
72**系统能力:** SystemCapability.ArkUI.ArkUI.Full
73
74| 名称 | 类型 | 必填 | 说明 |
75| -------- | -------- | -------- | -------- |
76| showExtraRegion | boolean | 否 | 可折叠屏幕在半折叠状态下是否显示扩展区域。默认值:false。 |
77| horizontalSplitRatio | number | 否 | 主要区域与扩展区域之间的宽度比例,当且仅当extra有效时此字段才生效。默认值:PresetSplitRatio.LAYOUT_3V2。 |
78| extraRegionPosition | [ExtraRegionPosition](#extraregionposition) | 否 | 扩展区域的位置信息,当且仅当showExtraRegion时此字段才生效。默认值:ExtraRegionPosition.top。 |
79
80> **说明:**
81>
82> 1.设备处于悬停态时,存在避让区域,布局计算需要考虑避让区域对布局的影响。
83> 2.在悬停模式下,屏幕上半部分用于显示,下半部分用于操作。
84
85## FoldedRegionLayoutOptions
86
87**原子化服务API:** 从API version 12开始,该接口支持在原子化服务中使用。
88
89**系统能力:** SystemCapability.ArkUI.ArkUI.Full
90
91折叠态布局信息。
92
93| 名称 | 类型 | 必填 | 说明 |
94| -------- | -------- | -------- | -------- |
95| verticalSplitRatio | number | 否 | 主要区域与次要区域之间的高度比例。默认值:PresetSplitRatio.LAYOUT_1V1。 |
96
97## onHoverStatusChangeHandler
98
99type OnHoverStatusChangeHandler = (status: HoverModeStatus) => void
100
101onHoverStatusChange事件处理。
102
103**原子化服务API:** 从API version 12开始,该接口支持在原子化服务中使用。
104
105**系统能力:** SystemCapability.ArkUI.ArkUI.Full
106
107**参数:**
108
109| 参数名 | 类型 | 必填 | 说明 |
110| -------- | -------- | -------- | -------- |
111| status | [HoverModeStatus](#hovermodestatus) | 是 | 折叠屏进入或退出悬停模式时触发的回调函数。 |
112
113## HoverModeStatus
114
115折叠态布局信息。
116
117**原子化服务API:** 从API version 12开始,该接口支持在原子化服务中使用。
118
119**系统能力:** SystemCapability.ArkUI.ArkUI.Full
120
121| 名称 | 类型 | 必填 | 说明 |
122| -------- | -------- | -------- | -------- |
123| foldStatus | [display.FoldStatus<sup>10+</sup>](../js-apis-display.md#foldstatus10) | 是 | 设备的折叠状态。 |
124| isHoverMode | boolean | 是 | app当前是否处于悬停态。 |
125| appRotation | number | 是 | 应用旋转角度。 |
126| windowStatusType | [window.WindowStatusType<sup>11+</sup>](../js-apis-window.md#windowstatustype11) | 是 | 窗口模式。 |
127
128## ExtraRegionPosition
129
130扩展区域位置信息。
131
132**原子化服务API:** 从API version 12开始,该接口支持在原子化服务中使用。
133
134**系统能力:** SystemCapability.ArkUI.ArkUI.Full
135
136| 名称 | 值 | 说明 |
137| -------- | -------- | -------- |
138| TOP | 1 | 扩展区域在组件上半区域。 |
139| BOTTOM | 2 | 扩展区域在组件下半区域。 |
140
141## PresetSplitRatio
142
143区域比例。
144
145**原子化服务API:** 从API version 12开始,该接口支持在原子化服务中使用。
146
147**系统能力:** SystemCapability.ArkUI.ArkUI.Full
148
149| 名称 | 值 | 说明 |
150| -------- | -------- | -------- |
151| LAYOUT_1V1 | 1/1 | 1:1比例。 |
152| LAYOUT_3V2 | 3/2 | 3:2比例。 |
153| LAYOUT_2V3 | 2/3 | 2:3比例。 |
154
155## 示例
156
157### 示例1(设置二分栏)
158
159该示例实现了折叠屏二分栏在展开态、悬停态以及折叠态的区域控制。
160
161```ts
162import { FoldSplitContainer } from '@kit.ArkUI';
163
164@Entry
165@Component
166struct TwoColumns {
167  @Builder
168  privateRegion() {
169    Text("Primary")
170      .backgroundColor('rgba(255, 0, 0, 0.1)')
171      .fontSize(28)
172      .textAlign(TextAlign.Center)
173      .height('100%')
174      .width('100%')
175  }
176
177  @Builder
178  secondaryRegion() {
179    Text("Secondary")
180      .backgroundColor('rgba(0, 255, 0, 0.1)')
181      .fontSize(28)
182      .textAlign(TextAlign.Center)
183      .height('100%')
184      .width('100%')
185  }
186
187  build() {
188    RelativeContainer() {
189      FoldSplitContainer({
190        primary: () => {
191          this.privateRegion()
192        },
193        secondary: () => {
194          this.secondaryRegion()
195        }
196      })
197    }
198    .height('100%')
199    .width('100%')
200  }
201}
202```
203
204| 折叠态 | 展开态 | 悬停态 |
205| ----- | ------ | ------ |
206| ![](figures/foldsplitcontainer-1.png) | ![](figures/foldsplitcontainer-2.png) | ![](figures/foldsplitcontainer-3.png) |
207
208### 示例2(设置三分栏)
209
210该示例实现了折叠屏三分栏在展开态、悬停态以及折叠态的区域控制。
211
212```ts
213import { FoldSplitContainer } from '@kit.ArkUI';
214
215@Entry
216@Component
217struct ThreeColumns {
218  @Builder
219  privateRegion() {
220    Text("Primary")
221      .backgroundColor('rgba(255, 0, 0, 0.1)')
222      .fontSize(28)
223      .textAlign(TextAlign.Center)
224      .height('100%')
225      .width('100%')
226  }
227
228  @Builder
229  secondaryRegion() {
230    Text("Secondary")
231      .backgroundColor('rgba(0, 255, 0, 0.1)')
232      .fontSize(28)
233      .textAlign(TextAlign.Center)
234      .height('100%')
235      .width('100%')
236  }
237
238  @Builder
239  extraRegion() {
240    Text("Extra")
241      .backgroundColor('rgba(0, 0, 255, 0.1)')
242      .fontSize(28)
243      .textAlign(TextAlign.Center)
244      .height('100%')
245      .width('100%')
246  }
247
248  build() {
249    RelativeContainer() {
250      FoldSplitContainer({
251        primary: () => {
252          this.privateRegion()
253        },
254        secondary: () => {
255          this.secondaryRegion()
256        },
257        extra: () => {
258          this.extraRegion()
259        }
260      })
261    }
262    .height('100%')
263    .width('100%')
264  }
265}
266```
267
268| 折叠态 | 展开态 | 悬停态 |
269| ----- | ------ | ------ |
270| ![](figures/foldsplitcontainer-4.png) | ![](figures/foldsplitcontainer-5.png) | ![](figures/foldsplitcontainer-6.png) |
271
272### 示例3(展开态布局信息)
273
274该示例通过配置ExpandedRegionLayoutOptions实现折叠屏展开态的布局信息。
275
276```ts
277import {
278  FoldSplitContainer,
279  PresetSplitRatio,
280  ExtraRegionPosition,
281  ExpandedRegionLayoutOptions,
282  HoverModeRegionLayoutOptions,
283  FoldedRegionLayoutOptions
284} from '@kit.ArkUI';
285
286@Component
287struct Region {
288  @Prop title: string;
289  @BuilderParam content: () => void;
290  @Prop compBackgroundColor: string;
291
292  build() {
293    Column({ space: 8 }) {
294      Text(this.title)
295        .fontSize("24fp")
296        .fontWeight(600)
297
298      Scroll() {
299        this.content()
300      }
301      .layoutWeight(1)
302      .width("100%")
303    }
304    .backgroundColor(this.compBackgroundColor)
305    .width("100%")
306    .height("100%")
307    .padding(12)
308  }
309}
310
311const noop = () => {
312};
313
314@Component
315struct SwitchOption {
316  @Prop label: string = ""
317  @Prop value: boolean = false
318  public onChange: (checked: boolean) => void = noop;
319
320  build() {
321    Row() {
322      Text(this.label)
323      Blank()
324      Toggle({ type: ToggleType.Switch, isOn: this.value })
325        .onChange((isOn) => {
326          this.onChange(isOn);
327        })
328    }
329    .backgroundColor(Color.White)
330    .borderRadius(8)
331    .padding(8)
332    .width("100%")
333  }
334}
335
336interface RadioOptions {
337  label: string;
338  value: Object | undefined | null;
339  onChecked: () => void;
340}
341
342@Component
343struct RadioOption {
344  @Prop label: string;
345  @Prop value: Object | undefined | null;
346  @Prop options: Array<RadioOptions>;
347
348  build() {
349    Row() {
350      Text(this.label)
351      Blank()
352      Column({ space: 4 }) {
353        ForEach(this.options, (option: RadioOptions) => {
354          Row() {
355            Radio({
356              group: this.label,
357              value: JSON.stringify(option.value),
358            })
359              .checked(this.value === option.value)
360              .onChange((checked) => {
361                if (checked) {
362                  option.onChecked();
363                }
364              })
365            Text(option.label)
366          }
367        })
368      }
369      .alignItems(HorizontalAlign.Start)
370    }
371    .alignItems(VerticalAlign.Top)
372    .backgroundColor(Color.White)
373    .borderRadius(8)
374    .padding(8)
375    .width("100%")
376  }
377}
378
379@Entry
380@Component
381struct Index {
382  @State expandedRegionLayoutOptions: ExpandedRegionLayoutOptions = {
383    horizontalSplitRatio: PresetSplitRatio.LAYOUT_3V2,
384    verticalSplitRatio: PresetSplitRatio.LAYOUT_1V1,
385    isExtraRegionPerpendicular: true,
386    extraRegionPosition: ExtraRegionPosition.TOP
387  };
388  @State foldingRegionLayoutOptions: HoverModeRegionLayoutOptions = {
389    horizontalSplitRatio: PresetSplitRatio.LAYOUT_3V2,
390    showExtraRegion: false,
391    extraRegionPosition: ExtraRegionPosition.TOP
392  };
393  @State foldedRegionLayoutOptions: FoldedRegionLayoutOptions = {
394    verticalSplitRatio: PresetSplitRatio.LAYOUT_1V1
395  };
396
397  @Builder
398  MajorRegion() {
399    Region({
400      title: "折叠态配置",
401      compBackgroundColor: "rgba(255, 0, 0, 0.1)",
402    }) {
403      Column({ space: 4 }) {
404        RadioOption({
405          label: "折叠态垂直高度度比",
406          value: this.foldedRegionLayoutOptions.verticalSplitRatio,
407          options: [
408            {
409              label: "1:1",
410              value: PresetSplitRatio.LAYOUT_1V1,
411              onChecked: () => {
412                this.foldedRegionLayoutOptions.verticalSplitRatio = PresetSplitRatio.LAYOUT_1V1
413              }
414            },
415            {
416              label: "2:3",
417              value: PresetSplitRatio.LAYOUT_2V3,
418              onChecked: () => {
419                this.foldedRegionLayoutOptions.verticalSplitRatio = PresetSplitRatio.LAYOUT_2V3
420              }
421            },
422            {
423              label: "3:2",
424              value: PresetSplitRatio.LAYOUT_3V2,
425              onChecked: () => {
426                this.foldedRegionLayoutOptions.verticalSplitRatio = PresetSplitRatio.LAYOUT_3V2
427              }
428            },
429            {
430              label: "未定义",
431              value: undefined,
432              onChecked: () => {
433                this.foldedRegionLayoutOptions.verticalSplitRatio = undefined
434              }
435            }
436          ]
437        })
438      }
439      .constraintSize({ minHeight: "100%" })
440    }
441  }
442
443  @Builder
444  MinorRegion() {
445    Region({
446      title: "悬停态配置",
447      compBackgroundColor: "rgba(0, 255, 0, 0.1)"
448    }) {
449      Column({ space: 4 }) {
450        RadioOption({
451          label: "悬停态水平宽度比",
452          value: this.foldingRegionLayoutOptions.horizontalSplitRatio,
453          options: [
454            {
455              label: "1:1",
456              value: PresetSplitRatio.LAYOUT_1V1,
457              onChecked: () => {
458                this.foldingRegionLayoutOptions.horizontalSplitRatio = PresetSplitRatio.LAYOUT_1V1
459              }
460            },
461            {
462              label: "2:3",
463              value: PresetSplitRatio.LAYOUT_2V3,
464              onChecked: () => {
465                this.foldingRegionLayoutOptions.horizontalSplitRatio = PresetSplitRatio.LAYOUT_2V3
466              }
467            },
468            {
469              label: "3:2",
470              value: PresetSplitRatio.LAYOUT_3V2,
471              onChecked: () => {
472                this.foldingRegionLayoutOptions.horizontalSplitRatio = PresetSplitRatio.LAYOUT_3V2
473              }
474            },
475            {
476              label: "未定义",
477              value: undefined,
478              onChecked: () => {
479                this.foldingRegionLayoutOptions.horizontalSplitRatio = undefined
480              }
481            },
482          ]
483        })
484
485        SwitchOption({
486          label: "悬停态是否显示扩展区",
487          value: this.foldingRegionLayoutOptions.showExtraRegion,
488          onChange: (checked) => {
489            this.foldingRegionLayoutOptions.showExtraRegion = checked;
490          }
491        })
492
493        if (this.foldingRegionLayoutOptions.showExtraRegion) {
494          RadioOption({
495            label: "悬停态扩展区位置",
496            value: this.foldingRegionLayoutOptions.extraRegionPosition,
497            options: [
498              {
499                label: "顶部",
500                value: ExtraRegionPosition.TOP,
501                onChecked: () => {
502                  this.foldingRegionLayoutOptions.extraRegionPosition = ExtraRegionPosition.TOP
503                }
504              },
505              {
506                label: "底部",
507                value: ExtraRegionPosition.BOTTOM,
508                onChecked: () => {
509                  this.foldingRegionLayoutOptions.extraRegionPosition = ExtraRegionPosition.BOTTOM
510                }
511              },
512              {
513                label: "未定义",
514                value: undefined,
515                onChecked: () => {
516                  this.foldingRegionLayoutOptions.extraRegionPosition = undefined
517                }
518              },
519            ]
520          })
521        }
522      }
523      .constraintSize({ minHeight: "100%" })
524    }
525  }
526
527  @Builder
528  ExtraRegion() {
529    Region({
530      title: "展开态配置",
531      compBackgroundColor: "rgba(0, 0, 255, 0.1)"
532    }) {
533      Column({ space: 4 }) {
534        RadioOption({
535          label: "展开态水平宽度比",
536          value: this.expandedRegionLayoutOptions.horizontalSplitRatio,
537          options: [
538            {
539              label: "1:1",
540              value: PresetSplitRatio.LAYOUT_1V1,
541              onChecked: () => {
542                this.expandedRegionLayoutOptions.horizontalSplitRatio = PresetSplitRatio.LAYOUT_1V1
543              }
544            },
545            {
546              label: "2:3",
547              value: PresetSplitRatio.LAYOUT_2V3,
548              onChecked: () => {
549                this.expandedRegionLayoutOptions.horizontalSplitRatio = PresetSplitRatio.LAYOUT_2V3
550              }
551            },
552            {
553              label: "3:2",
554              value: PresetSplitRatio.LAYOUT_3V2,
555              onChecked: () => {
556                this.expandedRegionLayoutOptions.horizontalSplitRatio = PresetSplitRatio.LAYOUT_3V2
557              }
558            },
559            {
560              label: "未定义",
561              value: undefined,
562              onChecked: () => {
563                this.expandedRegionLayoutOptions.horizontalSplitRatio = undefined
564              }
565            },
566          ]
567        })
568
569        RadioOption({
570          label: "展开态垂直高度度比",
571          value: this.expandedRegionLayoutOptions.verticalSplitRatio,
572          options: [
573            {
574              label: "1:1",
575              value: PresetSplitRatio.LAYOUT_1V1,
576              onChecked: () => {
577                this.expandedRegionLayoutOptions.verticalSplitRatio = PresetSplitRatio.LAYOUT_1V1
578              }
579            },
580            {
581              label: "2:3",
582              value: PresetSplitRatio.LAYOUT_2V3,
583              onChecked: () => {
584                this.expandedRegionLayoutOptions.verticalSplitRatio = PresetSplitRatio.LAYOUT_2V3
585              }
586            },
587            {
588              label: "3:2",
589              value: PresetSplitRatio.LAYOUT_3V2,
590              onChecked: () => {
591                this.expandedRegionLayoutOptions.verticalSplitRatio = PresetSplitRatio.LAYOUT_3V2
592              }
593            },
594            {
595              label: "未定义",
596              value: undefined,
597              onChecked: () => {
598                this.expandedRegionLayoutOptions.verticalSplitRatio = undefined
599              }
600            }
601          ]
602        })
603
604        SwitchOption({
605          label: "展开态扩展区是否上下贯穿",
606          value: this.expandedRegionLayoutOptions.isExtraRegionPerpendicular,
607          onChange: (checked) => {
608            this.expandedRegionLayoutOptions.isExtraRegionPerpendicular = checked;
609          }
610        })
611
612        if (!this.expandedRegionLayoutOptions.isExtraRegionPerpendicular) {
613          RadioOption({
614            label: "展开态扩展区位置",
615            value: this.expandedRegionLayoutOptions.extraRegionPosition,
616            options: [
617              {
618                label: "顶部",
619                value: ExtraRegionPosition.TOP,
620                onChecked: () => {
621                  this.expandedRegionLayoutOptions.extraRegionPosition = ExtraRegionPosition.TOP
622                }
623              },
624              {
625                label: "底部",
626                value: ExtraRegionPosition.BOTTOM,
627                onChecked: () => {
628                  this.expandedRegionLayoutOptions.extraRegionPosition = ExtraRegionPosition.BOTTOM
629                }
630              },
631              {
632                label: "未定义",
633                value: undefined,
634                onChecked: () => {
635                  this.expandedRegionLayoutOptions.extraRegionPosition = undefined
636                }
637              },
638            ]
639          })
640        }
641      }
642      .constraintSize({ minHeight: "100%" })
643    }
644  }
645
646  build() {
647    Column() {
648      FoldSplitContainer({
649        primary: () => {
650          this.MajorRegion()
651        },
652        secondary: () => {
653          this.MinorRegion()
654        },
655        extra: () => {
656          this.ExtraRegion()
657        },
658        expandedLayoutOptions: this.expandedRegionLayoutOptions,
659        hoverModeLayoutOptions: this.foldingRegionLayoutOptions,
660        foldedLayoutOptions: this.foldedRegionLayoutOptions,
661      })
662    }
663    .width("100%")
664    .height("100%")
665  }
666}
667```
668
669| 折叠态 | 展开态 | 悬停态 |
670| ----- | ------ | ------ |
671| ![](figures/foldsplitcontainer-7.png) | ![](figures/foldsplitcontainer-8.png) | ![](figures/foldsplitcontainer-11.png) |
672|                                       | ![](figures/foldsplitcontainer-9.png) | ![](figures/foldsplitcontainer-12.png) |
673|                                       | ![](figures/foldsplitcontainer-10.png) | ![](figures/foldsplitcontainer-13.png) |
674