1# Safe Area 2 3A safe area refers to the display area that isn't covered by a status bar, navigation bar, or any other component in the system-defined non-safe areas. By default, all the content you develop is placed within the safe area. If necessary, you can expand a component's safe area through the [expandSafeArea](#expandsafearea) attribute. This allows the component to extend its rendering area beyond the safe area without altering the layout. In addition, you can specify how to make space for the virtual keyboard through the [setKeyboardAvoidMode](#setkeyboardavoidmode11) attribute. To prevent text elements, such as a title bar, from overlapping with non-safe areas, you are advised to set the **expandSafeArea** attribute for the component to achieve an immersive effect. Alternatively, you can use the [setWindowLayoutFullScreen](../js-apis-window.md#setwindowlayoutfullscreen9) API directly to set an immersive layout. 4 5> **NOTE** 6> 7> This attribute is supported since API version 10. Updates will be marked with a superscript to indicate their earliest API version.<br> 8> By default, the notch area is not a non-safe area, and content can be displayed in this area.<br> 9> You can set the notch area as a non-safe area since API version 12, so that content is not displayed in this area. To do so, add the following to the **module.json5** file:<br> 10 "metadata": [<br> 11 {<br> 12 "name": "avoid_cutout",<br> 13 "value": "true",<br> 14 }<br> 15 ],<br> 16 17 18## expandSafeArea 19 20expandSafeArea(types?: Array<SafeAreaType>, edges?: Array<SafeAreaEdge>) 21 22Sets the safe area to be expanded to. 23 24**Atomic service API**: This API can be used in atomic services since API version 11. 25 26**System capability**: SystemCapability.ArkUI.ArkUI.Full 27 28**Parameters** 29 30| Name| Type | Mandatory| Description | 31| ------ | -------------------------------------------------- | ---- | ------------------------------------------------------------ | 32| types | Array <[SafeAreaType](ts-types.md#safeareatype10)> | No | Types of non-safe areas to extend into. For the **CUTOUT** type to take effect, the [Metadata](../../apis-ability-kit/js-apis-bundleManager-metadata.md) item must be added to the configuration file.<br>Default value: **[SafeAreaType.SYSTEM, SafeAreaType.CUTOUT, SafeAreaType.KEYBOARD]**| 33| edges | Array <[SafeAreaEdge](ts-types.md#safeareaedge10)> | No | Edges for expanding the safe area.<br>Default value: **[SafeAreaEdge.TOP, SafeAreaEdge.BOTTOM, SafeAreaEdge.START, SafeAreaEdge.END]**<br>The default value expands the safe area on all available edges.| 34 35> **NOTE** 36> 37> When using **expandSafeArea** to expand the drawing of a component, avoid setting a fixed width or height for the component (except for percentages). If a fixed width or height is set, the edges for the expanded safe area can only be [SafeAreaEdge.TOP, SafeAreaEdge.START], and the size of the component remains unchanged after the expansion. 38> 39> The safe area does not restrict the layout or size of components inside, nor does it clip the components. 40> 41> If the parent container is a scroll container, the **expandSafeArea** attribute does not take effect. 42> 43> When **expandSafeArea()** is set, no parameter is passed in, and the default value is used. When **expandSafeArea([],[])** is set, an empty array is passed in, and the settings do not take effect. 44> 45> After **expandSafeArea** is set: 46> 1. If **type** is set to **SafeAreaType.KEYBOARD**, the settings take effect without additional conditions. 47> 2. If **type** is set to any other value, the settings take effect under the prerequisite that the component can extend to the safe area when the component border overlaps with the safe area. For example, if the height of the status bar is 100, the absolute position of the component on the screen must be 0 <= y <= 100 for the settings to take effect. 48> 49> When the component extends to the safe area, the system may intercept events in the safe area to preferentially respond to events of system components, such as the status bar. 50> 51> Avoid setting the **expandSafeArea** attribute for components within scrollable containers. If you do set it, you must apply the **expandSafeArea** attribute to all direct nodes from the current node to the scrollable ancestor container, following the component nesting relationship. Otherwise, the **expandSafeArea** attribute may become ineffective after scrolling. For the correct implementation, see [Example 7](#example-7-expanding-the-safe-area-in-scrollable-containers). 52> 53> The **expandSafeArea** attribute only affects the current component and does not propagate to parent or child components. Therefore, all relevant components must be configured individually. 54> 55> When both **expandSafeArea** and **position** attributes are set, the **position** attribute takes precedence, and the **expandSafeArea** attribute is applied afterward. For components that do not have **position**, **offset**, or other rendering attributes set, the **expandSafeArea** attribute will not take effect if the component's boundary does not overlap with the safe area, such as with dialog boxes and sheets. 56> 57> In scenarios where the **expandSafeArea** attribute is ineffective, and you need to place a component in the safe area, you will need to manually adjust the component's coordinates. 58 59## setKeyboardAvoidMode<sup>11+</sup> 60 61setKeyboardAvoidMode(value: KeyboardAvoidMode): void 62 63Sets the avoidance mode for the virtual keyboard. 64 65**Atomic service API**: This API can be used in atomic services since API version 11. 66 67**System capability**: SystemCapability.ArkUI.ArkUI.Full 68 69**Parameters** 70 71| Name| Type | Mandatory| Description | 72| ------ | ---------------------------------------------------- | ---- | ------------------------------------------------------------ | 73| value | [KeyboardAvoidMode](../js-apis-arkui-UIContext.md#keyboardavoidmode11) | Yes | Avoidance mode of the virtual keyboard.<br>Default value: **KeyboardAvoidMode.OFFSET**, which means that the page moves up when the keyboard is displayed.| 74 75> **NOTE** 76> 77> With **KeyboardAvoidMode.RESIZE**, the page is resized to prevent the virtual keyboard from obstructing the view. Regarding components on the page, those with percentage-based width and height are resized with the page, and those with fixed width and height are laid out according to their set sizes. With **KeyboardAvoidMode.RESIZE**, **expandSafeArea([SafeAreaType.KEYBOARD],[SafeAreaEdge.BOTTOM])** does not take effect. 78> 79> With **KeyboardAvoidMode.NONE**, the page is covered by the displayed keyboard. 80 81## getKeyboardAvoidMode 82 83getKeyboardAvoidMode(): KeyboardAvoidMode 84 85Obtains the avoidance mode of the virtual keyboard. 86 87**Atomic service API**: This API can be used in atomic services since API version 11. 88 89**System capability**: SystemCapability.ArkUI.ArkUI.Full 90 91**Return value** 92 93| Name | Description | 94| ---------------------------------------------------- | ---------------------------------- | 95| [KeyboardAvoidMode](../js-apis-arkui-UIContext.md#keyboardavoidmode11) | Avoidance mode of the virtual keyboard.| 96 97## Example 98 99### Example 1: Implementing an Immersive Effect 100 101This example demonstrates how to use the **expandSafeArea** attribute to expand the safe area to the top and bottom to achieve an immersive effect. 102 103```ts 104// xxx.ets 105@Entry 106@Component 107struct SafeAreaExample1 { 108 @State text: string = '' 109 controller: TextInputController = new TextInputController() 110 111 build() { 112 Row() { 113 Column() 114 .height('100%').width('100%') 115 .backgroundImage($r('app.media.bg')).backgroundImageSize(ImageSize.Cover) 116 .expandSafeArea([SafeAreaType.SYSTEM], [SafeAreaEdge.TOP, SafeAreaEdge.BOTTOM]) 117 }.height('100%') 118 } 119} 120``` 121 122 123 124### Example 2: Setting a Fixed Width or Height with expandSafeArea 125 126This example demonstrates the effect of setting both a fixed width or height and the **expandSafeArea** attribute. 127 128```ts 129// xxx.ets 130@Entry 131@Component 132struct SafeAreaExample2 { 133 @State text: string = '' 134 controller: TextInputController = new TextInputController() 135 136 build() { 137 Column() { 138 TextInput({ text: this.text, placeholder: 'input your word...', controller: this.controller }) 139 .placeholderFont({ size: 14, weight: 400 }) 140 .width(320).height(40).offset({y: 120}) 141 .fontSize(14).fontColor(Color.Black) 142 .backgroundColor(Color.White) 143 } 144 .height('780') 145 .width('100%') 146 .backgroundColor('rgb(179,217,235)') 147 .expandSafeArea([SafeAreaType.SYSTEM], [SafeAreaEdge.TOP, SafeAreaEdge.BOTTOM]) 148 } 149} 150``` 151 152As shown in the figure below, the **Column** component expands to the top status bar ([SafeAreaEdge.TOP]) but does not expand to the bottom navigation bar ([SafeAreaEdge.BOTTOM]). The height of the component after expansion remains consistent with the set height. 153 154 155 156 157### Example 3: Fixing the Background Image Position During Keyboard Avoidance 158 159This example shows how to set the **expandSafeArea** attribute for the background image to keep it fixed when the keyboard is displayed and the layout is adjusted. 160 161```ts 162// xxx.ets 163@Entry 164@Component 165struct SafeAreaExample3 { 166 @State text: string = '' 167 controller: TextInputController = new TextInputController() 168 169 build() { 170 Row() { 171 Stack() { 172 Column() 173 .height('100%').width('100%') 174 .backgroundImage($r('app.media.bg')).backgroundImageSize(ImageSize.Cover) 175 .expandSafeArea([SafeAreaType.KEYBOARD, SafeAreaType.SYSTEM]) 176 Column() { 177 Button('Set caretPosition 1') 178 .onClick(() => { 179 this.controller.caretPosition(1) 180 }) 181 TextInput({ text: this.text, placeholder: 'input your word...', controller: this.controller }) 182 .placeholderFont({ size: 14, weight: 400 }) 183 .width(320).height(40).offset({y: 120}) 184 .fontSize(14).fontColor(Color.Black) 185 .backgroundColor(Color.White) 186 }.width('100%').alignItems(HorizontalAlign.Center) 187 } 188 }.height('100%') 189 } 190} 191``` 192 193 194 195### Example 4: Setting the Keyboard Avoidance Mode to Resize 196 197This example demonstrates how to use **setKeyboardAvoidMode** to set the keyboard avoidance mode to **RESIZE**, which resizes the page when the keyboard is displayed. 198 199```ts 200// EntryAbility.ets 201import { KeyboardAvoidMode } from '@kit.ArkUI'; 202 203onWindowStageCreate(windowStage: window.WindowStage) { 204 // Main window is created, set main page for this ability 205 hilog.info(0x0000, 'testTag', '%{public}s', 'Ability onWindowStageCreate'); 206 207 windowStage.loadContent('pages/Index', (err, data) => { 208 let keyboardAvoidMode = windowStage.getMainWindowSync().getUIContext().getKeyboardAvoidMode(); 209 // When the virtual keyboard is displayed, the page is resized to its original height minus the keyboard height. 210 windowStage.getMainWindowSync().getUIContext().setKeyboardAvoidMode(KeyboardAvoidMode.RESIZE); 211 if (err.code) { 212 hilog.error(0x0000, 'testTag', 'Failed to load the content. Cause: %{public}s', JSON.stringify(err) ?? ''); 213 return; 214 } 215 hilog.info(0x0000, 'testTag', 'Succeeded in loading the content. Data: %{public}s', JSON.stringify(data) ?? ''); 216 }); 217} 218``` 219 220```ts 221// xxx.ets 222@Entry 223@Component 224struct KeyboardAvoidExample1 { 225 build() { 226 Column() { 227 Row().height("30%").width("100%").backgroundColor(Color.Gray) 228 TextArea().width("100%").borderWidth(1) 229 Text("I can see the bottom of the page").width("100%").textAlign(TextAlign.Center).backgroundColor('rgb(179,217,235)').layoutWeight(1) 230 }.width('100%').height("100%") 231 } 232} 233``` 234 235 236 237### Example 5: Setting Keyboard Avoidance Mode to Offset 238 239This example demonstrates how to use **setKeyboardAvoidMode** to set the keyboard avoidance mode to **OFFSET**, which lifts the page when the keyboard is displayed. However, if the input cursor is positioned more than the keyboard's height from the bottom of the screen, the page will not be lifted, as demonstrated in this example. 240 241```ts 242// EntryAbility.ets 243import { KeyboardAvoidMode } from '@kit.ArkUI'; 244 245onWindowStageCreate(windowStage: window.WindowStage) { 246 // Main window is created, set main page for this ability 247 hilog.info(0x0000, 'testTag', '%{public}s', 'Ability onWindowStageCreate'); 248 249 windowStage.loadContent('pages/Index', (err, data) => { 250 let keyboardAvoidMode = windowStage.getMainWindowSync().getUIContext().getKeyboardAvoidMode(); 251 // When the virtual keyboard is displayed, the page is moved up until the caret is displayed. 252 windowStage.getMainWindowSync().getUIContext().setKeyboardAvoidMode(KeyboardAvoidMode.OFFSET); 253 if (err.code) { 254 hilog.error(0x0000, 'testTag', 'Failed to load the content. Cause: %{public}s', JSON.stringify(err) ?? ''); 255 return; 256 } 257 hilog.info(0x0000, 'testTag', 'Succeeded in loading the content. Data: %{public}s', JSON.stringify(data) ?? ''); 258 }); 259} 260``` 261 262```ts 263// xxx.ets 264@Entry 265@Component 266struct KeyboardAvoidExample2 { 267 build() { 268 Column() { 269 Row().height("30%").width("100%").backgroundColor(Color.Gray) 270 TextArea().width("100%").borderWidth(1) 271 Text("I can see the bottom of the page").width("100%").textAlign(TextAlign.Center).backgroundColor('rgb(179,217,235)').layoutWeight(1) 272 }.width('100%').height("100%") 273 } 274} 275``` 276 277 278 279### Example 6: Switching Avoidance Modes 280 281This example demonstrates how to switch between **OFFSET**, **RESIZE**, and **NONE** modes using **setKeyboardAvoidMode** to achieve three different keyboard avoidance effects. 282 283```ts 284import { hilog } from '@kit.PerformanceAnalysisKit'; 285import { KeyboardAvoidMode } from '@kit.ArkUI'; 286@Entry 287@Component 288 289struct KeyboardAvoidExample3 { 290 build() { 291 Column() { 292 Row({space:15}) { 293 Button('OFFSET') 294 .onClick(() => { 295 this.getUIContext().setKeyboardAvoidMode(KeyboardAvoidMode.OFFSET); 296 hilog.info(0x0000, 'keyboardAvoidMode: %{public}s', JSON.stringify(this.getUIContext().getKeyboardAvoidMode())); 297 }) 298 .layoutWeight(1) 299 Button('RESIZE') 300 .onClick(() => { 301 this.getUIContext().setKeyboardAvoidMode(KeyboardAvoidMode.RESIZE); 302 hilog.info(0x0000, 'keyboardAvoidMode: %{public}s', JSON.stringify(this.getUIContext().getKeyboardAvoidMode())); 303 }) 304 .layoutWeight(1) 305 Button('NONE') 306 .onClick(() => { 307 this.getUIContext().setKeyboardAvoidMode(KeyboardAvoidMode.NONE); 308 hilog.info(0x0000, 'keyboardAvoidMode: %{public}s', JSON.stringify(this.getUIContext().getKeyboardAvoidMode())); 309 }) 310 .layoutWeight(1) 311 } 312 .height("30%") 313 .width("100%") 314 .backgroundColor(Color.Gray) 315 316 TextArea() 317 .width("100%") 318 .borderWidth(1) 319 320 Text("I can see the bottom of the page") 321 .width("100%") 322 .textAlign(TextAlign.Center) 323 .backgroundColor('rgb(179,217,235)') 324 .layoutWeight(1) 325 326 TextArea() 327 .width("100%") 328 .borderWidth(1) 329 } 330 .width('100%') 331 .height("100%") 332 } 333} 334``` 335OFFSET mode 336 337 338 339RESIZE mode 340 341 342 343NONE mode 344 345 346 347### Example 7: Expanding the Safe Area in Scrollable Containers 348 349This example demonstrates how to use the **expandSafeArea** attribute within a scrollable container to achieve an immersive effect. 350 351```ts 352class SwiperDataSource implements IDataSource { 353 private list: Array<Color> = [] 354 constructor(list: Array<Color>) { 355 this.list = list 356 } 357 totalCount(): number { 358 return this.list.length 359 } 360 getData(index: number): Color { 361 return this.list[index] 362 } 363 registerDataChangeListener(listener: DataChangeListener): void { 364 } 365 unregisterDataChangeListener(listener: DataChangeListener): void { 366 } 367} 368@Entry 369@Component 370struct ExpandSafeAreaTest { 371 private swiperController: SwiperController = new SwiperController() 372 private swiperData: SwiperDataSource = new SwiperDataSource([]) 373 private list: Array<Color> = [ 374 Color.Pink, 375 Color.Blue, 376 Color.Green 377 ] 378 aboutToAppear(): void { 379 this.swiperData = new SwiperDataSource(this.list) 380 } 381 build() { 382 Scroll() { 383 Column() { 384 Swiper(this.swiperController) { 385 LazyForEach(this.swiperData, (item: Color, index: number) => { 386 Column() { 387 Text('banner' + index).fontSize(50).fontColor(Color.White) 388 } 389 .expandSafeArea([SafeAreaType.SYSTEM], [SafeAreaEdge.TOP, SafeAreaEdge.BOTTOM]) 390 .width('100%') 391 .height(400) 392 .backgroundColor(item) 393 }) 394 } 395 .loop(true) 396 .expandSafeArea([SafeAreaType.SYSTEM], [SafeAreaEdge.TOP, SafeAreaEdge.BOTTOM]) 397 .clip(false) 398 Column(){ 399 Text("Tab content").fontSize(50) 400 }.width("100%").height(1000) 401 .backgroundColor(Color.Grey) 402 }.expandSafeArea([SafeAreaType.SYSTEM], [SafeAreaEdge.TOP, SafeAreaEdge.BOTTOM]) 403 } 404 .clip(false) 405 .edgeEffect(EdgeEffect.None) 406 .width("100%").height("100%") 407 } 408} 409``` 410 411