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