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#bindoptions) 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-transition.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/onWilDismiss](../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 be displayed (before the animation starts).| 22| onAppear | () => void | Callback for when the semi-modal page is displayed (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 45The default nested mode for the above semi-modal interactions is: {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 }.alignListItem(ListItemAlign.Center).margin({top:'10vp'}).width('100%').height('900px') 78 // Step 2: Set the nested scrolling attributes of the scrollable component. 79 .nestedScroll({ 80 scrollForward: NestedScrollMode.PARENT_FIRST, 81 scrollBackward: NestedScrollMode.SELF_FIRST, 82 }) 83 84 Text("Non-scrollable area").width('100%').backgroundColor(Color.Gray) 85 .layoutWeight(1) 86 .textAlign(TextAlign.Center) 87 .align(Alignment.Top) 88 }.width('100%').height('100%') 89 } 90 build() { 91 Column() { 92 Button('Open Sheet').width('90%').height('80vp') 93 .onClick(()=>{ 94 this.isShowSheet = !this.isShowSheet 95 }) 96 .bindSheet($$this.isShowSheet, this.SheetBuilder(), { 97 detents:[SheetSize.MEDIUM, SheetSize.LARGE, 600], 98 preferType: SheetType.BOTTOM, 99 title: {title: 'Nested Scrolling Scenario'}, 100 }) 101 }.width('100%').height('100%') 102 .justifyContent(FlexAlign.Center) 103 } 104} 105``` 106 107## Secondary Confirmation Capability 108 109To 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. 110 111> **NOTE** 112> 113> 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. 114 115```ts 116// Step 1: Declare the onWillDismiss callback. 117onWillDismiss: ((DismissSheetAction: DismissSheetAction) => { 118// Step 2: Implement the secondary confirmation interaction, using an AlertDialog component to prompt the user for confirmation. 119 AlertDialog.show( 120 { 121 message: 'Do you want to close the semi-modal?', 122 autoCancel: true, 123 alignment: DialogAlignment.Bottom, 124 gridCount: 4, 125 offset: { dx: 0, dy: -20 }, 126 primaryButton: { 127 value: 'cancel', 128 action: () => { 129 console.info('Callback when the cancel button is clicked') 130 } 131 }, 132 secondaryButton: { 133 enabled: true, 134 defaultFocus: true, 135 style: DialogButtonStyle.HIGHLIGHT, 136 value: 'ok', 137 // Step 3: Define the logic for closing the semi-modal within the AlertDialog button callback. 138 action: () => { 139 // Step 4: Call dismiss() to close the semi-modal when the logic in step 3 is triggered. 140 DismissSheetAction.dismiss() 141 console.info('Callback when the ok button is clicked') 142 } 143 }, 144 cancel: () => { 145 console.info('AlertDialog Closed callbacks') 146 } 147 } 148 ) 149}) 150``` 151 152## Blocking Specific Dismiss Behavior 153 154After 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. This allows you to implement custom logic to control when the semi-modal should close. 155For example, you might want the semi-modal to close only when the user swipes down. Here's how you can implement this: 156 157```ts 158onWillDismiss: ((DismissSheetAction: DismissSheetAction) => { 159 if (DismissSheetAction.reason == DismissReason.SLIDE_DOWN) { 160 DismissSheetAction.dismiss() // Register the dismiss behavior. 161 } 162}), 163``` 164 165To enhance the user experience during the swiping down action, you can use the **onWillSpringBackWhenDismiss** API. 166This API allows you to control the rebound effect when the semi-modal is swiped down. By default, the semi-modal will rebound when swiped down, but you can prevent this behavior by not calling **SpringBackAction.springBack()**. 167 168Here is the specific code to prevent the rebound effect when the semi-modal is swiped down: 169 170```ts 171onWillDismiss: ((DismissSheetAction: DismissSheetAction) => { 172 if (DismissSheetAction.reason == DismissReason.SLIDE_DOWN) { 173 DismissSheetAction.dismiss() // Register the dismiss behavior. 174 } 175}), 176 177onWillSpringBackWhenDismiss: ((SpringBackAction: SpringBackAction) => { 178 // Do not call SpringBackAction.springBack(), so no rebound behavior occurs. 179}), 180``` 181