1# Binding a Semi-Modal Page (bindSheet) 2 3A semi-modal page, implemented using [bindSheet](../reference/apis-arkui/arkui-ts/ts-universal-attributes-sheet-transition.md#bindsheet), is a modal, non-full-screen popup interaction page by default, allowing parts of the underlying parent view to be visible. This helps users retain the context of their parent view while interacting with the semi-modal. 4 5Semi-modal pages are suitable for displaying simple tasks or information panels, such as personal information, text introductions, sharing panels, creating schedules, and adding content. If a semi-modal page needs to be displayed in a way that could potentially affect the parent view, it can be configured to use a non-modal interaction form. 6 7Semi-modal pages have different form capabilities on devices of different widths. For details about the form requirements on devices with different widths, see the [preferType](../reference/apis-arkui/arkui-ts/ts-universal-attributes-sheet-transition.md#sheetoptions) property. You can use **bindSheet** to build semi-modal transition effects. For details, see [Modal Transition](arkts-modal-transition.md#creating-sheet-transition-with-bindsheet). For complex or lengthy user processes, consider other transition methods instead of semi-modals, such as [full-modal transition](arkts-contentcover-page.md) and [navigation transition](arkts-navigation-navigation.md). 8 9## Constraints 10 11 - When a [UIExtension](../reference/apis-arkui/js-apis-arkui-uiExtension.md) is embedded in a semi-modal, launching another semi-modal or popup window within the UIExtension is not allowed. 12 13 - In scenarios without secondary confirmation or custom close behavior, avoid using the [shouldDismiss/onWillDismiss](../reference/apis-arkui/arkui-ts/ts-universal-attributes-sheet-transition.md#sheetoptions) API. 14 15## Lifecycle 16 17The semi-modal page provides lifecycle callbacks to notify the application of the lifecycle status of the popup. These callbacks are triggered in the following order: onWillAppear -> onAppear -> onWillDisappear -> onDisappear. 18 19| Name |Type| Description | 20| ----------------- | ------ | ---------------------------- | 21| onWillAppear | () => void | Callback for when the semi-modal page is about to appear (before the animation starts).| 22| onAppear | () => void | Callback for when the semi-modal page appears (after the animation ends). | 23| onWillDisappear | () => void | Callback for when the semi-modal page is about to disappear (before the animation starts).| 24| onDisappear |() => void | Callback for when the semi-modal page disappears (after the animation ends). | 25 26## Using Nested Scrolling 27 28The priority of operations during scrolling in the content area of a semi-modal panel is as follows: 29 301. 1. Content at the top and content that cannot be scrolled 31 32 Swiping up: The sheet will attempt to expand upwards. If no expansion is possible, the content will scroll. 33 34 Swiping down: The panel will attempt to contract downwards. If no contraction is possible, the panel will close. 352. 2. Content in the middle (scrollable both up and down) 36 37 Swiping up or down: The content will scroll until it reaches the top or bottom of the panel. 38 393. 3. Content at the bottom (scrollable) 40 41 Swiping up: The content area will display a rebound effect without changing the panel position. 42 43 Swiping down: The content will scroll until it reaches the top. 44 45By default, the nested scrolling mode for the half-modal panel is as follows: {Forward: PARENT\_FIRST, Backward: SELF\_FIRST} 46 47If you want to define a scrollable container, such as **List** or **Scroll**, in the panel content builder, and combine it with the semi-modal's interaction capabilities, you must set the nested scrolling attributes for the scrollable container in the vertical direction. 48 49```ts 50.nestedScroll({ 51 // Nested scrolling options for the scrollable component when it scrolls towards the end, with the gesture upwards. 52 scrollForward: NestedScrollMode.PARENT_FIRST, 53 // Nested scrolling options for the scrollable component when it scrolls towards the start, with the gesture downwards. 54 scrollBackward: NestedScrollMode.SELF_FIRST, 55}) 56``` 57 58The sample code is as follows: 59 60```ts 61@Entry 62@Component 63struct SheetDemo { 64 @State isShowSheet: boolean = false; 65 private items: number[] = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]; 66 67 @Builder 68 SheetBuilder() { 69 Column() { 70 // Step 1: Customize a scrollable container. 71 List({ space: '10vp' }) { 72 ForEach(this.items, (item: number) => { 73 ListItem() { 74 Text(String(item)).fontSize(16).fontWeight(FontWeight.Bold) 75 }.width('90%').height('80vp').backgroundColor('#ff53ecd9').borderRadius(10) 76 }) 77 } 78 .alignListItem(ListItemAlign.Center) 79 .margin({ top: '10vp' }) 80 .width('100%') 81 .height('900px') 82 // Step 2: Set the nested scrolling attributes of the scrollable component. 83 .nestedScroll({ 84 scrollForward: NestedScrollMode.PARENT_FIRST, 85 scrollBackward: NestedScrollMode.SELF_FIRST, 86 }) 87 88 Text("Non-scrollable area") 89 .width('100%') 90 .backgroundColor(Color.Gray) 91 .layoutWeight(1) 92 .textAlign(TextAlign.Center) 93 .align(Alignment.Top) 94 }.width('100%').height('100%') 95 } 96 97 build() { 98 Column() { 99 Button('Open Sheet').width('90%').height('80vp') 100 .onClick(() => { 101 this.isShowSheet = !this.isShowSheet; 102 }) 103 .bindSheet($$this.isShowSheet, this.SheetBuilder(), { 104 detents: [SheetSize.MEDIUM, SheetSize.LARGE, 600], 105 preferType: SheetType.BOTTOM, 106 title: { title: 'Nested Scrolling Scenario' }, 107 }) 108 }.width('100%').height('100%') 109 .justifyContent(FlexAlign.Center) 110 } 111} 112``` 113 114## Secondary Confirmation Capability 115 116To implement the secondary confirmation capability, you are advised to use the **onWillDismiss** API, with which you can handle secondary confirmation or custom close behavior in the callback. 117 118> **NOTE** 119> 120> After the **onWillDismiss** API is declared, all close operations of the semi-modal page, including side swiping, touching the close button, touching the mask, and pulling down, must be implemented by calling the **dismiss** API. If this logic is not implemented, the semi-modal page will not respond to the above close operations. 121 122```ts 123// Step 1: Declare the onWillDismiss callback. 124onWillDismiss: ((DismissSheetAction: DismissSheetAction) => { 125// Step 2: Implement the secondary confirmation interaction, using an AlertDialog component to prompt the user for confirmation. 126 this.getUIContext().showAlertDialog( 127 { 128 message: 'Do you want to close the semi-modal?', 129 autoCancel: true, 130 alignment: DialogAlignment.Bottom, 131 gridCount: 4, 132 offset: { dx: 0, dy: -20 }, 133 primaryButton: { 134 value: 'cancel', 135 action: () => { 136 console.info('Callback when the cancel button is clicked'); 137 } 138 }, 139 secondaryButton: { 140 enabled: true, 141 defaultFocus: true, 142 style: DialogButtonStyle.HIGHLIGHT, 143 value: 'ok', 144 // Step 3: Define the logic for closing the semi-modal within the AlertDialog button callback. 145 action: () => { 146 // Step 4: Call dismiss() to close the semi-modal when the logic in step 3 is triggered. 147 DismissSheetAction.dismiss(); 148 console.info('Callback when the ok button is clicked'); 149 } 150 }, 151 cancel: () => { 152 console.info('AlertDialog Closed callbacks'); 153 } 154 } 155 ) 156}) 157``` 158 159## Blocking Specific Dismiss Behavior 160 161After the **onWillDismiss** API is declared, it takes control over all dismiss behaviors of the semi-modal. This means that the semi-modal can be dismissed only when you explicitly call the **dismiss** API. You can customize the dismissal logic using **if** statements or other logic. 162For example, you might want the semi-modal to be dismissed only when the user swipes down. Here's how you can implement this: 163 164```ts 165onWillDismiss: ((DismissSheetAction: DismissSheetAction) => { 166 if (DismissSheetAction.reason === DismissReason.SLIDE_DOWN) { 167 DismissSheetAction.dismiss(); // Register the dismiss behavior. 168 } 169}), 170``` 171 172To enhance the user experience during the swiping down action, you can use the **onWillSpringBackWhenDismiss** API. 173Just like with **onWillDismiss**, after **onWillSpringBackWhenDismiss** is declared, the rebound operation during a swipe-down of the half-modal requires handling with **SpringBackAction.springBack()**; without this logic, no rebound will occur. 174 175Here is the specific code to prevent the rebound effect when the semi-modal is swiped down: 176 177```ts 178onWillDismiss: ((DismissSheetAction: DismissSheetAction) => { 179 if (DismissSheetAction.reason === DismissReason.SLIDE_DOWN) { 180 DismissSheetAction.dismiss(); // Register the dismiss behavior. 181 } 182}), 183 184onWillSpringBackWhenDismiss: ((SpringBackAction: SpringBackAction) => { 185 // No springBack is registered, so the half-modal will not bounce back when swiped down. 186}), 187``` 188