From d7c49db304f154682bed75fec7af3954541df35c Mon Sep 17 00:00:00 2001 From: laoyang Date: Wed, 16 Sep 2026 21:40:11 +0800 Subject: [PATCH] =?UTF-8?q?=E5=A2=9E=E5=8A=A0=E4=BF=AE=E5=A4=8D=E4=BA=86?= =?UTF-8?q?=E6=B7=B1=E8=89=B2=E6=A8=A1=E5=BC=8F=EF=BC=8C=E5=AE=8C=E5=85=A8?= =?UTF-8?q?=E6=B2=89=E6=B5=B8=E7=9A=84=E6=B7=B1=E8=89=B2=E6=A8=A1=E5=BC=8F?= =?UTF-8?q?=E5=AE=8C=E6=88=90=E4=BA=86=E3=80=82?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: laoyang --- entry/src/main/ets/common/DocViewer.ets | 2 + .../main/ets/entryability/EntryAbility.ets | 131 ++++++++++++++---- entry/src/main/ets/pages/AccountsPage.ets | 3 + entry/src/main/ets/pages/AddAccountPage.ets | 6 + entry/src/main/ets/pages/CalendarListPage.ets | 3 + entry/src/main/ets/pages/EditAccountPage.ets | 3 + entry/src/main/ets/pages/EventEditPage.ets | 26 ++++ entry/src/main/ets/pages/Index.ets | 12 +- entry/src/main/ets/pages/SettingsPage.ets | 2 + .../main/resources/dark/element/color.json | 23 +++ 10 files changed, 182 insertions(+), 29 deletions(-) create mode 100644 entry/src/main/resources/dark/element/color.json diff --git a/entry/src/main/ets/common/DocViewer.ets b/entry/src/main/ets/common/DocViewer.ets index faa8050..912593a 100644 --- a/entry/src/main/ets/common/DocViewer.ets +++ b/entry/src/main/ets/common/DocViewer.ets @@ -52,5 +52,7 @@ export struct DocViewer { .width('100%') .height('100%') .backgroundColor($r('app.color.page_bg')) + // 沉浸式:背景延伸到状态栏/导航条区域(只扩绘制,Web 与标题栏仍在安全区内) + .expandSafeArea([SafeAreaType.SYSTEM], [SafeAreaEdge.TOP, SafeAreaEdge.BOTTOM]) } } diff --git a/entry/src/main/ets/entryability/EntryAbility.ets b/entry/src/main/ets/entryability/EntryAbility.ets index 628de9d..7d182de 100644 --- a/entry/src/main/ets/entryability/EntryAbility.ets +++ b/entry/src/main/ets/entryability/EntryAbility.ets @@ -1,7 +1,6 @@ -import { AbilityConstant, ConfigurationConstant, UIAbility, Want } from '@kit.AbilityKit'; +import { AbilityConstant, ConfigurationConstant, UIAbility, Want, Configuration, EnvironmentCallback } from '@kit.AbilityKit'; import { hilog } from '@kit.PerformanceAnalysisKit'; import { window } from '@kit.ArkUI'; -import { BusinessError } from '@kit.BasicServicesKit'; import { BackgroundSyncService } from '../common/BackgroundSyncService'; import { LogUtil } from '../common/LogUtil'; @@ -67,38 +66,120 @@ export default class EntryAbility extends UIAbility { onWindowStageCreate(windowStage: window.WindowStage): void { hilog.info(DOMAIN, 'testTag', '%{public}s', 'Ability onWindowStageCreate'); + // ① 先把应用固定为「跟随系统」深浅色。必须在取窗口/刷系统栏之前调用, + // 否则会读到尚未更新到深色的色彩配置(曾导致深色下状态栏仍是浅灰)。 + try { + this.context.getApplicationContext().setColorMode(ConfigurationConstant.ColorMode.COLOR_MODE_NOT_SET); + } catch (err) { + hilog.error(DOMAIN, 'testTag', 'Failed to set colorMode. Cause: %{public}s', JSON.stringify(err)); + } + + // ② 沉浸式配色:状态栏/导航条背景**透明**,透出「主题化」的窗口底色, + // 消除顶部通知栏与底部灰条;前景(时间/图标)颜色按实际底色亮度取反。 + try { + const win: window.Window = windowStage.getMainWindowSync(); + this.mainWindow = win; + this.applySystemBars(win); + } catch (err) { + hilog.error(DOMAIN, 'testTag', 'Failed to apply immersive bars. Cause: %{public}s', JSON.stringify(err)); + } + windowStage.loadContent('pages/Index', (err) => { if (err.code) { hilog.error(DOMAIN, 'testTag', 'Failed to load the content. Cause: %{public}s', JSON.stringify(err)); return; } hilog.info(DOMAIN, 'testTag', 'Succeeded in loading the content.'); - // 沉浸式配色:状态栏/导航条与页面背景同色(app.color.page_bg = #F1F3F5), - // 消除顶部通知栏和底部的白色条 - windowStage.getMainWindow((werr: BusinessError, win: window.Window) => { - if (werr.code) { - hilog.error(DOMAIN, 'testTag', 'Failed to get main window. Cause: %{public}s', JSON.stringify(werr)); - return; - } - try { - win.setWindowSystemBarProperties({ - statusBarColor: '#F1F3F5', - statusBarContentColor: '#182431', - navigationBarColor: '#F1F3F5', - navigationBarContentColor: '#182431' - }); - // 鸿蒙 NEXT 导航条背景跟随窗口背景色:设为页面背景灰,消除底部白条 - win.setWindowBackgroundColor('#F1F3F5'); - } catch (barErr) { - hilog.error(DOMAIN, 'testTag', 'Failed to set system bar properties. Cause: %{public}s', - JSON.stringify(barErr)); - } - }); }); + + // ③ 系统深浅色切换时重刷配色。用 applicationContext 的 environment 回调, + // 它比 UIAbility.onConfigurationUpdate 更可靠(后者在部分场景下不回调, + // 会出现"页面已变深色但状态栏/底部仍是浅灰"的现象)。 try { - this.context.getApplicationContext().setColorMode(ConfigurationConstant.ColorMode.COLOR_MODE_NOT_SET); + const cb: EnvironmentCallback = { + onConfigurationUpdated: (config: Configuration): void => { + if (this.mainWindow !== undefined) { + this.applySystemBars(this.mainWindow); + } + }, + onMemoryLevel: (level: AbilityConstant.MemoryLevel): void => { + } + }; + this.context.getApplicationContext().on('environment', cb); } catch (err) { - hilog.error(DOMAIN, 'testTag', 'Failed to set colorMode. Cause: %{public}s', JSON.stringify(err)); + hilog.error(DOMAIN, 'testTag', 'Failed to watch environment. Cause: %{public}s', JSON.stringify(err)); + } + } + + /** 主窗口引用:系统深浅色切换时需要重新刷状态栏/导航栏配色 */ + private mainWindow?: window.Window; + + /** 当前是否处于系统深色模式(兜底用) */ + private isDarkMode(): boolean { + try { + return this.context.config.colorMode === ConfigurationConstant.ColorMode.COLOR_MODE_DARK; + } catch (err) { + return false; + } + } + + /** + * 取当前主题下 app.color.page_bg 的真实取值(经 dark/ 限定符解析): + * 浅色 #F1F3F5 / 深色 #000000。以"资源系统实际解析出的颜色"为准, + * 这样才能与页面真正渲染出来的背景色一致,不受 config 更新时机影响。 + */ + private themePageBg(): string { + try { + const c: number = this.context.resourceManager.getColorSync($r('app.color.page_bg').id) >>> 0; + return '#' + c.toString(16).padStart(8, '0'); + } catch (err) { + return this.isDarkMode() ? '#000000' : '#F1F3F5'; + } + } + + /** 背景是深色时需要浅色前景,反之用深色前景 */ + private isDarkBg(bg: string): boolean { + const s: string = bg.startsWith('#') ? bg.substring(1) : bg; + if (s.length < 6) { + return this.isDarkMode(); + } + const off: number = s.length >= 8 ? 2 : 0; + const r: number = parseInt(s.substring(off, off + 2), 16); + const g: number = parseInt(s.substring(off + 2, off + 4), 16); + const b: number = parseInt(s.substring(off + 4, off + 6), 16); + if (isNaN(r) || isNaN(g) || isNaN(b)) { + return this.isDarkMode(); + } + return (0.2126 * r + 0.7152 * g + 0.0722 * b) < 128; + } + + /** + * 按当前主题设置状态栏/导航条与窗口底色。 + * 背景取 0x00000000(全透明)——官方推荐的背景沉浸方案:系统栏透明, + * 透传应用自身背景,因此底色天然跟随深浅色,不会再出现恒定灰条。 + */ + private applySystemBars(win: window.Window): void { + const bgColor: string = this.themePageBg(); + const fgColor: string = this.isDarkBg(bgColor) ? '#FFFFFF' : '#182431'; + try { + win.setWindowSystemBarProperties({ + statusBarColor: '#00000000', + statusBarContentColor: fgColor, + navigationBarColor: '#00000000', + navigationBarContentColor: fgColor + }); + // 窗口底色=页面背景色,供透明的状态栏/导航条透出 + win.setWindowBackgroundColor(bgColor); + } catch (barErr) { + hilog.error(DOMAIN, 'testTag', 'Failed to set system bar properties. Cause: %{public}s', + JSON.stringify(barErr)); + } + } + + /** 兜底:部分设备/场景只回调 UIAbility.onConfigurationUpdate */ + onConfigurationUpdate(): void { + if (this.mainWindow !== undefined) { + this.applySystemBars(this.mainWindow); } } diff --git a/entry/src/main/ets/pages/AccountsPage.ets b/entry/src/main/ets/pages/AccountsPage.ets index 3f2640a..0ce1520 100644 --- a/entry/src/main/ets/pages/AccountsPage.ets +++ b/entry/src/main/ets/pages/AccountsPage.ets @@ -247,6 +247,9 @@ struct AccountsPage { } .width('100%') .height('100%') + // 沉浸式:背景延伸到状态栏/导航条区域(只扩绘制、不移动子组件) + .backgroundColor($r('app.color.page_bg')) + .expandSafeArea([SafeAreaType.SYSTEM], [SafeAreaEdge.TOP, SafeAreaEdge.BOTTOM]) } @Builder diff --git a/entry/src/main/ets/pages/AddAccountPage.ets b/entry/src/main/ets/pages/AddAccountPage.ets index a59e8b5..47b69c7 100644 --- a/entry/src/main/ets/pages/AddAccountPage.ets +++ b/entry/src/main/ets/pages/AddAccountPage.ets @@ -292,6 +292,8 @@ struct AddAccountPage { .height('100%') .padding({ left: 24, right: 24, top: 16, bottom: 24 }) .backgroundColor($r('app.color.page_bg')) + // 沉浸式:背景延伸到状态栏/导航条区域(只扩绘制、不移动子组件) + .expandSafeArea([SafeAreaType.SYSTEM], [SafeAreaEdge.TOP, SafeAreaEdge.BOTTOM]) .alignItems(HorizontalAlign.Center) } @@ -310,6 +312,10 @@ struct AddAccountPage { .fontSize(15) .backgroundColor($r('app.color.input_bg')) .borderRadius(8) + // 显式指定文字/提示/光标颜色:默认取系统主题色,深色模式下会与底色撞色而"看不清" + .fontColor($r('app.color.text_primary')) + .placeholderColor($r('app.color.text_hint')) + .caretColor($r('app.color.brand')) .onChange(onChange) } .alignItems(HorizontalAlign.Start) diff --git a/entry/src/main/ets/pages/CalendarListPage.ets b/entry/src/main/ets/pages/CalendarListPage.ets index 789ddf8..29092a5 100644 --- a/entry/src/main/ets/pages/CalendarListPage.ets +++ b/entry/src/main/ets/pages/CalendarListPage.ets @@ -249,6 +249,7 @@ struct CalendarListPage { .fontSize(16) .fontColor($r('app.color.text_primary')) .placeholderColor($r('app.color.text_hint')) + .caretColor($r('app.color.brand')) .backgroundColor($r('app.color.input_bg')) .borderRadius(10) .border({ width: 1.5, color: $r('app.color.brand') }) @@ -364,6 +365,8 @@ struct CalendarListPage { .height('100%') .padding({ left: 24, right: 24, top: 16, bottom: 24 }) .backgroundColor($r('app.color.page_bg')) + // 沉浸式:背景延伸到状态栏/导航条区域(只扩绘制、不移动子组件) + .expandSafeArea([SafeAreaType.SYSTEM], [SafeAreaEdge.TOP, SafeAreaEdge.BOTTOM]) .alignItems(HorizontalAlign.Center) } } diff --git a/entry/src/main/ets/pages/EditAccountPage.ets b/entry/src/main/ets/pages/EditAccountPage.ets index 31cd972..198e14b 100644 --- a/entry/src/main/ets/pages/EditAccountPage.ets +++ b/entry/src/main/ets/pages/EditAccountPage.ets @@ -318,6 +318,7 @@ struct EditAccountPage { .fontSize(16) .fontColor($r('app.color.text_primary')) .placeholderColor($r('app.color.text_hint')) + .caretColor($r('app.color.brand')) .backgroundColor($r('app.color.input_bg')) .borderRadius(10) .border({ width: 1.5, color: $r('app.color.brand') }) @@ -434,6 +435,8 @@ struct EditAccountPage { .height('100%') .padding({ left: 24, right: 24, top: 16, bottom: 24 }) .backgroundColor($r('app.color.page_bg')) + // 沉浸式:背景延伸到状态栏/导航条区域(只扩绘制、不移动子组件) + .expandSafeArea([SafeAreaType.SYSTEM], [SafeAreaEdge.TOP, SafeAreaEdge.BOTTOM]) .alignItems(HorizontalAlign.Center) } } diff --git a/entry/src/main/ets/pages/EventEditPage.ets b/entry/src/main/ets/pages/EventEditPage.ets index dc466b4..e9615ec 100644 --- a/entry/src/main/ets/pages/EventEditPage.ets +++ b/entry/src/main/ets/pages/EventEditPage.ets @@ -425,6 +425,11 @@ struct EventEditPage { .fontSize(16) .backgroundColor($r('app.color.card_bg')) .borderRadius(12) + // 显式指定文字/提示/光标颜色:TextInput 默认取系统主题色, + // 深色模式下会变成浅色文字 → 与卡片底色撞色而"看不清" + .fontColor($r('app.color.text_primary')) + .placeholderColor($r('app.color.text_hint')) + .caretColor($r('app.color.brand')) .onChange((v: string) => { this.title = v; }) @@ -541,6 +546,9 @@ struct EventEditPage { .fontSize(14) .backgroundColor($r('app.color.card_bg')) .borderRadius(12) + .fontColor($r('app.color.text_primary')) + .placeholderColor($r('app.color.text_hint')) + .caretColor($r('app.color.brand')) .onChange((v: string) => { this.location = v; }) @@ -551,6 +559,9 @@ struct EventEditPage { .fontSize(14) .backgroundColor($r('app.color.card_bg')) .borderRadius(12) + .fontColor($r('app.color.text_primary')) + .placeholderColor($r('app.color.text_hint')) + .caretColor($r('app.color.brand')) .onChange((v: string) => { this.description = v; }) @@ -591,6 +602,8 @@ struct EventEditPage { .height('100%') .padding({ top: 12 }) .backgroundColor($r('app.color.page_bg')) + // 沉浸式:背景延伸到状态栏/导航条区域(只扩绘制、不移动子组件) + .expandSafeArea([SafeAreaType.SYSTEM], [SafeAreaEdge.TOP, SafeAreaEdge.BOTTOM]) .bindSheet($$this.pickerShow, this.dateTimePickerSheet(), { height: 380, showClose: false, @@ -698,6 +711,13 @@ struct EventEditPage { .onDateChange((value: Date) => { this.pickDate = value; }) + // 滚轮文字显式指定颜色:默认取系统主题色,深色模式下与弹层底色撞色会"看不清" + .textStyle({ color: $r('app.color.text_secondary'), font: { size: 14 } }) + .selectedTextStyle({ + color: $r('app.color.text_primary'), + font: { size: 16, weight: FontWeight.Medium } + }) + .disappearTextStyle({ color: $r('app.color.text_hint'), font: { size: 14 } }) .layoutWeight(1) .height(210) if (!this.allDay) { @@ -708,6 +728,12 @@ struct EventEditPage { this.pickHour = value.hour; this.pickMin = value.minute; }) + .textStyle({ color: $r('app.color.text_secondary'), font: { size: 14 } }) + .selectedTextStyle({ + color: $r('app.color.text_primary'), + font: { size: 16, weight: FontWeight.Medium } + }) + .disappearTextStyle({ color: $r('app.color.text_hint'), font: { size: 14 } }) .layoutWeight(1) .height(210) } diff --git a/entry/src/main/ets/pages/Index.ets b/entry/src/main/ets/pages/Index.ets index 9f73b73..b891c1a 100644 --- a/entry/src/main/ets/pages/Index.ets +++ b/entry/src/main/ets/pages/Index.ets @@ -1042,6 +1042,10 @@ struct Index { } .width('100%') .height('100%') + // 沉浸式:根容器背景延伸到状态栏/导航条区域(只扩绘制、不移动子组件), + // 配合 EntryAbility 里"系统栏透明"的设置,彻底消除顶部通知栏与底部灰条。 + .backgroundColor($r('app.color.page_bg')) + .expandSafeArea([SafeAreaType.SYSTEM], [SafeAreaEdge.TOP, SafeAreaEdge.BOTTOM]) .bindSheet($$this.detailShow, this.detailSheet(), { height: 540, dragBar: true, @@ -1299,7 +1303,7 @@ struct Index { .borderRadius(12) .backgroundColor($r('app.color.card_bg')) .border({ width: 1, color: $r('app.color.shadow_color') }) - .shadow({ radius: 12, color: '#22000000', offsetY: 4 }) + .shadow({ radius: 12, color: $r('app.color.shadow_color'), offsetY: 4 }) .margin({ top: 56, right: 20 }) } .width('100%') @@ -2925,7 +2929,7 @@ struct DayTimelineView { .height(this.hourUnit) .textAlign(TextAlign.End) .padding({ right: 4, top: 2 }) - .border({ width: { bottom: 0.5 }, color: { bottom: '#14000000' } }) + .border({ width: { bottom: 0.5 }, color: { bottom: $r('app.color.grid_line') } }) }, (h: number) => `h${h}`) } .width(36) @@ -2941,7 +2945,7 @@ struct DayTimelineView { .layoutWeight(1) .height(this.viewH()) .alignContent(Alignment.TopStart) - .border({ width: { left: 0.5 }, color: { left: '#14000000' } }) + .border({ width: { left: 0.5 }, color: { left: $r('app.color.grid_line') } }) } .width('100%') .alignItems(VerticalAlign.Top) @@ -2959,7 +2963,7 @@ struct DayTimelineView { Column() .width('100%') .height(this.hourUnit) - .border({ width: { bottom: 0.5 }, color: { bottom: '#14000000' } }) + .border({ width: { bottom: 0.5 }, color: { bottom: $r('app.color.grid_line') } }) .hitTestBehavior(HitTestMode.None) // 装饰层子节点同样不参与命中测试 }, (h: number) => `gd_${h}`) } diff --git a/entry/src/main/ets/pages/SettingsPage.ets b/entry/src/main/ets/pages/SettingsPage.ets index 33a299b..ab32c96 100644 --- a/entry/src/main/ets/pages/SettingsPage.ets +++ b/entry/src/main/ets/pages/SettingsPage.ets @@ -1083,5 +1083,7 @@ struct SettingsPage { .width('100%') .height('100%') .backgroundColor($r('app.color.page_bg')) + // 沉浸式:背景延伸到状态栏/导航条区域(只扩绘制、不移动子组件) + .expandSafeArea([SafeAreaType.SYSTEM], [SafeAreaEdge.TOP, SafeAreaEdge.BOTTOM]) } } diff --git a/entry/src/main/resources/dark/element/color.json b/entry/src/main/resources/dark/element/color.json new file mode 100644 index 0000000..407dde8 --- /dev/null +++ b/entry/src/main/resources/dark/element/color.json @@ -0,0 +1,23 @@ +{ + "color": [ + { "name": "start_window_background", "value": "#000000" }, + { "name": "page_bg", "value": "#000000" }, + { "name": "card_bg", "value": "#1C1C1E" }, + { "name": "input_bg", "value": "#2C2C2E" }, + { "name": "text_primary", "value": "#E5E5E7" }, + { "name": "text_secondary", "value": "#99FFFFFF" }, + { "name": "text_hint", "value": "#66FFFFFF" }, + { "name": "brand", "value": "#0A84FF" }, + { "name": "brand_disabled", "value": "#660A84FF" }, + { "name": "button_text", "value": "#FFFFFF" }, + { "name": "success", "value": "#34C759" }, + { "name": "success_bg", "value": "#1F34C759" }, + { "name": "error", "value": "#FF453A" }, + { "name": "error_bg", "value": "#1FFF453A" }, + { "name": "shadow_color", "value": "#1FFFFFFF" }, + { "name": "grid_line", "value": "#1FFFFFFF" }, + { "name": "today_bg", "value": "#330A84FF" }, + { "name": "selected_bg", "value": "#0A84FF" }, + { "name": "chip_off_bg", "value": "#1FFFFFFF" } + ] +}