diff --git a/zh-cn/application-dev/reference/apis-arkui/arkui-ts/figures/expandSafeArea.png b/zh-cn/application-dev/reference/apis-arkui/arkui-ts/figures/expandSafeArea.png new file mode 100644 index 0000000000000000000000000000000000000000..4d94c0752ff3825279fa4184b530cb246dce606a Binary files /dev/null and b/zh-cn/application-dev/reference/apis-arkui/arkui-ts/figures/expandSafeArea.png differ diff --git a/zh-cn/application-dev/reference/apis-arkui/arkui-ts/figures/scroll-clipContent.png b/zh-cn/application-dev/reference/apis-arkui/arkui-ts/figures/scroll-clipContent.png new file mode 100644 index 0000000000000000000000000000000000000000..d037fcafd8c75fc97701343a90c306d265a99cfb Binary files /dev/null and b/zh-cn/application-dev/reference/apis-arkui/arkui-ts/figures/scroll-clipContent.png differ diff --git a/zh-cn/application-dev/reference/apis-arkui/arkui-ts/figures/scroll-expandSafeArea.png b/zh-cn/application-dev/reference/apis-arkui/arkui-ts/figures/scroll-expandSafeArea.png new file mode 100644 index 0000000000000000000000000000000000000000..cd852fd34664fecfdc126e249628f2378d9b88c8 Binary files /dev/null and b/zh-cn/application-dev/reference/apis-arkui/arkui-ts/figures/scroll-expandSafeArea.png differ diff --git a/zh-cn/application-dev/reference/apis-arkui/arkui-ts/figures/scroll-no.png b/zh-cn/application-dev/reference/apis-arkui/arkui-ts/figures/scroll-no.png new file mode 100644 index 0000000000000000000000000000000000000000..e3a00b80a2cd10226a337b2720564d58ca032170 Binary files /dev/null and b/zh-cn/application-dev/reference/apis-arkui/arkui-ts/figures/scroll-no.png differ diff --git a/zh-cn/application-dev/reference/apis-arkui/arkui-ts/figures/setWindowLayoutFullScreen.png b/zh-cn/application-dev/reference/apis-arkui/arkui-ts/figures/setWindowLayoutFullScreen.png new file mode 100644 index 0000000000000000000000000000000000000000..39d6242dc3c21d9367ea92f7853407d578c65fbf Binary files /dev/null and b/zh-cn/application-dev/reference/apis-arkui/arkui-ts/figures/setWindowLayoutFullScreen.png differ diff --git a/zh-cn/application-dev/reference/apis-arkui/arkui-ts/ts-universal-attributes-expand-safe-area.md b/zh-cn/application-dev/reference/apis-arkui/arkui-ts/ts-universal-attributes-expand-safe-area.md index 8aa3c1361a4005ffed78da7d86c80f4cd8187e56..c8fb2d321725eb17ae8577b975329b7106811d6c 100644 --- a/zh-cn/application-dev/reference/apis-arkui/arkui-ts/ts-universal-attributes-expand-safe-area.md +++ b/zh-cn/application-dev/reference/apis-arkui/arkui-ts/ts-universal-attributes-expand-safe-area.md @@ -1,12 +1,12 @@ # 安全区域 -安全区域是指页面的显示区域,默认不与系统设置的非安全区域比如状态栏、导航栏区域重叠,默认情况下开发者开发的界面都被布局在安全区域内。提供属性方法允许开发者设置组件绘制内容突破安全区域的限制,通过[expandSafeArea](#expandsafearea)属性支持组件不改变布局情况下扩展其绘制区域至安全区外,通过设置[setKeyboardAvoidMode](#setkeyboardavoidmode11)来配置虚拟键盘弹出时页面的避让模式。页面中有标题栏等文字不希望和非安全区重叠时,建议对组件设置expandSafeArea属性达到沉浸式效果,也可以直接通过窗口接口[setWindowLayoutFullScreen](../js-apis-window.md#setwindowlayoutfullscreen9)设置沉浸式。 +安全区域是指页面的显示区域,不与系统设置的非安全区域(如状态栏、导航条区域)重叠。默认情况下,开发者创建的界面都会布局在安全区域内。安全区之外的区域,包括状态栏和导航条,被称为避让区。ArkUI提供属性方法,使开发者可以设置组件的绘制内容突破安全区域的限制。通过[expandSafeArea](#expandsafearea)属性,支持组件在不改变布局的情况下扩展其绘制区域至安全区外。通过设置[setKeyboardAvoidMode](#setkeyboardavoidmode11),可以配置虚拟键盘弹出时页面的避让模式。 > **说明:** > > 从API Version 10开始支持。后续版本如有新增内容,则采用上角标单独标记该内容的起始版本。
> 默认摄像头挖孔区域不为非安全区域,页面不避让挖孔。
-> 从API Version 12开始,可在module.json5中添加配置项, 摄像头挖孔区域视为非安全区,实现页面默认避让挖孔:
+> 从API Version 12开始,可在module.json5中添加以下配置项, 摄像头挖孔区域视为非安全区,实现页面默认避让挖孔:
"metadata": [
  {
    "name": "avoid_cutout",
@@ -19,7 +19,7 @@ expandSafeArea(types?: Array<SafeAreaType>, edges?: Array<SafeAreaEdge>) -控制组件扩展其安全区域。 +控制组件扩展其安全区域。expandSafeArea属性仅作用于当前组件,不传递给父组件或子组件,因此,在使用过程中,所有嵌套组件均需单独配置。扩展安全区域不会限制内部组件的布局和大小,也不会裁剪内部组件。当组件扩展至避让区域时,避让区域的事件(如点击事件)可能被系统拦截,优先响应状态栏、导航条等系统组件。 **原子化服务API:** 从API version 11开始,该接口支持在原子化服务中使用。 @@ -29,32 +29,18 @@ expandSafeArea(types?: Array<SafeAreaType>, edges?: Array<SafeAreaEdge& | 参数名 | 类型 | 必填 | 说明 | | ------ | -------------------------------------------------- | ---- | ------------------------------------------------------------ | -| types | Array <[SafeAreaType](ts-types.md#safeareatype10)> | 否 | 配置扩展安全区域的类型。未添加[Metadata](../../apis-ability-kit/js-apis-bundleManager-metadata.md)配置项时,页面不避让挖孔, CUTOUT类型不生效。
默认值:[SafeAreaType.SYSTEM, SafeAreaType.CUTOUT, SafeAreaType.KEYBOARD] | +| types | Array <[SafeAreaType](ts-types.md#safeareatype10)> | 否 | 配置扩展安全区域的类型。
默认值:[SafeAreaType.SYSTEM, SafeAreaType.CUTOUT, SafeAreaType.KEYBOARD],未添加[Metadata](../../apis-ability-kit/js-apis-bundleManager-metadata.md)配置项时,页面不避让挖孔, CUTOUT类型不生效。 | | edges | Array <[SafeAreaEdge](ts-types.md#safeareaedge10)> | 否 | 配置扩展安全区域的方向。
默认值:[SafeAreaEdge.TOP, SafeAreaEdge.BOTTOM, SafeAreaEdge.START, SafeAreaEdge.END]
扩展至所有非安全区域。 | > **说明:** > -> 设置expandSafeArea属性进行组件绘制扩展时,建议组件尺寸不要设置固定宽高(百分比除外),当设置固定宽高时,扩展安全区域的方向只支持[SafeAreaEdge.TOP, SafeAreaEdge.START],扩展后的组件尺寸保持不变。 +> - 设置expandSafeArea()不传递参数时,系统将使用默认值进行处理;设置expandSafeArea([],[])时,相当于入参是空数组,此时设置expandSafeArea属性不生效;扩展类型为KEYBOARD时,设置expandSafeArea属性表现为组件不避让键盘;扩展安全区的生效条件为组件边界与避让区重叠。例如:设备屏幕高度为2720,顶部状态栏高度为123,底部导航条高度为91,扩展类型为SafeAreaType.SYSTEM,那么组件在屏幕中的绝对位置需要满足 0 <= y <= 123 (扩展至状态栏) 或 2629 <= y <= 2720 (扩展至导航条)。 > -> 安全区域不会限制内部组件的布局和大小,不会裁剪内部组件。 +> - 设置expandSafeArea属性进行组件绘制扩展时,建议组件尺寸不要设置固定宽高(百分比除外),当设置固定宽高时,扩展安全区域的方向只支持[SafeAreaEdge.TOP, SafeAreaEdge.START],扩展后的组件尺寸保持不变,组件布局位置可能会发生改变。在同时设置了expandSafeArea和position属性时,position属性先生效,expandSafeArea属性会后生效。对于未设置position、offset等绘制属性的组件,如果组件边界没有和避让区重叠,设置expandSafeArea属性不生效,如弹窗和半模态组件。对于expandSafeArea属性无法生效的场景,若要将组件部署在避让区,需手动调整组件的坐标。 > -> 当父容器是滚动容器时,设置expandSafeArea属性不生效。 +> - 组件设置expandSafeArea属性以扩展安全区,与调用窗口全屏布局接口[setWindowLayoutFullScreen](../js-apis-window.md#setwindowlayoutfullscreen9)设置窗口为沉浸式模式的区别,具体写法参考[示例1](#示例1沉浸式方案对比)。 > -> 设置expandSafeArea()时,不传参,走默认值处理;设置expandSafeArea([],[])时,相当于入参是空数组,此时设置expandSafeArea属性不生效。 -> -> 组件设置expandSafeArea之后生效的条件为: -> 1.type为SafeAreaType.KEYBOARD时默认生效,组件不避让键盘。 -> 2.设置其他type,组件的边界与安全区域重合时组件能够延伸到安全区域下。例如:设备顶部状态栏高度100,那么组件在屏幕中的绝对位置需要为0 <= y <= 100。 -> -> 组件延伸到安全区域下,在安全区域处的事件,如点击事件等可能会被系统拦截,优先给状态栏等系统组件响应。 -> -> 滚动类容器内的组件不建议设置expandSafeArea属性,如果设置,需要按照组件嵌套关系,将当前节点到滚动类祖先容器间所有直接节点设置expandSafeArea属性,否则expandSafeArea属性在滚动后可能会失效,写法参考[示例7](#示例7滚动类容器扩展安全区)。 -> -> expandSafeArea属性仅作用于当前组件,不会向父组件或子组件传递,因此使用过程中,所有相关组件均需配置。 -> -> 在同时设置了expandSafeArea和position属性时,position属性会先生效,expandSafeArea属性会后生效。对于未设置position、offset等绘制属性的组件,如果组件边界没有和避让区重叠,设置expandSafeArea属性不生效,如弹窗和半模态组件。 -> -> 对于expandSafeArea属性无法生效的场景,若要将组件部署在避让区,需要手动调整组件的坐标。 +> - 滚动容器设置expandSafeArea属性生效,但当滚动容器是父组件时,子组件设置expandSafeArea属性不生效。滚动容器的子组件实现沉浸式效果请参考[示例8(滚动类容器实现沉浸式效果)](#示例8滚动类容器实现沉浸式效果)。 ## setKeyboardAvoidMode11+ @@ -96,7 +82,127 @@ getKeyboardAvoidMode(): KeyboardAvoidMode ## 示例 -### 示例1(实现沉浸式效果) +### 示例1(沉浸式方案对比) + +该示例对比了设置expandSafeArea属性扩展安全区和调用setWindowLayoutFullScreen设置窗口全屏布局二者的沉浸式效果。 + +**设置expandSafeArea属性扩展安全区** +```ts +// xxx.ets +@Entry +@Component +struct Index { + + build() { + Row() { + Column() { + Stack() { + Text('Display Content 1').fontSize(30) + }.backgroundColor(Color.White).padding(20).borderRadius(15).width('80%') + .expandSafeArea([SafeAreaType.SYSTEM], [SafeAreaEdge.TOP, SafeAreaEdge.BOTTOM]) + Stack() { + Text('Display Content 2').fontSize(30) + }.backgroundColor(Color.White).padding(20).borderRadius(15).width('80%') + Stack() { + Text('Display Content 3').fontSize(30) + }.backgroundColor(Color.White).padding(20).borderRadius(15).width('80%') + Stack() { + Text('Display Content 4').fontSize(30) + }.backgroundColor(Color.White).padding(20).borderRadius(15).width('80%') + Stack() { + Text('Display Content 5').fontSize(30) + }.backgroundColor(Color.White).padding(20).borderRadius(15).width('80%') + Stack() { + Text('Display Content 6').fontSize(30) + }.backgroundColor(Color.White).padding(20).borderRadius(15).width('80%') + .expandSafeArea([SafeAreaType.SYSTEM], [SafeAreaEdge.TOP, SafeAreaEdge.BOTTOM]) + } + .width('100%') + .height('100%') + .justifyContent(FlexAlign.SpaceBetween) + .backgroundColor('rgb(213,213,213)') + .expandSafeArea([SafeAreaType.SYSTEM], [SafeAreaEdge.TOP, SafeAreaEdge.BOTTOM]) + } + } +} +``` + +![expandSafeArea](figures/expandSafeArea.png) + + +**调用setWindowLayoutFullScreen设置窗口全屏布局** +```ts +// EntryAbility.ets +import { AbilityConstant, ConfigurationConstant, UIAbility, Want } from '@kit.AbilityKit'; +import { BusinessError } from '@kit.BasicServicesKit'; +import { window } from '@kit.ArkUI'; + +export default class EntryAbility extends UIAbility { + onCreate(want: Want, launchParam: AbilityConstant.LaunchParam): void { + this.context.getApplicationContext().setColorMode(ConfigurationConstant.ColorMode.COLOR_MODE_NOT_SET); + } + + onDestroy(): void { + } + + onWindowStageCreate(windowStage: window.WindowStage): void { + windowStage.loadContent('pages/Index', (err) => { + if (err.code) { + return; + } + let windowClass: window.Window = windowStage.getMainWindowSync(); + let isLayoutFullScreen = true; + windowClass.setWindowLayoutFullScreen(isLayoutFullScreen).then(() => { + console.info('Succeeded in setting the window layout to full-screen mode.'); + }).catch((err: BusinessError) => { + console.error('Failed to set the window layout to full-screen mode. Cause:' + JSON.stringify(err)); + }); + }); + } +} +``` + +```ts +// xxx.ets +@Entry +@Component +struct Index { + + build() { + Row() { + Column() { + Stack() { + Text('Display Content 1').fontSize(30) + }.backgroundColor(Color.White).padding(20).borderRadius(15).width('80%') + Stack() { + Text('Display Content 2').fontSize(30) + }.backgroundColor(Color.White).padding(20).borderRadius(15).width('80%') + Stack() { + Text('Display Content 3').fontSize(30) + }.backgroundColor(Color.White).padding(20).borderRadius(15).width('80%') + Stack() { + Text('Display Content 4').fontSize(30) + }.backgroundColor(Color.White).padding(20).borderRadius(15).width('80%') + Stack() { + Text('Display Content 5').fontSize(30) + }.backgroundColor(Color.White).padding(20).borderRadius(15).width('80%') + Stack() { + Text('Display Content 6').fontSize(30) + }.backgroundColor(Color.White).padding(20).borderRadius(15).width('80%') + } + .width('100%') + .height('100%') + .justifyContent(FlexAlign.SpaceBetween) + .backgroundColor('rgb(213,213,213)') + } + } +} +``` + +![setWindowLayoutFullScreen](figures/setWindowLayoutFullScreen.png) + + +### 示例2(设置expandSafeArea属性实现沉浸式效果) 该示例通过设置expandSafeArea属性向顶部和底部扩展安全区实现沉浸式效果。 @@ -121,7 +227,8 @@ struct SafeAreaExample1 { ![expandSafeArea1](figures/expandSafeArea1.png) -### 示例2(同时设置固定宽高和expandSafeArea属性) + +### 示例3(同时设置固定宽高和expandSafeArea属性) 该示例展示了同时设置固定宽高和expandSafeArea属性的效果。 @@ -154,7 +261,7 @@ struct SafeAreaExample2 { ![expandSafeArea2](figures/expandSafeArea2.png) -### 示例3(键盘避让时固定背景图位置) +### 示例4(键盘避让时固定背景图位置) 该示例通过为背景图组件设置expandSafeArea属性,来实现拉起键盘进行避让时,背景图保持不动的效果。 @@ -192,7 +299,7 @@ struct SafeAreaExample3 { ![expandSafeArea3](figures/expandSafeArea3.png) -### 示例4(设置键盘避让模式为压缩) +### 示例5(设置键盘避让模式为压缩) 该示例通过调用setKeyboardAvoidMode设置键盘避让模式为RESIZE模式,实现键盘抬起时page的压缩效果。 @@ -234,7 +341,7 @@ struct KeyboardAvoidExample1 { ![keyboardAvoidMode1](figures/keyboardAvoidMode1.jpg) -### 示例5(设置键盘避让模式为上抬) +### 示例6(设置键盘避让模式为上抬) 该示例通过调用setKeyboardAvoidMode设置键盘避让模式为OFFSET模式,实现键盘抬起时page的上抬效果。但当输入光标距离屏幕底部的高度大于键盘高度时,page不会抬起,如本例中所示。 @@ -276,11 +383,12 @@ struct KeyboardAvoidExample2 { ![keyboardAvoidMode1](figures/keyboardAvoidMode2.jpg) -### 示例6(切换避让模式) +### 示例7(切换避让模式) 该示例通过调用setKeyboardAvoidMode来实现OFFSET、RESIZE和NONE模式之间的切换,实现三种不同的键盘避让效果。 ```ts +// xxx.ets import { hilog } from '@kit.PerformanceAnalysisKit'; import { KeyboardAvoidMode } from '@kit.ArkUI'; @Entry @@ -332,79 +440,108 @@ struct KeyboardAvoidExample3 { } } ``` -OFFSET模式 +**OFFSET模式** ![keyboardAvoidMode3-1](figures/keyboardAvoidMode3-1.jpg) -RESIZE模式 +**RESIZE模式** ![keyboardAvoidMode3-2](figures/keyboardAvoidMode3-2.jpg) -NONE模式 +**NONE模式** ![keyboardAvoidMode3-3](figures/keyboardAvoidMode3-3.jpg) -### 示例7(滚动类容器扩展安全区) +### 示例8(滚动类容器实现沉浸式效果) + +该示例对比了滚动类容器实现沉浸式效果的两种方案,分别是设置expandSafeArea属性和设置滚动容器的内容裁剪属性clipContent扩展安全区。 -该示例通过在滚动类容器内调用expandSafeArea属性实现沉浸式效果。 +**设置expandSafeArea属性扩展安全区** ```ts -class SwiperDataSource implements IDataSource { - private list: Array = [] - constructor(list: Array) { - this.list = list - } - totalCount(): number { - return this.list.length - } - getData(index: number): Color { - return this.list[index] - } - registerDataChangeListener(listener: DataChangeListener): void { - } - unregisterDataChangeListener(listener: DataChangeListener): void { +// xxx.ets +@Entry +@Component +struct ScrollExample { + scroller: Scroller = new Scroller() + private arr: number[] = [1, 2, 3, 4, 5, 6, 7, 8, 9] + + build() { + Stack({ alignContent: Alignment.TopStart }) { + Scroll(this.scroller) { + Column() { + ForEach(this.arr, (item: number) => { + Stack() { + Text('Display Content ' + item.toString()).fontSize(30) + } + .width('80%').padding(20).borderRadius(15).backgroundColor(Color.White).margin({ top:30, bottom:30 }) + }, (item: string) => item) + }.width('100%').backgroundColor('rgb(213,213,213)') + }.backgroundColor('rgb(213,213,213)') + .expandSafeArea([SafeAreaType.SYSTEM], [SafeAreaEdge.TOP, SafeAreaEdge.BOTTOM]) + }.width('100%').height('100%') + .expandSafeArea([SafeAreaType.SYSTEM], [SafeAreaEdge.TOP, SafeAreaEdge.BOTTOM]) } } +``` + +![scroll-expandSafeArea](figures/scroll-expandSafeArea.png) + +**设置clipContent属性扩展安全区** + +```ts +// xxx.ets @Entry @Component -struct ExpandSafeAreaTest { - private swiperController: SwiperController = new SwiperController() - private swiperData: SwiperDataSource = new SwiperDataSource([]) - private list: Array = [ - Color.Pink, - Color.Blue, - Color.Green - ] - aboutToAppear(): void { - this.swiperData = new SwiperDataSource(this.list) +struct ScrollExample { + scroller: Scroller = new Scroller() + private arr: number[] = [1, 2, 3, 4, 5, 6, 7, 8, 9] + + build() { + Stack({ alignContent: Alignment.TopStart }) { + Scroll(this.scroller) { + Column() { + ForEach(this.arr, (item: number) => { + Stack() { + Text('Display Content ' + item.toString()).fontSize(30) + } + .width('80%').padding(20).borderRadius(15).backgroundColor(Color.White).margin({ top:30, bottom:30 }) + }, (item: string) => item) + }.width('100%').backgroundColor('rgb(213,213,213)') + }.backgroundColor('rgb(213,213,213)') + .clipContent(ContentClipMode.SAFE_AREA) + }.width('100%').height('100%') } +} +``` + +![scroll-clipContent](figures/scroll-clipContent.png) + +**不设置expandSafeArea和clipContent属性** + +```ts +// xxx.ets +@Entry +@Component +struct ScrollExample { + scroller: Scroller = new Scroller() + private arr: number[] = [1, 2, 3, 4, 5, 6, 7, 8, 9] + build() { - Scroll() { - Column() { - Swiper(this.swiperController) { - LazyForEach(this.swiperData, (item: Color, index: number) => { - Column() { - Text('banner' + index).fontSize(50).fontColor(Color.White) + Stack({ alignContent: Alignment.TopStart }) { + Scroll(this.scroller) { + Column() { + ForEach(this.arr, (item: number) => { + Stack() { + Text('Display Content ' + item.toString()).fontSize(30) } - .expandSafeArea([SafeAreaType.SYSTEM], [SafeAreaEdge.TOP, SafeAreaEdge.BOTTOM]) - .width('100%') - .height(400) - .backgroundColor(item) - }) - } - .loop(true) - .expandSafeArea([SafeAreaType.SYSTEM], [SafeAreaEdge.TOP, SafeAreaEdge.BOTTOM]) - .clip(false) - Column(){ - Text("Tab页Content").fontSize(50) - }.width("100%").height(1000) - .backgroundColor(Color.Grey) - }.expandSafeArea([SafeAreaType.SYSTEM], [SafeAreaEdge.TOP, SafeAreaEdge.BOTTOM]) - } - .clip(false) - .edgeEffect(EdgeEffect.None) - .width("100%").height("100%") + .width('80%').padding(20).borderRadius(15).backgroundColor(Color.White).margin({ top:30, bottom:30 }) + }, (item: string) => item) + }.width('100%').backgroundColor('rgb(213,213,213)') + }.backgroundColor('rgb(213,213,213)') + }.width('100%').height('100%') } } ``` -![expandSafeArea4](figures/expandSafeArea4.png) \ No newline at end of file + +![scroll-no](figures/scroll-no.png) \ No newline at end of file