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&lt;SafeAreaType&gt;, edges?: Array&lt;SafeAreaEdge&gt;)
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![expandSafeArea1](figures/expandSafeArea1.png)
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![expandSafeArea2](figures/expandSafeArea2.png)
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![keyboardAvoidMode1](figures/keyboardAvoidMode1.jpg)
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![keyboardAvoidMode1](figures/keyboardAvoidMode2.jpg)
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![keyboardAvoidMode3-1](figures/keyboardAvoidMode3-1.jpg)
305
306RESIZE mode
307
308![keyboardAvoidMode3-2](figures/keyboardAvoidMode3-2.jpg)
309
310NONE mode
311
312![keyboardAvoidMode3-3](figures/keyboardAvoidMode3-3.jpg)
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![expandSafeArea3](figures/expandSafeArea3.jpg)
378