已开启
按沉浸式布局动态计算状态栏 padding,修复证书管理/安装页被遮挡问题,UIAbility拉起页面时,通过读 isLayoutFullScreen判断当前窗口是否为沉浸式,进而调整padding的取值 #104
hyl创建于 7月25日
按沉浸式布局动态计算状态栏 padding,修复证书管理/安装页被遮挡问题,UIAbility拉起页面时,通过读 isLayoutFullScreen判断当前窗口是否为沉浸式,进而调整padding的取值 #104
已开启
共 3 个文件变更+119-5
| @@ -0,0 +1,96 @@ | |||
| 1 | +/* | ||
| 2 | + * Copyright (c) 2026 Huawei Device Co., Ltd. | ||
| 3 | + * Licensed under the Apache License, Version 2.0 (the "License"); | ||
| 4 | + * you may not use this file except in compliance with the License. | ||
| 5 | + * You may obtain a copy of the License at | ||
| 6 | + * | ||
| 7 | + * http://www.apache.org/licenses/LICENSE-2.0 | ||
| 8 | + * | ||
| 9 | + * Unless required by applicable law or agreed to in writing, software | ||
| 10 | + * distributed under the License is distributed on an "AS IS" BASIS, | ||
| 11 | + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
| 12 | + * See the License for the specific language governing permissions and | ||
| 13 | + * limitations under the License. | ||
| 14 | + */ | ||
| 15 | + | ||
| 16 | +import { window } from '@kit.ArkUI'; | ||
| 17 | +import { BusinessError } from '@ohos.base'; | ||
| 18 | +import UIExtensionContentSession from '@ohos.app.ability.UIExtensionContentSession'; | ||
| 19 | +import hilog from '@ohos.hilog'; | ||
| 20 | +import { GlobalContext } from '../GlobalContext'; | ||
| 21 | + | ||
| 22 | +const DOMAIN = 0x0000; | ||
| 23 | +const TAG = 'StatusBarPaddingUtil'; | ||
| 24 | + | ||
| 25 | +function hilogInfo(message: string): void { | ||
| 26 | + hilog.info(DOMAIN, TAG, message); | ||
| 27 | +} | ||
| 28 | + | ||
| 29 | +function hilogError(message: string): void { | ||
| 30 | + hilog.error(DOMAIN, TAG, message); | ||
| 31 | +} | ||
| 32 | + | ||
| 33 | +/** | ||
| 34 | + * Determines whether manual status bar padding is required when opening a page: | ||
| 35 | + * UIExtension uses host position; UIAbility uses isLayoutFullScreen. | ||
| 36 | + */ | ||
| 37 | +export function updateStatusBarPaddingByImmersive(context: Context, | ||
| 38 | + onResult: (topPadding: number) => void): void { | ||
| 39 | + try { | ||
| 40 | + const session = GlobalContext.getContext().getSession(); | ||
| 41 | + if (session !== undefined && session !== null) { | ||
| 42 | + onResult(resolveUiExtensionStatusBarPadding(session)); | ||
| 43 | + return; | ||
| 44 | + } | ||
| 45 | + resolveUiAbilityStatusBarPadding(context, onResult); | ||
| 46 | + } catch (error) { | ||
| 47 | + const err: BusinessError = error as BusinessError; | ||
| 48 | + hilogError(`updateStatusBarPaddingByImmersive error: ${err.code}, ${err.message}`); | ||
| 49 | + const cached: number | undefined = AppStorage.get('STATUS_BAR_HEIGHT') as number | undefined; | ||
| 50 | + onResult(cached !== undefined ? cached : 0); | ||
| 51 | + } | ||
| 52 | +} | ||
| 53 | + | ||
| 54 | +/** | ||
| 55 | + * UIExtension scenario: determine whether manual status bar padding is required based on host position. | ||
| 56 | + */ | ||
| 57 | +function resolveUiExtensionStatusBarPadding(session: UIExtensionContentSession): number { | ||
| 58 | + const extensionWindow = session.getUIExtensionWindowProxy(); | ||
| 59 | + const area: window.AvoidArea = | ||
| 60 | + extensionWindow.getWindowAvoidArea(window.AvoidAreaType.TYPE_SYSTEM); | ||
| 61 | + const barHeight: number = px2vp(area.topRect.height); | ||
| 62 | + let needPadding: boolean = true; | ||
| 63 | + | ||
| 64 | + const hostRect: window.Rect = extensionWindow.properties.uiExtensionHostWindowProxyRect; | ||
| 65 | + if (hostRect !== undefined && hostRect !== null) { | ||
| 66 | + const hostTop: number = px2vp(hostRect.top); | ||
| 67 | + needPadding = hostTop < barHeight - 2; | ||
| 68 | + hilogInfo(`hostTop=${hostTop}, barHeight=${barHeight}, needPadding=${needPadding}`); | ||
| 69 | + } else { | ||
| 70 | + hilogInfo(`hostRect unavailable, barHeight=${barHeight}`); | ||
| 71 | + } | ||
| 72 | + | ||
| 73 | + const topPadding: number = needPadding ? barHeight : 0; | ||
| 74 | + AppStorage.setOrCreate('STATUS_BAR_HEIGHT', topPadding); | ||
| 75 | + return topPadding; | ||
| 76 | +} | ||
| 77 | + | ||
| 78 | +/** | ||
| 79 | + * UIAbility scenario: determine whether manual status bar padding is required based on isLayoutFullScreen. | ||
| 80 | + */ | ||
| 81 | +function resolveUiAbilityStatusBarPadding(context: Context, | ||
| 82 | + onResult: (topPadding: number) => void): void { | ||
| 83 | + window.getLastWindow(context).then((win: window.Window) => { | ||
| 84 | + const isLayoutFullScreen: boolean = win.getWindowProperties().isLayoutFullScreen; | ||
| 85 | + const barHeight: number = | ||
| 86 | + px2vp(win.getWindowAvoidArea(window.AvoidAreaType.TYPE_SYSTEM).topRect.height); | ||
| 87 | + const topPadding: number = isLayoutFullScreen ? barHeight : 0; | ||
| 88 | + AppStorage.setOrCreate('STATUS_BAR_HEIGHT', topPadding); | ||
| 89 | + hilogInfo(`isLayoutFullScreen=${isLayoutFullScreen}, statusBarHeight=${topPadding}`); | ||
| 90 | + onResult(topPadding); | ||
| 91 | + }).catch((err: BusinessError) => { | ||
| 92 | + hilogError(`getLastWindow failed: ${err.code}, ${err.message}`); | ||
| 93 | + const cached: number | undefined = AppStorage.get('STATUS_BAR_HEIGHT') as number | undefined; | ||
| 94 | + onResult(cached !== undefined ? cached : 0); | ||
| 95 | + }); | ||
| 96 | +} | ||
| @@ -32,6 +32,7 @@ import { SheetParam } from '../common/util/SheetParam'; | |||
| 32 | import FilterParams from '../common/constants/FileFilterParams'; | 32 | import FilterParams from '../common/constants/FileFilterParams'; |
| 33 | import { UIContext } from '@kit.ArkUI'; | 33 | import { UIContext } from '@kit.ArkUI'; |
| 34 | import { common } from '@kit.AbilityKit'; | 34 | import { common } from '@kit.AbilityKit'; |
| 35 | +import { updateStatusBarPaddingByImmersive } from '../common/util/StatusBarPaddingUtil'; | ||
| 35 | 36 | ||
| 36 | const COPIES_NUM: number = 12; | 37 | const COPIES_NUM: number = 12; |
| 37 | 38 | ||
| @@ -53,10 +54,18 @@ export struct CertInstallFromStorage { | |||
| 53 | @State private headRectHeightReal: number = 0; | 54 | @State private headRectHeightReal: number = 0; |
| 54 | private scroller: Scroller = new Scroller(); | 55 | private scroller: Scroller = new Scroller(); |
| 55 | @State private scrollerHeight: number = 0; | 56 | @State private scrollerHeight: number = 0; |
| 56 | - @State statusBarHeight: number = 0 | 57 | + @State statusBarHeight: number = 0; |
| 58 | + | ||
| 57 | aboutToAppear(): void { | 59 | aboutToAppear(): void { |
| 58 | - this.statusBarHeight = AppStorage.get('STATUS_BAR_HEIGHT') as number | 60 | + if (this.isStartBySheet) { |
| 61 | + this.statusBarHeight = 0; | ||
| 62 | + return; | ||
| 63 | + } | ||
| 64 | + updateStatusBarPaddingByImmersive(this.context, (topPadding: number) => { | ||
| 65 | + this.statusBarHeight = topPadding; | ||
| 66 | + }); | ||
| 59 | } | 67 | } |
| 68 | + | ||
| 60 | @Styles normalStyle() { | 69 | @Styles normalStyle() { |
| 61 | .backgroundColor($r('sys.color.ohos_id_color_card_bg')) | 70 | .backgroundColor($r('sys.color.ohos_id_color_card_bg')) |
| 62 | .borderRadius($r('app.float.user_list_divider_borderRadius_value')) | 71 | .borderRadius($r('app.float.user_list_divider_borderRadius_value')) |
| @@ -387,7 +396,7 @@ export struct CertInstallFromStorage { | |||
| 387 | .backgroundColor($r('sys.color.ohos_id_color_sub_background')) | 396 | .backgroundColor($r('sys.color.ohos_id_color_sub_background')) |
| 388 | .width(WidthPercent.WH_100_100) | 397 | .width(WidthPercent.WH_100_100) |
| 389 | .height(this.isStartBySheet ? WidthPercent.WH_AUTO : WidthPercent.WH_100_100) | 398 | .height(this.isStartBySheet ? WidthPercent.WH_AUTO : WidthPercent.WH_100_100) |
| 390 | - .padding({top:this.statusBarHeight}) | 399 | + .padding({ top: this.statusBarHeight }); |
| 391 | } | 400 | } |
| 392 | 401 | ||
| 393 | getScrollMinHeight() { | 402 | getScrollMinHeight() { |
| @@ -23,6 +23,7 @@ import promptAction from '@ohos.promptAction'; | |||
| 23 | import { CustomContentDialog } from '@ohos.arkui.advanced.Dialog'; | 23 | import { CustomContentDialog } from '@ohos.arkui.advanced.Dialog'; |
| 24 | import { NavEntryKey } from '../common/NavEntryKey'; | 24 | import { NavEntryKey } from '../common/NavEntryKey'; |
| 25 | import { SheetParam } from '../common/util/SheetParam'; | 25 | import { SheetParam } from '../common/util/SheetParam'; |
| 26 | +import { updateStatusBarPaddingByImmersive } from '../common/util/StatusBarPaddingUtil'; | ||
| 26 | 27 | ||
| 27 | const DISPLAY_DURATION: number = 2000; | 28 | const DISPLAY_DURATION: number = 2000; |
| 28 | const COPIES_NUM: number = 12; | 29 | const COPIES_NUM: number = 12; |
| @@ -55,10 +56,18 @@ export struct CertificateComponent { | |||
| 55 | @Prop sheetParam: SheetParam; | 56 | @Prop sheetParam: SheetParam; |
| 56 | private scroller: Scroller = new Scroller(); | 57 | private scroller: Scroller = new Scroller(); |
| 57 | @State private scrollerHeight: number = 0; | 58 | @State private scrollerHeight: number = 0; |
| 58 | - @State statusBarHeight: number = 0 | 59 | + @State statusBarHeight: number = 0; |
| 60 | + | ||
| 59 | aboutToAppear(): void { | 61 | aboutToAppear(): void { |
| 60 | - this.statusBarHeight = AppStorage.get('STATUS_BAR_HEIGHT') as number | 62 | + if (this.isStartBySheet) { |
| 63 | + this.statusBarHeight = 0; | ||
| 64 | + return; | ||
| 65 | + } | ||
| 66 | + updateStatusBarPaddingByImmersive(getContext(this), (topPadding: number) => { | ||
| 67 | + this.statusBarHeight = topPadding; | ||
| 68 | + }); | ||
| 61 | } | 69 | } |
| 70 | + | ||
| 62 | build() { | 71 | build() { |
| 63 | Column() { | 72 | Column() { |
| 64 | GridRow({ | 73 | GridRow({ |