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> To set the **expandSafeArea** attribute for a component, this component cannot have its width and height fixed (except to a percentage). 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 6]](#example-6-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](ts-types.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](ts-types.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: Fixing the Background Image Position During Keyboard Avoidance 125 126This 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. 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 Row() { 138 Stack() { 139 Column() 140 .height('100%').width('100%') 141 .backgroundImage($r('app.media.bg')).backgroundImageSize(ImageSize.Cover) 142 .expandSafeArea([SafeAreaType.KEYBOARD, SafeAreaType.SYSTEM]) 143 Column() { 144 Button('Set caretPosition 1') 145 .onClick(() => { 146 this.controller.caretPosition(1) 147 }) 148 TextInput({ text: this.text, placeholder: 'input your word...', controller: this.controller }) 149 .placeholderFont({ size: 14, weight: 400 }) 150 .width(320).height(40).offset({y: 120}) 151 .fontSize(14).fontColor(Color.Black) 152 .backgroundColor(Color.White) 153 }.width('100%').alignItems(HorizontalAlign.Center) 154 } 155 }.height('100%') 156 } 157} 158``` 159 160 161 162### Example 3: Setting the Keyboard Avoidance Mode to Resize 163 164This example demonstrates how to use **setKeyboardAvoidMode** to set the keyboard avoidance mode to **RESIZE**, which resizes the page when the keyboard is displayed. 165 166```ts 167// EntryAbility.ets 168import { KeyboardAvoidMode } from '@kit.ArkUI'; 169 170onWindowStageCreate(windowStage: window.WindowStage) { 171 // Main window is created, set main page for this ability 172 hilog.info(0x0000, 'testTag', '%{public}s', 'Ability onWindowStageCreate'); 173 174 windowStage.loadContent('pages/Index', (err, data) => { 175 let keyboardAvoidMode = windowStage.getMainWindowSync().getUIContext().getKeyboardAvoidMode(); 176 // When the virtual keyboard is displayed, the page is resized to its original height minus the keyboard height. 177 windowStage.getMainWindowSync().getUIContext().setKeyboardAvoidMode(KeyboardAvoidMode.RESIZE); 178 if (err.code) { 179 hilog.error(0x0000, 'testTag', 'Failed to load the content. Cause: %{public}s', JSON.stringify(err) ?? ''); 180 return; 181 } 182 hilog.info(0x0000, 'testTag', 'Succeeded in loading the content. Data: %{public}s', JSON.stringify(data) ?? ''); 183 }); 184} 185``` 186 187```ts 188// xxx.ets 189@Entry 190@Component 191struct KeyboardAvoidExample1 { 192 build() { 193 Column() { 194 Row().height("30%").width("100%").backgroundColor(Color.Gray) 195 TextArea().width("100%").borderWidth(1) 196 Text("I can see the bottom of the page").width("100%").textAlign(TextAlign.Center).backgroundColor(Color.Pink).layoutWeight(1) 197 }.width('100%').height("100%") 198 } 199} 200``` 201 202 203 204### Example 4: Setting Keyboard Avoidance Mode to Offset 205 206This 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. 207 208```ts 209// EntryAbility.ets 210import { KeyboardAvoidMode } from '@kit.ArkUI'; 211 212onWindowStageCreate(windowStage: window.WindowStage) { 213 // Main window is created, set main page for this ability 214 hilog.info(0x0000, 'testTag', '%{public}s', 'Ability onWindowStageCreate'); 215 216 windowStage.loadContent('pages/Index', (err, data) => { 217 let keyboardAvoidMode = windowStage.getMainWindowSync().getUIContext().getKeyboardAvoidMode(); 218 // When the virtual keyboard is displayed, the page is moved up until the caret is displayed. 219 windowStage.getMainWindowSync().getUIContext().setKeyboardAvoidMode(KeyboardAvoidMode.OFFSET); 220 if (err.code) { 221 hilog.error(0x0000, 'testTag', 'Failed to load the content. Cause: %{public}s', JSON.stringify(err) ?? ''); 222 return; 223 } 224 hilog.info(0x0000, 'testTag', 'Succeeded in loading the content. Data: %{public}s', JSON.stringify(data) ?? ''); 225 }); 226} 227``` 228 229```ts 230// xxx.ets 231@Entry 232@Component 233struct KeyboardAvoidExample2 { 234 build() { 235 Column() { 236 Row().height("30%").width("100%").backgroundColor(Color.Gray) 237 TextArea().width("100%").borderWidth(1) 238 Text("I can see the bottom of the page").width("100%").textAlign(TextAlign.Center).backgroundColor(Color.Pink).layoutWeight(1) 239 }.width('100%').height("100%") 240 } 241} 242``` 243 244 245 246### Example 5: Switching Avoidance Modes 247 248This example demonstrates how to switch between **OFFSET**, **RESIZE**, and **NONE** modes using **setKeyboardAvoidMode** to achieve three different keyboard avoidance effects. 249 250```ts 251import { hilog } from '@kit.PerformanceAnalysisKit'; 252import { KeyboardAvoidMode } from '@kit.ArkUI'; 253@Entry 254@Component 255 256struct KeyboardAvoidExample3 { 257 build() { 258 Column() { 259 Row({space:15}) { 260 Button('OFFSET') 261 .onClick(() => { 262 this.getUIContext().setKeyboardAvoidMode(KeyboardAvoidMode.OFFSET); 263 hilog.info(0x0000, 'keyboardAvoidMode: %{public}s', JSON.stringify(this.getUIContext().getKeyboardAvoidMode())); 264 }) 265 .layoutWeight(1) 266 Button('RESIZE') 267 .onClick(() => { 268 this.getUIContext().setKeyboardAvoidMode(KeyboardAvoidMode.RESIZE); 269 hilog.info(0x0000, 'keyboardAvoidMode: %{public}s', JSON.stringify(this.getUIContext().getKeyboardAvoidMode())); 270 }) 271 .layoutWeight(1) 272 Button('NONE') 273 .onClick(() => { 274 this.getUIContext().setKeyboardAvoidMode(KeyboardAvoidMode.NONE); 275 hilog.info(0x0000, 'keyboardAvoidMode: %{public}s', JSON.stringify(this.getUIContext().getKeyboardAvoidMode())); 276 }) 277 .layoutWeight(1) 278 } 279 .height("30%") 280 .width("100%") 281 .backgroundColor(Color.Gray) 282 283 TextArea() 284 .width("100%") 285 .borderWidth(1) 286 287 Text("I can see the bottom of the page") 288 .width("100%") 289 .textAlign(TextAlign.Center) 290 .backgroundColor(Color.Pink) 291 .layoutWeight(1) 292 293 TextArea() 294 .width("100%") 295 .borderWidth(1) 296 } 297 .width('100%') 298 .height("100%") 299 } 300} 301``` 302OFFSET mode 303 304 305 306RESIZE mode 307 308 309 310NONE mode 311 312 313 314### Example 6: Expanding the Safe Area in Scrollable Containers 315 316This example demonstrates how to use the **expandSafeArea** attribute within a scrollable container to achieve an immersive effect. 317 318```ts 319class SwiperDataSource implements IDataSource { 320 private list: Array<Color> = [] 321 constructor(list: Array<Color>) { 322 this.list = list 323 } 324 totalCount(): number { 325 return this.list.length 326 } 327 getData(index: number): Color { 328 return this.list[index] 329 } 330 registerDataChangeListener(listener: DataChangeListener): void { 331 } 332 unregisterDataChangeListener(listener: DataChangeListener): void { 333 } 334} 335@Entry 336@Component 337struct ExpandSafeAreaTest { 338 private swiperController: SwiperController = new SwiperController() 339 private swiperData: SwiperDataSource = new SwiperDataSource([]) 340 private list: Array<Color> = [ 341 Color.Pink, 342 Color.Blue, 343 Color.Green 344 ] 345 aboutToAppear(): void { 346 this.swiperData = new SwiperDataSource(this.list) 347 } 348 build() { 349 Scroll() { 350 Column() { 351 Swiper(this.swiperController) { 352 LazyForEach(this.swiperData, (item: Color, index: number) => { 353 Column() { 354 Text('banner' + index).fontSize(50).fontColor(Color.White) 355 } 356 .expandSafeArea([SafeAreaType.SYSTEM], [SafeAreaEdge.TOP, SafeAreaEdge.BOTTOM]) 357 .width('100%') 358 .height(400) 359 .backgroundColor(item) 360 }) 361 } 362 .loop(true) 363 .expandSafeArea([SafeAreaType.SYSTEM], [SafeAreaEdge.TOP, SafeAreaEdge.BOTTOM]) 364 .clip(false) 365 Column(){ 366 Text("Tab content").fontSize(50) 367 }.width("100%").height(1000) 368 .backgroundColor(Color.Grey) 369 }.expandSafeArea([SafeAreaType.SYSTEM], [SafeAreaEdge.TOP, SafeAreaEdge.BOTTOM]) 370 } 371 .clip(false) 372 .edgeEffect(EdgeEffect.None) 373 .width("100%").height("100%") 374 } 375} 376``` 377 378