• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1# FoldSplitContainer
2
3
4**FoldSplitContainer** is a layout container designed to manage regions for two-panel and three-panel arrangements on a foldable device across various states, including the expanded state, the hover state, and the folded state.
5
6
7> **NOTE**
8>
9> This component is supported since API version 12. Updates will be marked with a superscript to indicate their earliest API version.
10
11## Modules to Import
12
13```ts
14import { FoldSplitContainer } from '@kit.ArkUI';
15```
16
17## Child Components
18
19Not supported
20
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
34Creates a **FoldSplitContainer** component to manage regions for two-panel and three-panel arrangements on a foldable device across various states, including the expanded state, the hover state, and the folded state.
35
36**Decorator**: \@Component
37
38**Atomic service API**: This API can be used in atomic services since API version 12.
39
40**System capability**: SystemCapability.ArkUI.ArkUI.Full
41
42| Name| Type| Mandatory| Decorator| Description|
43| -------- | -------- | -------- | -------- | -------- |
44| primary | ()=>void | Yes| @BuilderParam | Callback function for the primary region.|
45| secondary | ()=>void | Yes| @BuilderParam | Callback function for the secondary region.|
46| extra | ()=>void | No| @BuilderParam | Callback function for the extra region. If this parameter is not provided, there is no corresponding region.|
47| expandedLayoutOptions | [ExpandedRegionLayoutOptions](#expandedregionlayoutoptions) | Yes| @Prop | Layout information for the expanded state.|
48| hoverModeLayoutOptions | [HoverModeRegionLayoutOptions](#hovermoderegionlayoutoptions) | Yes| @Prop | Layout information for the hover state.|
49| foldedLayoutOptions | [FoldedRegionLayoutOptions](#foldedregionlayoutoptions) | Yes| @Prop | Layout information for the folded state.|
50| animationOptions | [AnimateParam](ts-explicit-animation.md#animateparam) \| null | No| @Prop | Animation settings. The value **null** indicates that the animation is disabled.|
51| onHoverStatusChange | [OnHoverStatusChangeHandler](#onhoverstatuschangehandler) | No| - | Callback function triggered when the foldable device enters or exits the hover state.|
52
53## ExpandedRegionLayoutOptions
54
55Defines the layout information for the expanded state.
56
57**Atomic service API**: This API can be used in atomic services since API version 12.
58
59**System capability**: SystemCapability.ArkUI.ArkUI.Full
60
61| Name| Type| Mandatory| Description|
62| -------- | -------- | -------- | -------- |
63| isExtraRegionPerpendicular | boolean | No| Whether the extra region extends perpendicularly through the entire component from top to bottom. This setting takes effect only when **extra** is effective. Default value: **true**|
64| verticalSplitRatio | number | No| Height ratio between the primary and secondary regions. Default value: **PresetSplitRatio.LAYOUT_1V1**|
65| horizontalSplitRatio | number | No| Width ratio between the primary and extra regions. This setting takes effect only when **extra** is effective. Default value: **PresetSplitRatio.LAYOUT_3V2**|
66| extraRegionPosition | [ExtraRegionPosition](#extraregionposition) | No| Position information of the extra region. This setting takes effect only when **isExtraRegionPerpendicular** is **false**. Default value: **ExtraRegionPosition.top**|
67
68## HoverModeRegionLayoutOptions
69
70Defines the layout information for the hover state.
71
72**Atomic service API**: This API can be used in atomic services since API version 12.
73
74**System capability**: SystemCapability.ArkUI.ArkUI.Full
75
76| Name| Type| Mandatory| Description|
77| -------- | -------- | -------- | -------- |
78| showExtraRegion | boolean | No| Whether to display the extra region in the half-folded state. Default value: **false**|
79| horizontalSplitRatio | number | No| Width ratio between the primary and extra regions. This setting takes effect only when **extra** is effective. Default value: **PresetSplitRatio.LAYOUT_3V2**|
80| extraRegionPosition | [ExtraRegionPosition](#extraregionposition) | No| Position information of the extra region. This setting takes effect only when **showExtraRegion** is set. Default value: **ExtraRegionPosition.top**|
81
82> **NOTE**
83>
84> 1. When the device is in the hover state, there is an avoid area, and layout calculations need to account for the impact of the avoid area on the layout.
85> 2 In the hover state, the upper half screen is used for display, and the lower half is used for interaction.
86
87## FoldedRegionLayoutOptions
88
89Defines the layout information for the folded state.
90
91**Atomic service API**: This API can be used in atomic services since API version 12.
92
93**System capability**: SystemCapability.ArkUI.ArkUI.Full
94
95| Name| Type| Mandatory| Description|
96| -------- | -------- | -------- | -------- |
97| verticalSplitRatio | number | No| Height ratio between the primary and secondary regions. Default value: **PresetSplitRatio.LAYOUT_1V1**|
98
99## OnHoverStatusChangeHandler
100
101type OnHoverStatusChangeHandler = (status: HoverModeStatus) => void
102
103Implements a handler for the **onHoverStatusChange** event.
104
105**Atomic service API**: This API can be used in atomic services since API version 12.
106
107**System capability**: SystemCapability.ArkUI.ArkUI.Full
108
109**Parameters**
110
111| Name| Type| Mandatory| Description|
112| -------- | -------- | -------- | -------- |
113| status | [HoverModeStatus](#hovermodestatus) | Yes| Callback function triggered when the foldable device enters or exits the hover state.|
114
115## HoverModeStatus
116
117Provides information about the device or application's folding, rotation, and window state.
118
119**Atomic service API**: This API can be used in atomic services since API version 12.
120
121**System capability**: SystemCapability.ArkUI.ArkUI.Full
122
123| Name| Type| Mandatory| Description|
124| -------- | -------- | -------- | -------- |
125| foldStatus | [display.FoldStatus](../js-apis-display.md#foldstatus10) | Yes| Fold status of the device.|
126| isHoverMode | boolean | Yes| Whether the application is in the hover state.|
127| appRotation | number | Yes| Rotation angle of the application.|
128| windowStatusType | [window.WindowStatusType](../js-apis-window.md#windowstatustype11) | Yes| Window mode.|
129
130## ExtraRegionPosition
131
132Provides the position information of the extra region.
133
134**Atomic service API**: This API can be used in atomic services since API version 12.
135
136**System capability**: SystemCapability.ArkUI.ArkUI.Full
137
138| Name| Value| Description|
139| -------- | -------- | -------- |
140| TOP | 1 | The extra region is in the upper half of the component.|
141| BOTTOM | 2 | The extra region is in the lower half of the component.|
142
143## PresetSplitRatio
144
145Enumerates the split ratios.
146
147**Atomic service API**: This API can be used in atomic services since API version 12.
148
149**System capability**: SystemCapability.ArkUI.ArkUI.Full
150
151| Name| Value| Description|
152| -------- | -------- | -------- |
153| LAYOUT_1V1 | 1 | 1:1.|
154| LAYOUT_3V2 | 1.5 | 3:2.|
155| LAYOUT_2V3 | 0.6666666666666666 | 2:3.|
156
157## Example
158
159### Example 1: Setting Up a Two-Panel Layout
160
161This example demonstrates how to control the region for a two-panel layout on a foldable screen across different states: folded, expanded, and hover.
162
163```ts
164import { FoldSplitContainer } from '@kit.ArkUI';
165
166@Entry
167@Component
168struct TwoColumns {
169  @Builder
170  privateRegion() {
171    Text("Primary")
172      .backgroundColor('rgba(255, 0, 0, 0.1)')
173      .fontSize(28)
174      .textAlign(TextAlign.Center)
175      .height('100%')
176      .width('100%')
177  }
178
179  @Builder
180  secondaryRegion() {
181    Text("Secondary")
182      .backgroundColor('rgba(0, 255, 0, 0.1)')
183      .fontSize(28)
184      .textAlign(TextAlign.Center)
185      .height('100%')
186      .width('100%')
187  }
188
189  build() {
190    RelativeContainer() {
191      FoldSplitContainer({
192        primary: () => {
193          this.privateRegion()
194        },
195        secondary: () => {
196          this.secondaryRegion()
197        }
198      })
199    }
200    .height('100%')
201    .width('100%')
202  }
203}
204```
205
206| Folded| Expanded| Hover|
207| ----- | ------ | ------ |
208| ![](figures/foldsplitcontainer-1.png) | ![](figures/foldsplitcontainer-2.png) | ![](figures/foldsplitcontainer-3.png) |
209
210### Example 2: Setting Up a Three-Panel Layout
211
212This example demonstrates how to control the region for a three-panel layout on a foldable screen across different states: folded, expanded, and hover.
213
214```ts
215import { FoldSplitContainer } from '@kit.ArkUI';
216
217@Entry
218@Component
219struct ThreeColumns {
220  @Builder
221  privateRegion() {
222    Text("Primary")
223      .backgroundColor('rgba(255, 0, 0, 0.1)')
224      .fontSize(28)
225      .textAlign(TextAlign.Center)
226      .height('100%')
227      .width('100%')
228  }
229
230  @Builder
231  secondaryRegion() {
232    Text("Secondary")
233      .backgroundColor('rgba(0, 255, 0, 0.1)')
234      .fontSize(28)
235      .textAlign(TextAlign.Center)
236      .height('100%')
237      .width('100%')
238  }
239
240  @Builder
241  extraRegion() {
242    Text("Extra")
243      .backgroundColor('rgba(0, 0, 255, 0.1)')
244      .fontSize(28)
245      .textAlign(TextAlign.Center)
246      .height('100%')
247      .width('100%')
248  }
249
250  build() {
251    RelativeContainer() {
252      FoldSplitContainer({
253        primary: () => {
254          this.privateRegion()
255        },
256        secondary: () => {
257          this.secondaryRegion()
258        },
259        extra: () => {
260          this.extraRegion()
261        }
262      })
263    }
264    .height('100%')
265    .width('100%')
266  }
267}
268```
269
270| Folded| Expanded| Hover|
271| ----- | ------ | ------ |
272| ![](figures/foldsplitcontainer-4.png) | ![](figures/foldsplitcontainer-5.png) | ![](figures/foldsplitcontainer-6.png) |
273
274### Example 3: Setting Layout Information in Expanded State
275
276This example illustrates how to configure **ExpandedRegionLayoutOptions** to set the layout information for a foldable screen when it is in the expanded state.
277
278```ts
279import {
280  FoldSplitContainer,
281  PresetSplitRatio,
282  ExtraRegionPosition,
283  ExpandedRegionLayoutOptions,
284  HoverModeRegionLayoutOptions,
285  FoldedRegionLayoutOptions
286} from '@kit.ArkUI';
287
288@Component
289struct Region {
290  @Prop title: string;
291  @BuilderParam content: () => void;
292  @Prop compBackgroundColor: string;
293
294  build() {
295    Column({ space: 8 }) {
296      Text(this.title)
297        .fontSize("24fp")
298        .fontWeight(600)
299
300      Scroll() {
301        this.content()
302      }
303      .layoutWeight(1)
304      .width("100%")
305    }
306    .backgroundColor(this.compBackgroundColor)
307    .width("100%")
308    .height("100%")
309    .padding(12)
310  }
311}
312
313const noop = () => {
314};
315
316@Component
317struct SwitchOption {
318  @Prop label: string = ""
319  @Prop value: boolean = false
320  public onChange: (checked: boolean) => void = noop;
321
322  build() {
323    Row() {
324      Text(this.label)
325      Blank()
326      Toggle({ type: ToggleType.Switch, isOn: this.value })
327        .onChange((isOn) => {
328          this.onChange(isOn);
329        })
330    }
331    .backgroundColor(Color.White)
332    .borderRadius(8)
333    .padding(8)
334    .width("100%")
335  }
336}
337
338interface RadioOptions {
339  label: string;
340  value: Object | undefined | null;
341  onChecked: () => void;
342}
343
344@Component
345struct RadioOption {
346  @Prop label: string;
347  @Prop value: Object | undefined | null;
348  @Prop options: Array<RadioOptions>;
349
350  build() {
351    Row() {
352      Text(this.label)
353      Blank()
354      Column({ space: 4 }) {
355        ForEach(this.options, (option: RadioOptions) => {
356          Row() {
357            Radio({
358              group: this.label,
359              value: JSON.stringify(option.value),
360            })
361              .checked(this.value === option.value)
362              .onChange((checked) => {
363                if (checked) {
364                  option.onChecked();
365                }
366              })
367            Text(option.label)
368          }
369        })
370      }
371      .alignItems(HorizontalAlign.Start)
372    }
373    .alignItems(VerticalAlign.Top)
374    .backgroundColor(Color.White)
375    .borderRadius(8)
376    .padding(8)
377    .width("100%")
378  }
379}
380
381@Entry
382@Component
383struct Index {
384  @State expandedRegionLayoutOptions: ExpandedRegionLayoutOptions = {
385    horizontalSplitRatio: PresetSplitRatio.LAYOUT_3V2,
386    verticalSplitRatio: PresetSplitRatio.LAYOUT_1V1,
387    isExtraRegionPerpendicular: true,
388    extraRegionPosition: ExtraRegionPosition.TOP
389  };
390  @State foldingRegionLayoutOptions: HoverModeRegionLayoutOptions = {
391    horizontalSplitRatio: PresetSplitRatio.LAYOUT_3V2,
392    showExtraRegion: false,
393    extraRegionPosition: ExtraRegionPosition.TOP
394  };
395  @State foldedRegionLayoutOptions: FoldedRegionLayoutOptions = {
396    verticalSplitRatio: PresetSplitRatio.LAYOUT_1V1
397  };
398
399  @Builder
400  MajorRegion() {
401    Region({
402      title: "Folded state settings",
403      compBackgroundColor: "rgba(255, 0, 0, 0.1)",
404    }) {
405      Column({ space: 4 }) {
406        RadioOption({
407          label: "Height ratio",
408          value: this.foldedRegionLayoutOptions.verticalSplitRatio,
409          options: [
410            {
411              label: "1:1",
412              value: PresetSplitRatio.LAYOUT_1V1,
413              onChecked: () => {
414                this.foldedRegionLayoutOptions.verticalSplitRatio = PresetSplitRatio.LAYOUT_1V1
415              }
416            },
417            {
418              label: "2:3",
419              value: PresetSplitRatio.LAYOUT_2V3,
420              onChecked: () => {
421                this.foldedRegionLayoutOptions.verticalSplitRatio = PresetSplitRatio.LAYOUT_2V3
422              }
423            },
424            {
425              label: "3:2",
426              value: PresetSplitRatio.LAYOUT_3V2,
427              onChecked: () => {
428                this.foldedRegionLayoutOptions.verticalSplitRatio = PresetSplitRatio.LAYOUT_3V2
429              }
430            },
431            {
432              label: "Not set",
433              value: undefined,
434              onChecked: () => {
435                this.foldedRegionLayoutOptions.verticalSplitRatio = undefined
436              }
437            }
438          ]
439        })
440      }
441      .constraintSize({ minHeight: "100%" })
442    }
443  }
444
445  @Builder
446  MinorRegion() {
447    Region({
448      title: "Hover state settings",
449      compBackgroundColor: "rgba(0, 255, 0, 0.1)"
450    }) {
451      Column({ space: 4 }) {
452        RadioOption({
453          label: "Width ratio",
454          value: this.foldingRegionLayoutOptions.horizontalSplitRatio,
455          options: [
456            {
457              label: "1:1",
458              value: PresetSplitRatio.LAYOUT_1V1,
459              onChecked: () => {
460                this.foldingRegionLayoutOptions.horizontalSplitRatio = PresetSplitRatio.LAYOUT_1V1
461              }
462            },
463            {
464              label: "2:3",
465              value: PresetSplitRatio.LAYOUT_2V3,
466              onChecked: () => {
467                this.foldingRegionLayoutOptions.horizontalSplitRatio = PresetSplitRatio.LAYOUT_2V3
468              }
469            },
470            {
471              label: "3:2",
472              value: PresetSplitRatio.LAYOUT_3V2,
473              onChecked: () => {
474                this.foldingRegionLayoutOptions.horizontalSplitRatio = PresetSplitRatio.LAYOUT_3V2
475              }
476            },
477            {
478              label: "Not set",
479              value: undefined,
480              onChecked: () => {
481                this.foldingRegionLayoutOptions.horizontalSplitRatio = undefined
482              }
483            },
484          ]
485        })
486
487        SwitchOption({
488          label: "Show extra region",
489          value: this.foldingRegionLayoutOptions.showExtraRegion,
490          onChange: (checked) => {
491            this.foldingRegionLayoutOptions.showExtraRegion = checked;
492          }
493        })
494
495        if (this.foldingRegionLayoutOptions.showExtraRegion) {
496          RadioOption({
497            label: "Extra region location,"
498            value: this.foldingRegionLayoutOptions.extraRegionPosition,
499            options: [
500              {
501                label: "Top,"
502                value: ExtraRegionPosition.TOP,
503                onChecked: () => {
504                  this.foldingRegionLayoutOptions.extraRegionPosition = ExtraRegionPosition.TOP
505                }
506              },
507              {
508                label: "Bottom,"
509                value: ExtraRegionPosition.BOTTOM,
510                onChecked: () => {
511                  this.foldingRegionLayoutOptions.extraRegionPosition = ExtraRegionPosition.BOTTOM
512                }
513              },
514              {
515                label: "Not set",
516                value: undefined,
517                onChecked: () => {
518                  this.foldingRegionLayoutOptions.extraRegionPosition = undefined
519                }
520              },
521            ]
522          })
523        }
524      }
525      .constraintSize({ minHeight: "100%" })
526    }
527  }
528
529  @Builder
530  ExtraRegion() {
531    Region({
532      title: "Expanded state settings,"
533      compBackgroundColor: "rgba(0, 0, 255, 0.1)"
534    }) {
535      Column({ space: 4 }) {
536        RadioOption({
537          label: "Width ratio,"
538          value: this.expandedRegionLayoutOptions.horizontalSplitRatio,
539          options: [
540            {
541              label: "1:1",
542              value: PresetSplitRatio.LAYOUT_1V1,
543              onChecked: () => {
544                this.expandedRegionLayoutOptions.horizontalSplitRatio = PresetSplitRatio.LAYOUT_1V1
545              }
546            },
547            {
548              label: "2:3",
549              value: PresetSplitRatio.LAYOUT_2V3,
550              onChecked: () => {
551                this.expandedRegionLayoutOptions.horizontalSplitRatio = PresetSplitRatio.LAYOUT_2V3
552              }
553            },
554            {
555              label: "3:2",
556              value: PresetSplitRatio.LAYOUT_3V2,
557              onChecked: () => {
558                this.expandedRegionLayoutOptions.horizontalSplitRatio = PresetSplitRatio.LAYOUT_3V2
559              }
560            },
561            {
562              label: "Not set",
563              value: undefined,
564              onChecked: () => {
565                this.expandedRegionLayoutOptions.horizontalSplitRatio = undefined
566              }
567            },
568          ]
569        })
570
571        RadioOption({
572          label: "Height ratio",
573          value: this.expandedRegionLayoutOptions.verticalSplitRatio,
574          options: [
575            {
576              label: "1:1",
577              value: PresetSplitRatio.LAYOUT_1V1,
578              onChecked: () => {
579                this.expandedRegionLayoutOptions.verticalSplitRatio = PresetSplitRatio.LAYOUT_1V1
580              }
581            },
582            {
583              label: "2:3",
584              value: PresetSplitRatio.LAYOUT_2V3,
585              onChecked: () => {
586                this.expandedRegionLayoutOptions.verticalSplitRatio = PresetSplitRatio.LAYOUT_2V3
587              }
588            },
589            {
590              label: "3:2",
591              value: PresetSplitRatio.LAYOUT_3V2,
592              onChecked: () => {
593                this.expandedRegionLayoutOptions.verticalSplitRatio = PresetSplitRatio.LAYOUT_3V2
594              }
595            },
596            {
597              label: "Not set",
598              value: undefined,
599              onChecked: () => {
600                this.expandedRegionLayoutOptions.verticalSplitRatio = undefined
601              }
602            }
603          ]
604        })
605
606        SwitchOption({
607          label: "Show extra region perpendicularly,"
608          value: this.expandedRegionLayoutOptions.isExtraRegionPerpendicular,
609          onChange: (checked) => {
610            this.expandedRegionLayoutOptions.isExtraRegionPerpendicular = checked;
611          }
612        })
613
614        if (!this.expandedRegionLayoutOptions.isExtraRegionPerpendicular) {
615          RadioOption({
616            label: "Extra region location,"
617            value: this.expandedRegionLayoutOptions.extraRegionPosition,
618            options: [
619              {
620                label: "Top,"
621                value: ExtraRegionPosition.TOP,
622                onChecked: () => {
623                  this.expandedRegionLayoutOptions.extraRegionPosition = ExtraRegionPosition.TOP
624                }
625              },
626              {
627                label: "Bottom,"
628                value: ExtraRegionPosition.BOTTOM,
629                onChecked: () => {
630                  this.expandedRegionLayoutOptions.extraRegionPosition = ExtraRegionPosition.BOTTOM
631                }
632              },
633              {
634                label: "Not set",
635                value: undefined,
636                onChecked: () => {
637                  this.expandedRegionLayoutOptions.extraRegionPosition = undefined
638                }
639              },
640            ]
641          })
642        }
643      }
644      .constraintSize({ minHeight: "100%" })
645    }
646  }
647
648  build() {
649    Column() {
650      FoldSplitContainer({
651        primary: () => {
652          this.MajorRegion()
653        },
654        secondary: () => {
655          this.MinorRegion()
656        },
657        extra: () => {
658          this.ExtraRegion()
659        },
660        expandedLayoutOptions: this.expandedRegionLayoutOptions,
661        hoverModeLayoutOptions: this.foldingRegionLayoutOptions,
662        foldedLayoutOptions: this.foldedRegionLayoutOptions,
663      })
664    }
665    .width("100%")
666    .height("100%")
667  }
668}
669```
670
671| Folded| Expanded| Hover|
672| ----- | ------ | ------ |
673| ![](figures/foldsplitcontainer-7.png) | ![](figures/foldsplitcontainer-8.png) | ![](figures/foldsplitcontainer-11.png) |
674|                                       | ![](figures/foldsplitcontainer-9.png) | ![](figures/foldsplitcontainer-12.png) |
675|                                       | ![](figures/foldsplitcontainer-10.png) | ![](figures/foldsplitcontainer-13.png) |
676