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