From 2128df768c63ae5d9f214a83bf245fdbc2168d62 Mon Sep 17 00:00:00 2001 From: EasyGuohf <163991322+EasyGuohf@users.noreply.github.com> Date: Thu, 3 Jul 2025 16:01:42 +0800 Subject: [PATCH 1/8] =?UTF-8?q?=E4=B8=80=E5=A4=9A=E5=AF=BC=E8=88=AA?= =?UTF-8?q?=E6=A0=8Fhar=E5=8C=85=E5=9B=9E=E5=90=88=E5=8F=8AAppStorage?= =?UTF-8?q?=E6=95=B4=E6=94=B9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- multinavbarlibrary/Index.ets | 2 +- multinavbarlibrary/hvigorfile.ts | 2 +- multinavbarlibrary/oh-package.json5 | 2 +- .../ets/common/utils/BreakpointSystem.ets | 2 +- .../src/main/ets/common/utils/WindowUtils.ets | 36 +++++++------ .../src/main/ets/pages/MultiNavBarPage.ets | 2 +- multinavbarlibrary/src/main/ets/view/Home.ets | 2 +- .../src/main/ets/view/TopTabView.ets | 25 +++++++-- .../src/main/ets/view/VideoInfoView.ets | 51 ++++++++++++++++--- multinavbarlibrary/src/main/module.json5 | 2 +- .../main/ets/entryability/EntryAbility.ets | 3 +- 11 files changed, 92 insertions(+), 37 deletions(-) diff --git a/multinavbarlibrary/Index.ets b/multinavbarlibrary/Index.ets index 49ca810..64c3717 100644 --- a/multinavbarlibrary/Index.ets +++ b/multinavbarlibrary/Index.ets @@ -1 +1 @@ -export { MultiNavBarPage } from './src/main/ets/pages/MultiNavBarPage'; +export { MultiNavBarPage } from './src/main/ets/pages/MultiNavBarPage'; \ No newline at end of file diff --git a/multinavbarlibrary/hvigorfile.ts b/multinavbarlibrary/hvigorfile.ts index 4218707..a4f778b 100644 --- a/multinavbarlibrary/hvigorfile.ts +++ b/multinavbarlibrary/hvigorfile.ts @@ -3,4 +3,4 @@ import { harTasks } from '@ohos/hvigor-ohos-plugin'; export default { system: harTasks, /* Built-in plugin of Hvigor. It cannot be modified. */ plugins:[] /* Custom plugin to extend the functionality of Hvigor. */ -} +} \ No newline at end of file diff --git a/multinavbarlibrary/oh-package.json5 b/multinavbarlibrary/oh-package.json5 index fcc72a9..6e3f873 100644 --- a/multinavbarlibrary/oh-package.json5 +++ b/multinavbarlibrary/oh-package.json5 @@ -6,4 +6,4 @@ "author": "", "license": "Apache-2.0", "dependencies": {} -} +} \ No newline at end of file diff --git a/multinavbarlibrary/src/main/ets/common/utils/BreakpointSystem.ets b/multinavbarlibrary/src/main/ets/common/utils/BreakpointSystem.ets index 0799771..bd12aa6 100644 --- a/multinavbarlibrary/src/main/ets/common/utils/BreakpointSystem.ets +++ b/multinavbarlibrary/src/main/ets/common/utils/BreakpointSystem.ets @@ -84,7 +84,7 @@ export class BreakpointSystem { public updateCurrentBreakpoint(breakpoint: BreakpointTypeEnum): void { if (this.currentBreakpoint !== breakpoint) { this.currentBreakpoint = breakpoint; - AppStorage.setOrCreate('currentWidthBreakpoint', this.currentBreakpoint); + AppStorage.setOrCreate('navBarBreakpoint', this.currentBreakpoint); } } diff --git a/multinavbarlibrary/src/main/ets/common/utils/WindowUtils.ets b/multinavbarlibrary/src/main/ets/common/utils/WindowUtils.ets index dd767c0..270591b 100644 --- a/multinavbarlibrary/src/main/ets/common/utils/WindowUtils.ets +++ b/multinavbarlibrary/src/main/ets/common/utils/WindowUtils.ets @@ -48,19 +48,25 @@ export class WindowUtil { hilog.error(0x0000, TAG, `Failed to get main window: ${err.message}`); return; } - BreakpointSystem.getInstance().updateWidthBp(data); - data.on('windowSizeChange', () => BreakpointSystem.getInstance().onWindowSizeChange(data)); - if (deviceInfo.deviceType === '2in1') { - data.setWindowDecorVisible(false); - data.setWindowDecorHeight(64); - } else { - WindowUtil.requestFullScreen(windowStage) - data.on('avoidAreaChange', (avoidAreaOption) => { - if (avoidAreaOption.type === window.AvoidAreaType.TYPE_SYSTEM || - avoidAreaOption.type === window.AvoidAreaType.TYPE_NAVIGATION_INDICATOR) { - WindowUtil.setAvoidArea(avoidAreaOption.type, avoidAreaOption.area); - } - }); + try { + BreakpointSystem.getInstance().updateWidthBp(data); + data.on('windowSizeChange', () => BreakpointSystem.getInstance().onWindowSizeChange(data)); + if (deviceInfo.deviceType === '2in1' && canIUse('SystemCapability.Window.SessionManager')) { + data.setWindowDecorVisible(false); + data.setWindowDecorHeight(64); + } else { + WindowUtil.requestFullScreen(windowStage) + data.on('avoidAreaChange', (avoidAreaOption) => { + if (avoidAreaOption.type === window.AvoidAreaType.TYPE_SYSTEM || + avoidAreaOption.type === window.AvoidAreaType.TYPE_NAVIGATION_INDICATOR) { + WindowUtil.setAvoidArea(avoidAreaOption.type, avoidAreaOption.area); + } + }); + } + } catch (error) { + const err: BusinessError = error as BusinessError; + hilog.error(0x0000, TAG, + `Failed to set the window decor or get the WindowAvoidArea. Cause: ${err.code}, ${err.message}`); } }) } @@ -68,9 +74,9 @@ export class WindowUtil { // Get status bar height and indicator height. public static setAvoidArea(type: window.AvoidAreaType, area: window.AvoidArea) { if (type === window.AvoidAreaType.TYPE_SYSTEM) { - AppStorage.setOrCreate('statusBarHeight', px2vp(area.topRect.height)); + AppStorage.setOrCreate('navBarStatusBarHeight', px2vp(area.topRect.height)); } else { - AppStorage.setOrCreate('naviIndicatorHeight', px2vp(area.bottomRect.height)); + AppStorage.setOrCreate('navBarNaviIndicatorHeight', px2vp(area.bottomRect.height)); } } } \ No newline at end of file diff --git a/multinavbarlibrary/src/main/ets/pages/MultiNavBarPage.ets b/multinavbarlibrary/src/main/ets/pages/MultiNavBarPage.ets index 1ea96f0..4aa9051 100644 --- a/multinavbarlibrary/src/main/ets/pages/MultiNavBarPage.ets +++ b/multinavbarlibrary/src/main/ets/pages/MultiNavBarPage.ets @@ -1,4 +1,4 @@ -import { Home } from "../view/Home" +import { Home } from "../view/Home"; @Component export struct MultiNavBarPage { diff --git a/multinavbarlibrary/src/main/ets/view/Home.ets b/multinavbarlibrary/src/main/ets/view/Home.ets index 3a6de04..7a6ef30 100644 --- a/multinavbarlibrary/src/main/ets/view/Home.ets +++ b/multinavbarlibrary/src/main/ets/view/Home.ets @@ -21,7 +21,7 @@ import { VideoInfoView } from './VideoInfoView'; @Component export struct Home { - @StorageLink('currentWidthBreakpoint') currentWidthBreakpoint: string = 'sm'; + @StorageLink('navBarBreakpoint') currentWidthBreakpoint: string = 'sm'; @State firstLevelIndex: number = 0; @State secondLevelIndex: number = 0; @State tabViewModel: TabViewModel = new TabViewModel(); diff --git a/multinavbarlibrary/src/main/ets/view/TopTabView.ets b/multinavbarlibrary/src/main/ets/view/TopTabView.ets index c0b9a42..d0a8993 100644 --- a/multinavbarlibrary/src/main/ets/view/TopTabView.ets +++ b/multinavbarlibrary/src/main/ets/view/TopTabView.ets @@ -23,9 +23,9 @@ const TAG: string = '[TopTabView]'; @Component export struct TopTabView { - @StorageLink('currentWidthBreakpoint') currentWidthBreakpoint: string = 'sm'; + @StorageLink('navBarBreakpoint') currentWidthBreakpoint: string = 'sm'; @State secondLevelIndex: number = 0; - @State statusBarHeight: number = AppStorage.get('statusBarHeight')!; + @State statusBarHeight: number = AppStorage.get('navBarStatusBarHeight')!; @Link tabData: TabDataModel; private firstLevel: string = ''; @@ -53,7 +53,12 @@ export struct TopTabView { } .align(Alignment.Center) .padding({ - right: new BreakpointType({sm:8, md:12, lg:18, xl:0}).getValue(this.currentWidthBreakpoint) + right: new BreakpointType({ + sm: 8, + md: 12, + lg: 18, + xl: 0 + }).getValue(this.currentWidthBreakpoint) }) .onClick(() => { this.secondLevelIndex = index; @@ -63,8 +68,18 @@ export struct TopTabView { .scrollBar(BarState.Off) .listDirection(Axis.Horizontal) .padding({ - left: new BreakpointType({sm:16, md:24, lg:36, xl:24}).getValue(this.currentWidthBreakpoint), - right: new BreakpointType({sm:16, md:24, lg:36, xl:24}).getValue(this.currentWidthBreakpoint), + left: new BreakpointType({ + sm: 16, + md: 24, + lg: 36, + xl: 24 + }).getValue(this.currentWidthBreakpoint), + right: new BreakpointType({ + sm: 16, + md: 24, + lg: 36, + xl: 24 + }).getValue(this.currentWidthBreakpoint), top: $r('sys.float.padding_level5') }) .height(56) diff --git a/multinavbarlibrary/src/main/ets/view/VideoInfoView.ets b/multinavbarlibrary/src/main/ets/view/VideoInfoView.ets index da7f559..27f1324 100644 --- a/multinavbarlibrary/src/main/ets/view/VideoInfoView.ets +++ b/multinavbarlibrary/src/main/ets/view/VideoInfoView.ets @@ -18,7 +18,7 @@ import { VideoViewModel } from '../viewmodel/VideoViewModel'; @Component export struct VideoInfoView { - @StorageLink('currentWidthBreakpoint') currentWidthBreakpoint: string = 'sm'; + @StorageLink('navBarBreakpoint') currentWidthBreakpoint: string = 'sm'; @Link secondLevelIndex: number; private videoViewModel = new VideoViewModel(); private iteration: number[] = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16]; @@ -39,7 +39,12 @@ export struct VideoInfoView { .borderRadius(12) .backgroundColor($r('sys.color.ohos_id_color_click_effect')) .margin({ - top: new BreakpointType({sm:10, md:10, lg:12, xl:11}).getValue(this.currentWidthBreakpoint), + top: new BreakpointType({ + sm: 10, + md: 10, + lg: 12, + xl: 11 + }).getValue(this.currentWidthBreakpoint), bottom: 6 }) @@ -57,16 +62,46 @@ export struct VideoInfoView { } .layoutWeight(1) .scrollBar(BarState.Off) - .columnsTemplate(new BreakpointType({sm:'1fr 1fr', md:'1fr 1fr 1fr', lg:'1fr 1fr 1fr 1fr', xl:'1fr 1fr 1fr'}) + .columnsTemplate(new BreakpointType({ + sm: '1fr 1fr', + md: '1fr 1fr 1fr', + lg: '1fr 1fr 1fr 1fr', + xl: '1fr 1fr 1fr' + }) .getValue(this.currentWidthBreakpoint)) .width('100%') - .rowsGap(new BreakpointType({sm:12, md:16, lg:16, xl:16}).getValue(this.currentWidthBreakpoint)) - .columnsGap(new BreakpointType({sm:16, md:12, lg:16, xl:16}).getValue(this.currentWidthBreakpoint)) + .rowsGap(new BreakpointType({ + sm: 12, + md: 16, + lg: 16, + xl: 16 + }).getValue(this.currentWidthBreakpoint)) + .columnsGap(new BreakpointType({ + sm: 16, + md: 12, + lg: 16, + xl: 16 + }).getValue(this.currentWidthBreakpoint)) .padding({ - left: new BreakpointType({sm:16, md:24, lg:36, xl:24}).getValue(this.currentWidthBreakpoint), - right: new BreakpointType({sm:16, md:24, lg:36, xl:24}).getValue(this.currentWidthBreakpoint), + left: new BreakpointType({ + sm: 16, + md: 24, + lg: 36, + xl: 24 + }).getValue(this.currentWidthBreakpoint), + right: new BreakpointType({ + sm: 16, + md: 24, + lg: 36, + xl: 24 + }).getValue(this.currentWidthBreakpoint), top: 12, - bottom: new BreakpointType({sm:6, md:6, lg:20, xl:20}).getValue(this.currentWidthBreakpoint) + bottom: new BreakpointType({ + sm: 6, + md: 6, + lg: 20, + xl: 20 + }).getValue(this.currentWidthBreakpoint) }) } } \ No newline at end of file diff --git a/multinavbarlibrary/src/main/module.json5 b/multinavbarlibrary/src/main/module.json5 index ef4e58e..19c971a 100644 --- a/multinavbarlibrary/src/main/module.json5 +++ b/multinavbarlibrary/src/main/module.json5 @@ -8,4 +8,4 @@ "2in1" ] } -} +} \ No newline at end of file diff --git a/multinavbarsample/src/main/ets/entryability/EntryAbility.ets b/multinavbarsample/src/main/ets/entryability/EntryAbility.ets index c1acff5..ff3f6d7 100644 --- a/multinavbarsample/src/main/ets/entryability/EntryAbility.ets +++ b/multinavbarsample/src/main/ets/entryability/EntryAbility.ets @@ -22,7 +22,6 @@ import { WindowUtil } from 'multinavbarlibrary/src/main/ets/common/utils/WindowU const TAG: string = '[EntryAbility]'; export default class EntryAbility extends UIAbility { - onCreate(): void { hilog.info(0x0000, TAG, 'Ability onCreate'); this.context.getApplicationContext().setColorMode(ConfigurationConstant.ColorMode.COLOR_MODE_NOT_SET); @@ -37,6 +36,6 @@ export default class EntryAbility extends UIAbility { } hilog.info(0x0000, TAG, 'Succeeded in loading the content.'); }); - WindowUtil.registerBreakPoint(windowStage) + WindowUtil.registerBreakPoint(windowStage); } } \ No newline at end of file -- Gitee From 71ca5afd21dfb120b1cfc1e21ed72b0ea9d7fb26 Mon Sep 17 00:00:00 2001 From: EasyGuohf <163991322+EasyGuohf@users.noreply.github.com> Date: Fri, 4 Jul 2025 17:40:00 +0800 Subject: [PATCH 2/8] =?UTF-8?q?=E9=81=BF=E8=AE=A9=E5=88=9D=E5=A7=8B?= =?UTF-8?q?=E5=8C=96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- multinavbarlibrary/src/main/ets/common/utils/WindowUtils.ets | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/multinavbarlibrary/src/main/ets/common/utils/WindowUtils.ets b/multinavbarlibrary/src/main/ets/common/utils/WindowUtils.ets index 270591b..1869972 100644 --- a/multinavbarlibrary/src/main/ets/common/utils/WindowUtils.ets +++ b/multinavbarlibrary/src/main/ets/common/utils/WindowUtils.ets @@ -50,6 +50,11 @@ export class WindowUtil { } try { BreakpointSystem.getInstance().updateWidthBp(data); + const systemAvoidArea: window.AvoidArea = data.getWindowAvoidArea(window.AvoidAreaType.TYPE_SYSTEM); + const navIndicatorAvoidArea: window.AvoidArea = + data.getWindowAvoidArea(window.AvoidAreaType.TYPE_NAVIGATION_INDICATOR); + WindowUtil.setAvoidArea(window.AvoidAreaType.TYPE_SYSTEM, systemAvoidArea); + WindowUtil.setAvoidArea(window.AvoidAreaType.TYPE_NAVIGATION_INDICATOR, navIndicatorAvoidArea); data.on('windowSizeChange', () => BreakpointSystem.getInstance().onWindowSizeChange(data)); if (deviceInfo.deviceType === '2in1' && canIUse('SystemCapability.Window.SessionManager')) { data.setWindowDecorVisible(false); -- Gitee From 0e9695b14a638ff21b06e685b52e2b14c0cbde13 Mon Sep 17 00:00:00 2001 From: EasyGuohf <163991322+EasyGuohf@users.noreply.github.com> Date: Fri, 4 Jul 2025 17:44:10 +0800 Subject: [PATCH 3/8] =?UTF-8?q?=E6=96=AD=E7=82=B9=E5=88=9D=E5=A7=8B?= =?UTF-8?q?=E5=8C=96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/main/ets/common/utils/BreakpointSystem.ets | 1 + 1 file changed, 1 insertion(+) diff --git a/multinavbarlibrary/src/main/ets/common/utils/BreakpointSystem.ets b/multinavbarlibrary/src/main/ets/common/utils/BreakpointSystem.ets index bd12aa6..8280dc0 100644 --- a/multinavbarlibrary/src/main/ets/common/utils/BreakpointSystem.ets +++ b/multinavbarlibrary/src/main/ets/common/utils/BreakpointSystem.ets @@ -77,6 +77,7 @@ export class BreakpointSystem { public static getInstance(): BreakpointSystem { if (!BreakpointSystem.instance) { BreakpointSystem.instance = new BreakpointSystem(); + AppStorage.setOrCreate('navBarBreakpoint', BreakpointTypeEnum.MD); } return BreakpointSystem.instance; } -- Gitee From 80ed9f8f12df6806bd9791d938721b72712601d9 Mon Sep 17 00:00:00 2001 From: EasyGuohf <163991322+EasyGuohf@users.noreply.github.com> Date: Tue, 8 Jul 2025 16:48:19 +0800 Subject: [PATCH 4/8] =?UTF-8?q?=E6=96=B0=E5=A2=9E=E5=BC=80=E6=BA=90?= =?UTF-8?q?=E6=A8=A1=E6=9D=BF=E6=96=87=E4=BB=B6=E5=8F=8A=E8=A7=84=E8=8C=83?= =?UTF-8?q?=E4=BC=98=E5=8C=96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- multinavbarlibrary/CHANGELOG.md | 6 ++ multinavbarlibrary/Index.ets | 4 +- multinavbarlibrary/LICENSE | 78 +++++++++++++++++++ multinavbarlibrary/README.md | 42 ++++++++++ multinavbarlibrary/oh-package.json5 | 7 +- .../main/ets/entryability/EntryAbility.ets | 2 +- 6 files changed, 134 insertions(+), 5 deletions(-) create mode 100644 multinavbarlibrary/CHANGELOG.md create mode 100644 multinavbarlibrary/LICENSE create mode 100644 multinavbarlibrary/README.md diff --git a/multinavbarlibrary/CHANGELOG.md b/multinavbarlibrary/CHANGELOG.md new file mode 100644 index 0000000..b525b8c --- /dev/null +++ b/multinavbarlibrary/CHANGELOG.md @@ -0,0 +1,6 @@ +# 版本记录 +## 1.0.0(2025.07.08) + +--- +### Initial +- 初始版本 diff --git a/multinavbarlibrary/Index.ets b/multinavbarlibrary/Index.ets index 64c3717..7766b29 100644 --- a/multinavbarlibrary/Index.ets +++ b/multinavbarlibrary/Index.ets @@ -1 +1,3 @@ -export { MultiNavBarPage } from './src/main/ets/pages/MultiNavBarPage'; \ No newline at end of file +export { MultiNavBarPage } from './src/main/ets/pages/MultiNavBarPage'; + +export { WindowUtil } from './src/main/ets/common/utils/WindowUtils'; \ No newline at end of file diff --git a/multinavbarlibrary/LICENSE b/multinavbarlibrary/LICENSE new file mode 100644 index 0000000..338e5b0 --- /dev/null +++ b/multinavbarlibrary/LICENSE @@ -0,0 +1,78 @@ + Copyright (c) 2024 Huawei Device Co., Ltd. All rights reserved. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + +Apache License, Version 2.0 +TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + +1. Definitions. + +"License" shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 through 9 of this document. + +"Licensor" shall mean the copyright owner or entity authorized by the copyright owner that is granting the License. + +"Legal Entity" shall mean the union of the acting entity and all other entities that control, are controlled by, or are under common control with that entity. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity. + +"You" (or "Your") shall mean an individual or Legal Entity exercising permissions granted by this License. + +"Source" form shall mean the preferred form for making modifications, including but not limited to software source code, documentation source, and configuration files. + +"Object" form shall mean any form resulting from mechanical transformation or translation of a Source form, including but not limited to compiled object code, generated documentation, and conversions to other media types. + +"Work" shall mean the work of authorship, whether in Source or Object form, made available under the License, as indicated by a copyright notice that is included in or attached to the work (an example is provided in the Appendix below). + +"Derivative Works" shall mean any work, whether in Source or Object form, that is based on (or derived from) the Work and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. For the purposes of this License, Derivative Works shall not include works that remain separable from, or merely link (or bind by name) to the interfaces of, the Work and Derivative Works thereof. + +"Contribution" shall mean any work of authorship, including the original version of the Work and any modifications or additions to that Work or Derivative Works thereof, that is intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by an individual or Legal Entity authorized to submit on behalf of the copyright owner. For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to the Licensor or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, the Licensor for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by the copyright owner as "Not a Contribution." + +"Contributor" shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been received by Licensor and subsequently incorporated within the Work. + +2. Grant of Copyright License. + +Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or Object form. + +3. Grant of Patent License. + +Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by such Contributor that are necessarily infringed by their Contribution(s) alone or by combination of their Contribution(s) with the Work to which such Contribution(s) was submitted. If You institute patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Work or a Contribution incorporated within the Work constitutes direct or contributory patent infringement, then any patent licenses granted to You under this License for that Work shall terminate as of the date such litigation is filed. + +4. Redistribution. + +You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without modifications, and in Source or Object form, provided that You meet the following conditions: +1.You must give any other recipients of the Work or Derivative Works a copy of this License; and +2.You must cause any modified files to carry prominent notices stating that You changed the files; and +3.You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent, trademark, and attribution notices from the Source form of the Work, excluding those notices that do not pertain to any part of the Derivative Works; and +4.If the Work includes a "NOTICE" text file as part of its distribution, then any Derivative Works that You distribute must include a readable copy of the attribution notices contained within such NOTICE file, excluding those notices that do not pertain to any part of the Derivative Works, in at least one of the following places: within a NOTICE text file distributed as part of the Derivative Works; within the Source form or documentation, if provided along with the Derivative Works; or, within a display generated by the Derivative Works, if and wherever such third-party notices normally appear. The contents of the NOTICE file are for informational purposes only and do not modify the License. You may add Your own attribution notices within Derivative Works that You distribute, alongside or as an addendum to the NOTICE text from the Work, provided that such additional attribution notices cannot be construed as modifying the License. + +You may add Your own copyright statement to Your modifications and may provide additional or different license terms and conditions for use, reproduction, or distribution of Your modifications, or for any such Derivative Works as a whole, provided Your use, reproduction, and distribution of the Work otherwise complies with the conditions stated in this License. + +5. Submission of Contributions. + +Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by You to the Licensor shall be under the terms and conditions of this License, without any additional terms or conditions. Notwithstanding the above, nothing herein shall supersede or modify the terms of any separate license agreement you may have executed with Licensor regarding such Contributions. + +6. Trademarks. + +This License does not grant permission to use the trade names, trademarks, service marks, or product names of the Licensor, except as required for reasonable and customary use in describing the origin of the Work and reproducing the content of the NOTICE file. + +7. Disclaimer of Warranty. + +Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness of using or redistributing the Work and assume any risks associated with Your exercise of permissions under this License. + +8. Limitation of Liability. + +In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be liable to You for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising as a result of this License or out of the use or inability to use the Work (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses), even if such Contributor has been advised of the possibility of such damages. + +9. Accepting Warranty or Additional Liability. + +While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole responsibility, not on behalf of any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability. + +END OF TERMS AND CONDITIONS \ No newline at end of file diff --git a/multinavbarlibrary/README.md b/multinavbarlibrary/README.md new file mode 100644 index 0000000..4d72e76 --- /dev/null +++ b/multinavbarlibrary/README.md @@ -0,0 +1,42 @@ +## 多设备分级导航栏 + +### 介绍 + +本示例基于自适应布局和响应式布局,实现多设备上的分级导航栏效果。 + +### 下载安装 + +使用ohpm安装依赖 + +``` +ohpm install @ohos_samples/multinavbarlibrary +``` + +或者按需在模块中修改oh-package.json5 + +``` +{ + "dependencies": { + "@ohos_samples/multinavbarlibrary": "^1.0.0" + } +} +``` + +### 使用说明 + +``` +import { MultiNavBarPage, WindowUtil } from '@ohos_samples/multinavbarlibrary'; +``` +按需在文件中使用导出模块即可,其中MultiNavBarPage是整个sample的入口页面。WindowUtil封装了沉浸式、设备断点判断、避让区域计算等窗口能力。示例如下: +``` +// Page.ets +import { MultiNavBarPage } from '@ohos_samples/multinavbarlibrary'; +Stack() { + MultiNavBarPage() +} + +// EntryAbility.ets +import { WindowUtil } from '@ohos_samples/multinavbarlibrary'; +WindowUtil.requestFullScreen(windowStage); +WindowUtil.registerBreakPoint(windowStage); +``` \ No newline at end of file diff --git a/multinavbarlibrary/oh-package.json5 b/multinavbarlibrary/oh-package.json5 index 6e3f873..1caad8e 100644 --- a/multinavbarlibrary/oh-package.json5 +++ b/multinavbarlibrary/oh-package.json5 @@ -1,9 +1,10 @@ { - "name": "multinavbarlibrary", + "name": "@ohos_samples/multinavbarlibrary", "version": "1.0.0", - "description": "Please describe the basic information.", + "description": "This sample shows the style of the navigation component in different device forms.", "main": "Index.ets", - "author": "", + "author": "@ohos_samples", "license": "Apache-2.0", + "repository": "https://gitee.com/harmonyos_samples/multi-nav-bar/tree/br_release_hmos/", "dependencies": {} } \ No newline at end of file diff --git a/multinavbarsample/src/main/ets/entryability/EntryAbility.ets b/multinavbarsample/src/main/ets/entryability/EntryAbility.ets index ff3f6d7..581570c 100644 --- a/multinavbarsample/src/main/ets/entryability/EntryAbility.ets +++ b/multinavbarsample/src/main/ets/entryability/EntryAbility.ets @@ -15,7 +15,7 @@ import { ConfigurationConstant, UIAbility } from '@kit.AbilityKit'; import { window } from '@kit.ArkUI'; -import { BusinessError, deviceInfo } from '@kit.BasicServicesKit'; +import { BusinessError } from '@kit.BasicServicesKit'; import { hilog } from '@kit.PerformanceAnalysisKit'; import { WindowUtil } from 'multinavbarlibrary/src/main/ets/common/utils/WindowUtils'; -- Gitee From 9c8573823577364c471ba530f1990fe5e509645e Mon Sep 17 00:00:00 2001 From: EasyGuohf <163991322+EasyGuohf@users.noreply.github.com> Date: Thu, 10 Jul 2025 17:53:41 +0800 Subject: [PATCH 5/8] =?UTF-8?q?=E6=96=B0=E8=A7=84=E8=8C=83=E4=BC=98?= =?UTF-8?q?=E5=8C=96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 32 ++++++++++++------- multinavbarlibrary/CHANGELOG.md | 2 +- multinavbarlibrary/Index.ets | 4 +-- multinavbarlibrary/README.md | 14 ++++---- .../src/main/ets/NavBarController.ets | 22 +++++++++++++ .../src/main/ets/common/Constants.ets | 27 ++++++++++++++++ .../ets/common/utils/BreakpointSystem.ets | 7 ++-- .../src/main/ets/common/utils/WindowUtils.ets | 26 +++++++++++---- .../MultiNavBarComponent.ets} | 3 +- multinavbarlibrary/src/main/ets/view/Home.ets | 3 +- .../src/main/ets/view/TopTabView.ets | 8 +++-- .../src/main/ets/view/VideoInfoView.ets | 3 +- .../src/main/ets/viewmodel/TabViewModel.ets | 10 +++--- multinavbarsample/oh-package.json5 | 2 +- .../main/ets/entryability/EntryAbility.ets | 7 ++-- .../src/main/ets/pages/Index.ets | 4 +-- 16 files changed, 125 insertions(+), 49 deletions(-) create mode 100644 multinavbarlibrary/src/main/ets/NavBarController.ets create mode 100644 multinavbarlibrary/src/main/ets/common/Constants.ets rename multinavbarlibrary/src/main/ets/{pages/MultiNavBarPage.ets => component/MultiNavBarComponent.ets} (79%) diff --git a/README.md b/README.md index 6ff2819..849c207 100644 --- a/README.md +++ b/README.md @@ -22,27 +22,35 @@ ### 工程目录 ``` -├──entry/src/main/ets // 代码区 +multinavbarlibrary +├──src/main/ets // 代码区 │ ├──common -│ │ └──utils -│ │ ├──BreakpointType.ets // 断点工具类 -│ │ └──WindowUtils.ets // 窗口工具类 -│ ├──entryability -│ │ └──EntryAbility.ets // 程序入口类 +│ │ ├──utils +│ │ │ ├──BreakpointType.ets // 断点工具类 +│ │ │ └──WindowUtils.ets // 窗口工具类 +│ │ └──Constants.ets │ ├──model │ │ ├──TabDataModel.ets // 导航目录数据类 │ │ └──VideoDataModel.ets // 内容区数据类 -│ ├──pages -│ │ └──Index.ets // 首页 +│ ├──component +│ │ └──MultiNavBarComponent.ets // 首页 │ ├──view │ │ ├──Home.ets // 主页 │ │ ├──SideBarView.ets // 侧边栏 │ │ ├──TopTabView.ets // 顶部页签 │ │ └──VideoInfoView.ets // 内容区域页 -│ └──viewmodel -│ ├──TabViewModel.ets // 导航目录数据 -│ └──VideoViewModel.ets // 内容区数据 -└──entry/src/main/resources // 应用静态资源目录 +│ ├──viewmodel +│ │ ├──TabViewModel.ets // 导航目录数据 +│ │ └──VideoViewModel.ets // 内容区数据 +│ └──NavBarController.ets +└──src/main/resources // 应用静态资源目录 +multinavbarsample +├──src/main/ets // 代码区 +│ ├──entryability +│ │ └──EntryAbility.ets +│ └──pages +│ └──Index.ets // 入口页面 +└──src/main/resources // 应用资源目录 ``` ### 具体实现 diff --git a/multinavbarlibrary/CHANGELOG.md b/multinavbarlibrary/CHANGELOG.md index b525b8c..10f7f3f 100644 --- a/multinavbarlibrary/CHANGELOG.md +++ b/multinavbarlibrary/CHANGELOG.md @@ -1,5 +1,5 @@ # 版本记录 -## 1.0.0(2025.07.08) +## 1.0.0(2025.07.10) --- ### Initial diff --git a/multinavbarlibrary/Index.ets b/multinavbarlibrary/Index.ets index 7766b29..90f2e8c 100644 --- a/multinavbarlibrary/Index.ets +++ b/multinavbarlibrary/Index.ets @@ -1,3 +1,3 @@ -export { MultiNavBarPage } from './src/main/ets/pages/MultiNavBarPage'; +export { MultiNavBarComponent } from './src/main/ets/component/MultiNavBarComponent'; -export { WindowUtil } from './src/main/ets/common/utils/WindowUtils'; \ No newline at end of file +export { NavBarController } from './src/main/ets/NavBarController'; \ No newline at end of file diff --git a/multinavbarlibrary/README.md b/multinavbarlibrary/README.md index 4d72e76..c692771 100644 --- a/multinavbarlibrary/README.md +++ b/multinavbarlibrary/README.md @@ -25,18 +25,18 @@ ohpm install @ohos_samples/multinavbarlibrary ### 使用说明 ``` -import { MultiNavBarPage, WindowUtil } from '@ohos_samples/multinavbarlibrary'; +import { MultiNavBarComponent, NavBarController } from '@ohos_samples/multinavbarlibrary'; ``` -按需在文件中使用导出模块即可,其中MultiNavBarPage是整个sample的入口页面。WindowUtil封装了沉浸式、设备断点判断、避让区域计算等窗口能力。示例如下: +按需在文件中使用导出模块即可,其中MultiNavBarComponent是整个sample的入口页面组件。NavBarController封装了沉浸式、设备断点判断、避让区域计算等窗口能力。示例如下: ``` // Page.ets -import { MultiNavBarPage } from '@ohos_samples/multinavbarlibrary'; +import { MultiNavBarComponent } from '@ohos_samples/multinavbarlibrary'; Stack() { - MultiNavBarPage() + MultiNavBarComponent() } // EntryAbility.ets -import { WindowUtil } from '@ohos_samples/multinavbarlibrary'; -WindowUtil.requestFullScreen(windowStage); -WindowUtil.registerBreakPoint(windowStage); +import { NavBarController } from '@ohos_samples/multinavbarlibrary'; +// onWindowStageCreate回调里的loadContent方法里初始化 +NavBarController.initWindowConfig(windowStage); ``` \ No newline at end of file diff --git a/multinavbarlibrary/src/main/ets/NavBarController.ets b/multinavbarlibrary/src/main/ets/NavBarController.ets new file mode 100644 index 0000000..0edf723 --- /dev/null +++ b/multinavbarlibrary/src/main/ets/NavBarController.ets @@ -0,0 +1,22 @@ +/* + * Copyright (c) 2024 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +import { window } from '@kit.ArkUI'; +import { WindowUtil } from './common/utils/WindowUtils'; + +export class NavBarController { + public static initWindowConfig(windowStage: window.WindowStage): void { + WindowUtil.initialize(windowStage); + } +} \ No newline at end of file diff --git a/multinavbarlibrary/src/main/ets/common/Constants.ets b/multinavbarlibrary/src/main/ets/common/Constants.ets new file mode 100644 index 0000000..6e901bf --- /dev/null +++ b/multinavbarlibrary/src/main/ets/common/Constants.ets @@ -0,0 +1,27 @@ +/* + * Copyright (c) 2025 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * Common constants for all features. + */ +export class Constants { + /** + * AppStorage key + */ + public static readonly KEY_PREFIX: string = 'navBar'; + public static readonly KEY_BREAKPOINT: string = Constants.KEY_PREFIX + 'Breakpoint'; + public static readonly KEY_TOP_RECT_HEIGHT: string = Constants.KEY_PREFIX + 'TopRectHeight'; + public static readonly KEY_BOTTOM_RECT_HEIGHT: string = Constants.KEY_PREFIX + 'BottomRectHeight'; + public static readonly KEY_UI_CONTEXT: string = Constants.KEY_PREFIX + 'UIContext'; +} \ No newline at end of file diff --git a/multinavbarlibrary/src/main/ets/common/utils/BreakpointSystem.ets b/multinavbarlibrary/src/main/ets/common/utils/BreakpointSystem.ets index 8280dc0..75e6e95 100644 --- a/multinavbarlibrary/src/main/ets/common/utils/BreakpointSystem.ets +++ b/multinavbarlibrary/src/main/ets/common/utils/BreakpointSystem.ets @@ -16,6 +16,7 @@ import { window } from '@kit.ArkUI'; import type { BusinessError } from '@kit.BasicServicesKit'; import { hilog } from '@kit.PerformanceAnalysisKit'; +import { Constants } from '../Constants'; const TAG: string = '[BreakpointSystem]'; @@ -77,7 +78,7 @@ export class BreakpointSystem { public static getInstance(): BreakpointSystem { if (!BreakpointSystem.instance) { BreakpointSystem.instance = new BreakpointSystem(); - AppStorage.setOrCreate('navBarBreakpoint', BreakpointTypeEnum.MD); + AppStorage.setOrCreate(Constants.KEY_BREAKPOINT, BreakpointTypeEnum.MD); } return BreakpointSystem.instance; } @@ -85,7 +86,7 @@ export class BreakpointSystem { public updateCurrentBreakpoint(breakpoint: BreakpointTypeEnum): void { if (this.currentBreakpoint !== breakpoint) { this.currentBreakpoint = breakpoint; - AppStorage.setOrCreate('navBarBreakpoint', this.currentBreakpoint); + AppStorage.setOrCreate(Constants.KEY_BREAKPOINT, this.currentBreakpoint); } } @@ -97,7 +98,7 @@ export class BreakpointSystem { try { const mainWindow: window.WindowProperties = window.getWindowProperties(); const windowWidth: number = mainWindow.windowRect.width; - const windowWidthVp = px2vp(windowWidth); + const windowWidthVp = window.getUIContext().px2vp(windowWidth); let widthBp: BreakpointTypeEnum = BreakpointTypeEnum.MD; if (windowWidthVp < 320) { widthBp = BreakpointTypeEnum.XS; diff --git a/multinavbarlibrary/src/main/ets/common/utils/WindowUtils.ets b/multinavbarlibrary/src/main/ets/common/utils/WindowUtils.ets index 1869972..69d34c1 100644 --- a/multinavbarlibrary/src/main/ets/common/utils/WindowUtils.ets +++ b/multinavbarlibrary/src/main/ets/common/utils/WindowUtils.ets @@ -16,11 +16,24 @@ import { window } from '@kit.ArkUI'; import { BusinessError, deviceInfo } from '@kit.BasicServicesKit'; import { hilog } from '@kit.PerformanceAnalysisKit'; +import { Constants } from '../Constants'; import { BreakpointSystem } from './BreakpointSystem'; const TAG: string = '[WindowUtil]'; export class WindowUtil { + public static initialize(windowStage: window.WindowStage) { + try { + const uiContext: UIContext = windowStage.getMainWindowSync().getUIContext(); + AppStorage.setOrCreate(Constants.KEY_UI_CONTEXT, uiContext); + WindowUtil.requestFullScreen(windowStage); + WindowUtil.registerBreakPoint(windowStage); + } catch (err) { + const error = err as BusinessError; + hilog.error(0x0000, TAG, `Initialize failed. Cause code: ${error.code}, message: ${error.message}`); + } + } + public static requestFullScreen(windowStage: window.WindowStage): void { windowStage.getMainWindow((err: BusinessError, data: window.Window) => { if (err.code) { @@ -53,8 +66,8 @@ export class WindowUtil { const systemAvoidArea: window.AvoidArea = data.getWindowAvoidArea(window.AvoidAreaType.TYPE_SYSTEM); const navIndicatorAvoidArea: window.AvoidArea = data.getWindowAvoidArea(window.AvoidAreaType.TYPE_NAVIGATION_INDICATOR); - WindowUtil.setAvoidArea(window.AvoidAreaType.TYPE_SYSTEM, systemAvoidArea); - WindowUtil.setAvoidArea(window.AvoidAreaType.TYPE_NAVIGATION_INDICATOR, navIndicatorAvoidArea); + WindowUtil.setAvoidArea(data, window.AvoidAreaType.TYPE_SYSTEM, systemAvoidArea); + WindowUtil.setAvoidArea(data, window.AvoidAreaType.TYPE_NAVIGATION_INDICATOR, navIndicatorAvoidArea); data.on('windowSizeChange', () => BreakpointSystem.getInstance().onWindowSizeChange(data)); if (deviceInfo.deviceType === '2in1' && canIUse('SystemCapability.Window.SessionManager')) { data.setWindowDecorVisible(false); @@ -64,7 +77,7 @@ export class WindowUtil { data.on('avoidAreaChange', (avoidAreaOption) => { if (avoidAreaOption.type === window.AvoidAreaType.TYPE_SYSTEM || avoidAreaOption.type === window.AvoidAreaType.TYPE_NAVIGATION_INDICATOR) { - WindowUtil.setAvoidArea(avoidAreaOption.type, avoidAreaOption.area); + WindowUtil.setAvoidArea(data, avoidAreaOption.type, avoidAreaOption.area); } }); } @@ -77,11 +90,12 @@ export class WindowUtil { } // Get status bar height and indicator height. - public static setAvoidArea(type: window.AvoidAreaType, area: window.AvoidArea) { + public static setAvoidArea(data: window.Window, type: window.AvoidAreaType, area: window.AvoidArea) { + const context: UIContext = data.getUIContext(); if (type === window.AvoidAreaType.TYPE_SYSTEM) { - AppStorage.setOrCreate('navBarStatusBarHeight', px2vp(area.topRect.height)); + AppStorage.setOrCreate(Constants.KEY_TOP_RECT_HEIGHT, context.px2vp(area.topRect.height)); } else { - AppStorage.setOrCreate('navBarNaviIndicatorHeight', px2vp(area.bottomRect.height)); + AppStorage.setOrCreate(Constants.KEY_BOTTOM_RECT_HEIGHT, context.px2vp(area.bottomRect.height)); } } } \ No newline at end of file diff --git a/multinavbarlibrary/src/main/ets/pages/MultiNavBarPage.ets b/multinavbarlibrary/src/main/ets/component/MultiNavBarComponent.ets similarity index 79% rename from multinavbarlibrary/src/main/ets/pages/MultiNavBarPage.ets rename to multinavbarlibrary/src/main/ets/component/MultiNavBarComponent.ets index 4aa9051..d28ac8b 100644 --- a/multinavbarlibrary/src/main/ets/pages/MultiNavBarPage.ets +++ b/multinavbarlibrary/src/main/ets/component/MultiNavBarComponent.ets @@ -1,8 +1,7 @@ import { Home } from "../view/Home"; @Component -export struct MultiNavBarPage { - +export struct MultiNavBarComponent { build() { Column() { Home() diff --git a/multinavbarlibrary/src/main/ets/view/Home.ets b/multinavbarlibrary/src/main/ets/view/Home.ets index 7a6ef30..9e6e0fa 100644 --- a/multinavbarlibrary/src/main/ets/view/Home.ets +++ b/multinavbarlibrary/src/main/ets/view/Home.ets @@ -13,6 +13,7 @@ * limitations under the License. */ +import { Constants } from '../common/Constants'; import { TabDataModel } from '../model/TabDataModel'; import { TabViewModel } from '../viewmodel/TabViewModel'; import { SideBarView } from './SideBarView'; @@ -21,7 +22,7 @@ import { VideoInfoView } from './VideoInfoView'; @Component export struct Home { - @StorageLink('navBarBreakpoint') currentWidthBreakpoint: string = 'sm'; + @StorageLink(Constants.KEY_BREAKPOINT) currentWidthBreakpoint: string = 'sm'; @State firstLevelIndex: number = 0; @State secondLevelIndex: number = 0; @State tabViewModel: TabViewModel = new TabViewModel(); diff --git a/multinavbarlibrary/src/main/ets/view/TopTabView.ets b/multinavbarlibrary/src/main/ets/view/TopTabView.ets index d0a8993..f305af5 100644 --- a/multinavbarlibrary/src/main/ets/view/TopTabView.ets +++ b/multinavbarlibrary/src/main/ets/view/TopTabView.ets @@ -18,20 +18,22 @@ import { TabDataModel } from '../model/TabDataModel'; import { VideoInfoView } from './VideoInfoView'; import { hilog } from '@kit.PerformanceAnalysisKit'; import { BusinessError } from '@kit.BasicServicesKit'; +import { Constants } from '../common/Constants'; const TAG: string = '[TopTabView]'; @Component export struct TopTabView { - @StorageLink('navBarBreakpoint') currentWidthBreakpoint: string = 'sm'; + @StorageLink(Constants.KEY_BREAKPOINT) currentWidthBreakpoint: string = 'sm'; @State secondLevelIndex: number = 0; - @State statusBarHeight: number = AppStorage.get('navBarStatusBarHeight')!; + @State statusBarHeight: number = AppStorage.get(Constants.KEY_TOP_RECT_HEIGHT)!; @Link tabData: TabDataModel; private firstLevel: string = ''; aboutToAppear(): void { try { - this.firstLevel = getContext(this).resourceManager.getStringSync($r('app.string.tab_home').id) + this.firstLevel = + this.getUIContext().getHostContext()!.resourceManager.getStringSync($r('app.string.tab_home').id); } catch (error) { hilog.error(0x0000, TAG, 'Get string by resourceManager failed. Cause: ' + (error as BusinessError).message); } diff --git a/multinavbarlibrary/src/main/ets/view/VideoInfoView.ets b/multinavbarlibrary/src/main/ets/view/VideoInfoView.ets index 27f1324..ba05131 100644 --- a/multinavbarlibrary/src/main/ets/view/VideoInfoView.ets +++ b/multinavbarlibrary/src/main/ets/view/VideoInfoView.ets @@ -13,12 +13,13 @@ * limitations under the License. */ +import { Constants } from '../common/Constants'; import { BreakpointType } from '../common/utils/BreakpointSystem'; import { VideoViewModel } from '../viewmodel/VideoViewModel'; @Component export struct VideoInfoView { - @StorageLink('navBarBreakpoint') currentWidthBreakpoint: string = 'sm'; + @StorageLink(Constants.KEY_BREAKPOINT) currentWidthBreakpoint: string = 'sm'; @Link secondLevelIndex: number; private videoViewModel = new VideoViewModel(); private iteration: number[] = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16]; diff --git a/multinavbarlibrary/src/main/ets/viewmodel/TabViewModel.ets b/multinavbarlibrary/src/main/ets/viewmodel/TabViewModel.ets index 7c378a8..712bad2 100644 --- a/multinavbarlibrary/src/main/ets/viewmodel/TabViewModel.ets +++ b/multinavbarlibrary/src/main/ets/viewmodel/TabViewModel.ets @@ -13,6 +13,7 @@ * limitations under the License. */ +import { Constants } from '../common/Constants'; import { TabDataModel } from '../model/TabDataModel'; export class TabViewModel { @@ -20,13 +21,14 @@ export class TabViewModel { constructor() { let tabMap: Map = new Map(); - tabMap.set(getContext(this).resourceManager.getStringSync($r('app.string.tab_home').id), + const context: UIContext = AppStorage.get(Constants.KEY_UI_CONTEXT) as UIContext; + tabMap.set(context.getHostContext()!.resourceManager.getStringSync($r('app.string.tab_home').id), [$r('app.string.selected'), $r('app.string.video'), $r('app.string.community'), $r('app.string.news')]); - tabMap.set(getContext(this).resourceManager.getStringSync($r('app.string.tab_moments').id), + tabMap.set(context.getHostContext()!.resourceManager.getStringSync($r('app.string.tab_moments').id), [$r('app.string.selected'), $r('app.string.video'), $r('app.string.community'), $r('app.string.news')]); - tabMap.set(getContext(this).resourceManager.getStringSync($r('app.string.tab_shopping').id), + tabMap.set(context.getHostContext()!.resourceManager.getStringSync($r('app.string.tab_shopping').id), [$r('app.string.selected'), $r('app.string.video'), $r('app.string.community'), $r('app.string.news')]); - tabMap.set(getContext(this).resourceManager.getStringSync($r('app.string.tab_me').id), + tabMap.set(context.getHostContext()!.resourceManager.getStringSync($r('app.string.tab_me').id), [$r('app.string.selected'), $r('app.string.video'), $r('app.string.community'), $r('app.string.news')]); this.tabMap = new TabDataModel(tabMap); } diff --git a/multinavbarsample/oh-package.json5 b/multinavbarsample/oh-package.json5 index 82c2342..864b68a 100644 --- a/multinavbarsample/oh-package.json5 +++ b/multinavbarsample/oh-package.json5 @@ -6,6 +6,6 @@ "author": "", "license": "", "dependencies": { - "multinavbarlibrary": "file:../multinavbarlibrary" + "@ohos_samples/multinavbarlibrary": "file:../multinavbarlibrary" } } \ No newline at end of file diff --git a/multinavbarsample/src/main/ets/entryability/EntryAbility.ets b/multinavbarsample/src/main/ets/entryability/EntryAbility.ets index 581570c..bb56195 100644 --- a/multinavbarsample/src/main/ets/entryability/EntryAbility.ets +++ b/multinavbarsample/src/main/ets/entryability/EntryAbility.ets @@ -13,18 +13,17 @@ * limitations under the License. */ -import { ConfigurationConstant, UIAbility } from '@kit.AbilityKit'; +import { UIAbility } from '@kit.AbilityKit'; import { window } from '@kit.ArkUI'; import { BusinessError } from '@kit.BasicServicesKit'; import { hilog } from '@kit.PerformanceAnalysisKit'; -import { WindowUtil } from 'multinavbarlibrary/src/main/ets/common/utils/WindowUtils'; +import { NavBarController } from '@ohos_samples/multinavbarlibrary'; const TAG: string = '[EntryAbility]'; export default class EntryAbility extends UIAbility { onCreate(): void { hilog.info(0x0000, TAG, 'Ability onCreate'); - this.context.getApplicationContext().setColorMode(ConfigurationConstant.ColorMode.COLOR_MODE_NOT_SET); } onWindowStageCreate(windowStage: window.WindowStage): void { @@ -34,8 +33,8 @@ export default class EntryAbility extends UIAbility { hilog.error(0x0000, TAG, `Failed to load the content. Cause: ${err.message}`); return; } + NavBarController.initWindowConfig(windowStage); hilog.info(0x0000, TAG, 'Succeeded in loading the content.'); }); - WindowUtil.registerBreakPoint(windowStage); } } \ No newline at end of file diff --git a/multinavbarsample/src/main/ets/pages/Index.ets b/multinavbarsample/src/main/ets/pages/Index.ets index 1d5e4ed..3872fe6 100644 --- a/multinavbarsample/src/main/ets/pages/Index.ets +++ b/multinavbarsample/src/main/ets/pages/Index.ets @@ -13,14 +13,14 @@ * limitations under the License. */ -import { MultiNavBarPage } from 'multinavbarlibrary'; +import { MultiNavBarComponent } from '@ohos_samples/multinavbarlibrary'; @Entry @Component struct Index { build() { Stack() { - MultiNavBarPage() + MultiNavBarComponent() } } } \ No newline at end of file -- Gitee From f125bc87152e5ca14647104eb2dddae72205ed6f Mon Sep 17 00:00:00 2001 From: EasyGuohf <163991322+EasyGuohf@users.noreply.github.com> Date: Thu, 10 Jul 2025 18:46:33 +0800 Subject: [PATCH 6/8] =?UTF-8?q?readme=E4=BF=AE=E6=94=B9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index 849c207..e0b9333 100644 --- a/README.md +++ b/README.md @@ -23,10 +23,10 @@ ``` multinavbarlibrary -├──src/main/ets // 代码区 +├──src/main/ets // 代码区 │ ├──common │ │ ├──utils -│ │ │ ├──BreakpointType.ets // 断点工具类 +│ │ │ ├──BreakpointSystem.ets // 断点工具类 │ │ │ └──WindowUtils.ets // 窗口工具类 │ │ └──Constants.ets │ ├──model @@ -43,14 +43,14 @@ multinavbarlibrary │ │ ├──TabViewModel.ets // 导航目录数据 │ │ └──VideoViewModel.ets // 内容区数据 │ └──NavBarController.ets -└──src/main/resources // 应用静态资源目录 +└──src/main/resources // 应用静态资源目录 multinavbarsample -├──src/main/ets // 代码区 +├──src/main/ets // 代码区 │ ├──entryability │ │ └──EntryAbility.ets │ └──pages -│ └──Index.ets // 入口页面 -└──src/main/resources // 应用资源目录 +│ └──Index.ets // 入口页面 +└──src/main/resources // 应用资源目录 ``` ### 具体实现 -- Gitee From 28c18814bde6b72d7d60b7d0aaa06988ce1fb594 Mon Sep 17 00:00:00 2001 From: EasyGuohf <163991322+EasyGuohf@users.noreply.github.com> Date: Wed, 16 Jul 2025 17:52:17 +0800 Subject: [PATCH 7/8] =?UTF-8?q?=E8=B5=84=E6=BA=90=E5=8F=8A=E8=A7=84?= =?UTF-8?q?=E8=8C=83=E6=95=B4=E6=94=B9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- multinavbarlibrary/README.md | 2 +- multinavbarlibrary/build-profile.json5 | 2 +- .../src/main/ets/common/Constants.ets | 14 ++- .../src/main/ets/common/utils/WindowUtils.ets | 99 ++++++++---------- .../ets/component/MultiNavBarComponent.ets | 16 ++- multinavbarlibrary/src/main/ets/view/Home.ets | 43 ++++---- .../src/main/ets/view/SideBarView.ets | 48 +++++---- .../src/main/ets/view/TopTabView.ets | 42 ++++---- .../src/main/ets/view/VideoInfoView.ets | 66 ++++++------ .../main/resources/base/element/color.json | 12 ++- .../main/resources/base/element/float.json | 56 ++++++++++ .../main/resources/base/element/string.json | 10 +- .../main/resources/en_US/element/string.json | 10 +- .../main/resources/zh_CN/element/string.json | 10 +- .../main/ets/entryability/EntryAbility.ets | 3 +- multinavbarsample/src/main/module.json5 | 2 +- .../main/resources/base/element/color.json | 8 ++ .../main/resources/base/element/string.json | 16 +++ .../main/resources/base/media/background.png | Bin .../main/resources/base/media/foreground.png | Bin .../resources/base/media/layered_image.json | 0 .../main/resources/base/media/startIcon.png | Bin 0 -> 20093 bytes .../main/resources/en_US/element/string.json | 16 +++ .../main/resources/zh_CN/element/string.json | 16 +++ 24 files changed, 298 insertions(+), 193 deletions(-) create mode 100644 multinavbarlibrary/src/main/resources/base/element/float.json create mode 100644 multinavbarsample/src/main/resources/base/element/color.json create mode 100644 multinavbarsample/src/main/resources/base/element/string.json rename {multinavbarlibrary => multinavbarsample}/src/main/resources/base/media/background.png (100%) rename {multinavbarlibrary => multinavbarsample}/src/main/resources/base/media/foreground.png (100%) rename {multinavbarlibrary => multinavbarsample}/src/main/resources/base/media/layered_image.json (100%) create mode 100644 multinavbarsample/src/main/resources/base/media/startIcon.png create mode 100644 multinavbarsample/src/main/resources/en_US/element/string.json create mode 100644 multinavbarsample/src/main/resources/zh_CN/element/string.json diff --git a/multinavbarlibrary/README.md b/multinavbarlibrary/README.md index c692771..3cdb8da 100644 --- a/multinavbarlibrary/README.md +++ b/multinavbarlibrary/README.md @@ -29,7 +29,7 @@ import { MultiNavBarComponent, NavBarController } from '@ohos_samples/multinavba ``` 按需在文件中使用导出模块即可,其中MultiNavBarComponent是整个sample的入口页面组件。NavBarController封装了沉浸式、设备断点判断、避让区域计算等窗口能力。示例如下: ``` -// Page.ets +// Index.ets import { MultiNavBarComponent } from '@ohos_samples/multinavbarlibrary'; Stack() { MultiNavBarComponent() diff --git a/multinavbarlibrary/build-profile.json5 b/multinavbarlibrary/build-profile.json5 index 312d38e..cda3307 100644 --- a/multinavbarlibrary/build-profile.json5 +++ b/multinavbarlibrary/build-profile.json5 @@ -8,7 +8,7 @@ "arkOptions": { "obfuscation": { "ruleOptions": { - "enable": true, + "enable": false, "files": [ "./obfuscation-rules.txt" ] diff --git a/multinavbarlibrary/src/main/ets/common/Constants.ets b/multinavbarlibrary/src/main/ets/common/Constants.ets index 6e901bf..775c7bb 100644 --- a/multinavbarlibrary/src/main/ets/common/Constants.ets +++ b/multinavbarlibrary/src/main/ets/common/Constants.ets @@ -12,16 +12,20 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -/** + +/* * Common constants for all features. */ export class Constants { - /** + public static readonly SPACE_2: number = 2; + public static readonly SPACE_8: number = 8; + public static readonly WINDOW_DECOR_HEIGHT: number = 64; + /* * AppStorage key */ - public static readonly KEY_PREFIX: string = 'navBar'; + public static readonly KEY_PREFIX: string = 'multiNavBar'; public static readonly KEY_BREAKPOINT: string = Constants.KEY_PREFIX + 'Breakpoint'; - public static readonly KEY_TOP_RECT_HEIGHT: string = Constants.KEY_PREFIX + 'TopRectHeight'; - public static readonly KEY_BOTTOM_RECT_HEIGHT: string = Constants.KEY_PREFIX + 'BottomRectHeight'; + public static readonly KEY_STATUS_BAR_HEIGHT: string = Constants.KEY_PREFIX + 'StatusBarHeight'; + public static readonly KEY_NAV_INDICATOR_HEIGHT: string = Constants.KEY_PREFIX + 'NavIndicatorHeight'; public static readonly KEY_UI_CONTEXT: string = Constants.KEY_PREFIX + 'UIContext'; } \ No newline at end of file diff --git a/multinavbarlibrary/src/main/ets/common/utils/WindowUtils.ets b/multinavbarlibrary/src/main/ets/common/utils/WindowUtils.ets index 69d34c1..3da1091 100644 --- a/multinavbarlibrary/src/main/ets/common/utils/WindowUtils.ets +++ b/multinavbarlibrary/src/main/ets/common/utils/WindowUtils.ets @@ -22,80 +22,67 @@ import { BreakpointSystem } from './BreakpointSystem'; const TAG: string = '[WindowUtil]'; export class WindowUtil { + private static windowClass: window.Window; + public static initialize(windowStage: window.WindowStage) { try { - const uiContext: UIContext = windowStage.getMainWindowSync().getUIContext(); + WindowUtil.windowClass = windowStage.getMainWindowSync(); + const uiContext: UIContext = WindowUtil.windowClass.getUIContext(); AppStorage.setOrCreate(Constants.KEY_UI_CONTEXT, uiContext); - WindowUtil.requestFullScreen(windowStage); - WindowUtil.registerBreakPoint(windowStage); + WindowUtil.registerBreakPoint(WindowUtil.windowClass); } catch (err) { const error = err as BusinessError; hilog.error(0x0000, TAG, `Initialize failed. Cause code: ${error.code}, message: ${error.message}`); } } - public static requestFullScreen(windowStage: window.WindowStage): void { - windowStage.getMainWindow((err: BusinessError, data: window.Window) => { - if (err.code) { - return; - } - const windowClass: window.Window = data; - // Realize the immersive effect. - try { - const promise: Promise = windowClass.setWindowLayoutFullScreen(true); - promise.then(() => { - hilog.info(0x0000, TAG, 'Succeeded in setting the window layout to full-screen mode.'); - }).catch((err: BusinessError) => { - hilog.info(0x0000, TAG, - `Failed to set the window layout to full-screen mode. Cause: ${err.code}, ${err.message}`); - }); - } catch { - hilog.error(0x0000, TAG, 'Failed to set the window layout to full-screen mode. '); - } - }); + public static requestFullScreen(windowClass: window.Window): void { + // Realize the immersive effect. + try { + const promise: Promise = windowClass.setWindowLayoutFullScreen(true); + promise.then(() => { + hilog.info(0x0000, TAG, 'Succeeded in setting the window layout to full-screen mode.'); + }).catch((err: BusinessError) => { + hilog.error(0x0000, TAG, + `Failed to set the window layout to full-screen mode. Cause: ${err.code}, ${err.message}`); + }); + } catch { + hilog.error(0x0000, TAG, 'Failed to set the window layout to full-screen mode. '); + } } - public static registerBreakPoint(windowStage: window.WindowStage) { - windowStage.getMainWindow((err: BusinessError, data: window.Window) => { - if (err.code) { - hilog.error(0x0000, TAG, `Failed to get main window: ${err.message}`); - return; - } - try { - BreakpointSystem.getInstance().updateWidthBp(data); - const systemAvoidArea: window.AvoidArea = data.getWindowAvoidArea(window.AvoidAreaType.TYPE_SYSTEM); - const navIndicatorAvoidArea: window.AvoidArea = - data.getWindowAvoidArea(window.AvoidAreaType.TYPE_NAVIGATION_INDICATOR); - WindowUtil.setAvoidArea(data, window.AvoidAreaType.TYPE_SYSTEM, systemAvoidArea); - WindowUtil.setAvoidArea(data, window.AvoidAreaType.TYPE_NAVIGATION_INDICATOR, navIndicatorAvoidArea); - data.on('windowSizeChange', () => BreakpointSystem.getInstance().onWindowSizeChange(data)); - if (deviceInfo.deviceType === '2in1' && canIUse('SystemCapability.Window.SessionManager')) { - data.setWindowDecorVisible(false); - data.setWindowDecorHeight(64); - } else { - WindowUtil.requestFullScreen(windowStage) - data.on('avoidAreaChange', (avoidAreaOption) => { - if (avoidAreaOption.type === window.AvoidAreaType.TYPE_SYSTEM || - avoidAreaOption.type === window.AvoidAreaType.TYPE_NAVIGATION_INDICATOR) { - WindowUtil.setAvoidArea(data, avoidAreaOption.type, avoidAreaOption.area); - } - }); - } - } catch (error) { - const err: BusinessError = error as BusinessError; - hilog.error(0x0000, TAG, - `Failed to set the window decor or get the WindowAvoidArea. Cause: ${err.code}, ${err.message}`); + public static registerBreakPoint(data: window.Window) { + try { + BreakpointSystem.getInstance().updateWidthBp(data); + const systemAvoidArea: window.AvoidArea = data.getWindowAvoidArea(window.AvoidAreaType.TYPE_SYSTEM); + const navIndicatorAvoidArea: window.AvoidArea = + data.getWindowAvoidArea(window.AvoidAreaType.TYPE_NAVIGATION_INDICATOR); + WindowUtil.setAvoidArea(data, window.AvoidAreaType.TYPE_SYSTEM, systemAvoidArea); + WindowUtil.setAvoidArea(data, window.AvoidAreaType.TYPE_NAVIGATION_INDICATOR, navIndicatorAvoidArea); + data.on('windowSizeChange', () => BreakpointSystem.getInstance().onWindowSizeChange(data)); + if (deviceInfo.deviceType === '2in1' && canIUse('SystemCapability.Window.SessionManager')) { + data.setWindowDecorVisible(false); + data.setWindowDecorHeight(Constants.WINDOW_DECOR_HEIGHT); + } else { + WindowUtil.requestFullScreen(data); } - }) + data.on('avoidAreaChange', (avoidAreaOption) => { + WindowUtil.setAvoidArea(data, avoidAreaOption.type, avoidAreaOption.area); + }); + } catch (error) { + const err: BusinessError = error as BusinessError; + hilog.error(0x0000, TAG, + `Failed to set the window decor or get the WindowAvoidArea. Cause: ${err.code}, ${err.message}`); + } } // Get status bar height and indicator height. public static setAvoidArea(data: window.Window, type: window.AvoidAreaType, area: window.AvoidArea) { const context: UIContext = data.getUIContext(); if (type === window.AvoidAreaType.TYPE_SYSTEM) { - AppStorage.setOrCreate(Constants.KEY_TOP_RECT_HEIGHT, context.px2vp(area.topRect.height)); - } else { - AppStorage.setOrCreate(Constants.KEY_BOTTOM_RECT_HEIGHT, context.px2vp(area.bottomRect.height)); + AppStorage.setOrCreate(Constants.KEY_STATUS_BAR_HEIGHT, context.px2vp(area.topRect.height)); + } else if (type === window.AvoidAreaType.TYPE_NAVIGATION_INDICATOR) { + AppStorage.setOrCreate(Constants.KEY_NAV_INDICATOR_HEIGHT, context.px2vp(area.bottomRect.height)); } } } \ No newline at end of file diff --git a/multinavbarlibrary/src/main/ets/component/MultiNavBarComponent.ets b/multinavbarlibrary/src/main/ets/component/MultiNavBarComponent.ets index d28ac8b..42891f3 100644 --- a/multinavbarlibrary/src/main/ets/component/MultiNavBarComponent.ets +++ b/multinavbarlibrary/src/main/ets/component/MultiNavBarComponent.ets @@ -1,4 +1,18 @@ -import { Home } from "../view/Home"; +/* + * Copyright (c) 2025 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +import { Home } from '../view/Home'; @Component export struct MultiNavBarComponent { diff --git a/multinavbarlibrary/src/main/ets/view/Home.ets b/multinavbarlibrary/src/main/ets/view/Home.ets index 9e6e0fa..2adad6e 100644 --- a/multinavbarlibrary/src/main/ets/view/Home.ets +++ b/multinavbarlibrary/src/main/ets/view/Home.ets @@ -14,6 +14,7 @@ */ import { Constants } from '../common/Constants'; +import { BreakpointTypeEnum } from '../common/utils/BreakpointSystem'; import { TabDataModel } from '../model/TabDataModel'; import { TabViewModel } from '../viewmodel/TabViewModel'; import { SideBarView } from './SideBarView'; @@ -22,7 +23,7 @@ import { VideoInfoView } from './VideoInfoView'; @Component export struct Home { - @StorageLink(Constants.KEY_BREAKPOINT) currentWidthBreakpoint: string = 'sm'; + @StorageLink(Constants.KEY_BREAKPOINT) currentWidthBreakpoint: string = BreakpointTypeEnum.SM; @State firstLevelIndex: number = 0; @State secondLevelIndex: number = 0; @State tabViewModel: TabViewModel = new TabViewModel(); @@ -32,22 +33,22 @@ export struct Home { tabBuilder(name: Resource, index: number) { Column() { SymbolGlyph($r('sys.symbol.person_crop_circle_fill_1')) - .fontSize(24) + .fontSize($r('sys.float.Title_M')) .fontColor(index === this.firstLevelIndex ? [$r('sys.color.font_emphasize')] : [$r('sys.color.font_secondary')]) Text(name) - .fontSize(10) - .fontWeight(500) + .fontSize($r('sys.float.Caption_M')) + .fontWeight(FontWeight.Medium) .fontColor(index === this.firstLevelIndex ? $r('sys.color.font_emphasize') : $r('sys.color.font_secondary')) - .margin({ top: 4 }) + .margin({ top: $r('sys.float.padding_level2') }) } - .padding({ bottom: 24 }) - .height(this.currentWidthBreakpoint === 'lg' ? 100 : '100%') + .padding({ bottom: $r('sys.float.padding_level12') }) + .height(this.currentWidthBreakpoint === BreakpointTypeEnum.LG ? $r('app.float.top_tab_button_height') : '100%') .width('100%') .justifyContent(FlexAlign.Center) } build() { - if (this.currentWidthBreakpoint === 'xl') { + if (this.currentWidthBreakpoint === BreakpointTypeEnum.XL) { // Use SideBarContainer at XL breakpoint. SideBarContainer(SideBarContainerType.Embed) { SideBarView({ @@ -59,12 +60,12 @@ export struct Home { Column() { Text(this.tabViewModel.getTabNameOfSecondLevel(this.tabViewModel.getTabNameOfFirstLevel(this.firstLevelIndex), this.secondLevelIndex)) - .fontSize('20fp') - .fontWeight(700) + .fontSize($r('sys.float.Title_S')) + .fontWeight(FontWeight.Bold) .margin({ - left: 32, - top: 71, - bottom: 14 + left: $r('sys.float.padding_level16'), + top: $r('sys.float.padding_level36'), + bottom: $r('sys.float.padding_level7') }) VideoInfoView({ secondLevelIndex: this.secondLevelIndex @@ -75,13 +76,13 @@ export struct Home { .autoHide(false) .divider({ strokeWidth: 0.3 }) .showControlButton(false) - .sideBarWidth(240) - .minSideBarWidth(240) - .maxSideBarWidth(240) + .sideBarWidth($r('app.float.side_bar_width')) + .minSideBarWidth($r('app.float.side_bar_width')) + .maxSideBarWidth($r('app.float.side_bar_width')) } else { // Use Tabs and List at other breakpoints. Tabs({ - barPosition: this.currentWidthBreakpoint === 'lg' ? BarPosition.Start : BarPosition.End + barPosition: this.currentWidthBreakpoint === BreakpointTypeEnum.LG ? BarPosition.Start : BarPosition.End }) { TabContent() { TopTabView({ tabData: this.tabData }) @@ -104,11 +105,11 @@ export struct Home { .tabBar(this.tabBuilder($r('app.string.tab_me'), 3)) } .barBackgroundColor($r('sys.color.background_secondary')) - .barWidth(this.currentWidthBreakpoint === 'lg' ? 96 : '100%') - .barHeight(this.currentWidthBreakpoint === 'lg' ? '100%' : 76) - .barMode(this.currentWidthBreakpoint === 'lg' ? BarMode.Scrollable : BarMode.Fixed, + .barWidth(this.currentWidthBreakpoint === BreakpointTypeEnum.LG ? $r('app.float.tab_bar_width') : '100%') + .barHeight(this.currentWidthBreakpoint === BreakpointTypeEnum.LG ? '100%' : $r('app.float.tab_bar_height')) + .barMode(this.currentWidthBreakpoint === BreakpointTypeEnum.LG ? BarMode.Scrollable : BarMode.Fixed, { nonScrollableLayoutStyle: LayoutStyle.ALWAYS_CENTER }) - .vertical(this.currentWidthBreakpoint === 'lg') + .vertical(this.currentWidthBreakpoint === BreakpointTypeEnum.LG) .barBackgroundBlurStyle(BlurStyle.COMPONENT_THICK) .onChange((index: number) => { this.firstLevelIndex = index; diff --git a/multinavbarlibrary/src/main/ets/view/SideBarView.ets b/multinavbarlibrary/src/main/ets/view/SideBarView.ets index 3ecc161..46579a2 100644 --- a/multinavbarlibrary/src/main/ets/view/SideBarView.ets +++ b/multinavbarlibrary/src/main/ets/view/SideBarView.ets @@ -13,6 +13,7 @@ * limitations under the License. */ +import { Constants } from '../common/Constants'; import { TabDataModel } from '../model/TabDataModel'; @Component @@ -24,56 +25,57 @@ export struct SideBarView { build() { Column() { - Row({ space: 8 }) { + Row({ space: Constants.SPACE_8 }) { Image($r('app.media.startIcon')) - .height(24) - Text($r('app.string.EntryAbility_label')) - .fontSize('16fp') + .height($r('app.float.size_24')) + Text($r('app.string.project_name')) + .fontSize($r('sys.float.Body_L')) .fontWeight(FontWeight.Medium) } - .padding({ left: 8 }) - .height(56) + .padding({ left: $r('sys.float.padding_level4') }) + .height($r('app.float.size_56')) - Column({ space: 2 }) { + Column({ space: Constants.SPACE_2 }) { ForEach(this.tabData.getFirstList(), (item: string, index: number) => { Column() { Row() { - Row({ space: 8 }) { + Row({ space: Constants.SPACE_8 }) { SymbolGlyph($r('sys.symbol.person_crop_circle_fill_1')) - .fontSize(24) + .fontSize($r('sys.float.Title_M')) .fontColor(index === this.firstLevelIndex ? [$r('sys.color.font_emphasize')] : [$r('sys.color.font_secondary')]) Text(item) - .fontSize('16fp') + .fontSize($r('sys.float.Body_L')) .fontWeight(index === this.firstLevelIndex ? FontWeight.Bold : FontWeight.Medium) } if (this.tabData.getSecondList(item).length > 0) { Image((index === this.firstLevelIndex && this.isShow) ? $r('app.media.chevron_up') : $r('app.media.arrow_down')) - .width(20) - .height(20) + .width($r('app.float.size_20')) + .height($r('app.float.size_20')) } } .justifyContent(FlexAlign.SpaceBetween) .width('100%') - .height(40) + .height($r('app.float.size_40')) .padding({ - left: 8 + left: $r('sys.float.padding_level2') }) - Column({ space: 2 }) { + Column({ space: Constants.SPACE_2 }) { ForEach(this.tabData.getSecondList(item), (item: string, index: number) => { Row() { Text(item) - .fontSize('16fp') + .fontSize($r('sys.float.Body_L')) .fontWeight(index === this.secondLevelIndex ? FontWeight.Bold : FontWeight.Medium) - .margin({ left: 40 }) + .margin({ left: $r('app.float.size_40') }) } .width('100%') - .height(40) - .borderRadius(8) - .backgroundColor(index === this.secondLevelIndex ? '#1A0A59F7' : '#00FFFFFF') + .height($r('app.float.size_40')) + .borderRadius($r('sys.float.corner_radius_level4')) + .backgroundColor(index === this.secondLevelIndex ? $r('app.color.tab_bar_color_normal') : + $r('app.color.tab_bar_color_selected')) .onClick(() => { this.secondLevelIndex = index; }) @@ -93,10 +95,10 @@ export struct SideBarView { .alignItems(HorizontalAlign.Start) } .alignItems(HorizontalAlign.Start) - .backgroundColor('#0D000000') + .backgroundColor($r('app.color.side_bar_backgroundColor')) .padding({ - left: 16, - right: 16 + left: $r('sys.float.padding_level8'), + right: $r('sys.float.padding_level8') }) .height('100%') .width('100%') diff --git a/multinavbarlibrary/src/main/ets/view/TopTabView.ets b/multinavbarlibrary/src/main/ets/view/TopTabView.ets index f305af5..fb2556e 100644 --- a/multinavbarlibrary/src/main/ets/view/TopTabView.ets +++ b/multinavbarlibrary/src/main/ets/view/TopTabView.ets @@ -13,20 +13,20 @@ * limitations under the License. */ -import { BreakpointType } from '../common/utils/BreakpointSystem'; -import { TabDataModel } from '../model/TabDataModel'; -import { VideoInfoView } from './VideoInfoView'; -import { hilog } from '@kit.PerformanceAnalysisKit'; import { BusinessError } from '@kit.BasicServicesKit'; +import { hilog } from '@kit.PerformanceAnalysisKit'; import { Constants } from '../common/Constants'; +import { BreakpointType, BreakpointTypeEnum } from '../common/utils/BreakpointSystem'; +import { TabDataModel } from '../model/TabDataModel'; +import { VideoInfoView } from './VideoInfoView'; const TAG: string = '[TopTabView]'; @Component export struct TopTabView { - @StorageLink(Constants.KEY_BREAKPOINT) currentWidthBreakpoint: string = 'sm'; + @StorageLink(Constants.KEY_BREAKPOINT) currentWidthBreakpoint: string = BreakpointTypeEnum.SM; @State secondLevelIndex: number = 0; - @State statusBarHeight: number = AppStorage.get(Constants.KEY_TOP_RECT_HEIGHT)!; + @State statusBarHeight: number = AppStorage.get(Constants.KEY_STATUS_BAR_HEIGHT)!; @Link tabData: TabDataModel; private firstLevel: string = ''; @@ -45,8 +45,8 @@ export struct TopTabView { ForEach(this.tabData.getSecondList(this.firstLevel), (item: string, index: number) => { ListItem() { Button(item) - .width(110) - .height(36) + .width($r('app.float.top_tab_button_width')) + .height($r('app.float.size_36')) .buttonStyle(index === this.secondLevelIndex ? ButtonStyleMode.EMPHASIZED : ButtonStyleMode.NORMAL) .fontSize($r('sys.float.Body_M')) .fontColor(index === this.secondLevelIndex ? $r('sys.color.font_on_primary') : @@ -56,10 +56,10 @@ export struct TopTabView { .align(Alignment.Center) .padding({ right: new BreakpointType({ - sm: 8, - md: 12, - lg: 18, - xl: 0 + sm: $r('sys.float.padding_level4'), + md: $r('sys.float.padding_level6'), + lg: $r('sys.float.padding_level9'), + xl: $r('sys.float.padding_level0') }).getValue(this.currentWidthBreakpoint) }) .onClick(() => { @@ -71,20 +71,20 @@ export struct TopTabView { .listDirection(Axis.Horizontal) .padding({ left: new BreakpointType({ - sm: 16, - md: 24, - lg: 36, - xl: 24 + sm: $r('sys.float.padding_level8'), + md: $r('sys.float.padding_level12'), + lg: $r('app.float.padding_level18'), + xl: $r('sys.float.padding_level12') }).getValue(this.currentWidthBreakpoint), right: new BreakpointType({ - sm: 16, - md: 24, - lg: 36, - xl: 24 + sm: $r('sys.float.padding_level8'), + md: $r('sys.float.padding_level12'), + lg: $r('app.float.padding_level18'), + xl: $r('sys.float.padding_level12') }).getValue(this.currentWidthBreakpoint), top: $r('sys.float.padding_level5') }) - .height(56) + .height($r('app.float.size_56')) .width('100%') VideoInfoView({ secondLevelIndex: this.secondLevelIndex }) diff --git a/multinavbarlibrary/src/main/ets/view/VideoInfoView.ets b/multinavbarlibrary/src/main/ets/view/VideoInfoView.ets index ba05131..0b45338 100644 --- a/multinavbarlibrary/src/main/ets/view/VideoInfoView.ets +++ b/multinavbarlibrary/src/main/ets/view/VideoInfoView.ets @@ -14,12 +14,12 @@ */ import { Constants } from '../common/Constants'; -import { BreakpointType } from '../common/utils/BreakpointSystem'; +import { BreakpointType, BreakpointTypeEnum } from '../common/utils/BreakpointSystem'; import { VideoViewModel } from '../viewmodel/VideoViewModel'; @Component export struct VideoInfoView { - @StorageLink(Constants.KEY_BREAKPOINT) currentWidthBreakpoint: string = 'sm'; + @StorageLink(Constants.KEY_BREAKPOINT) currentWidthBreakpoint: string = BreakpointTypeEnum.SM; @Link secondLevelIndex: number; private videoViewModel = new VideoViewModel(); private iteration: number[] = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16]; @@ -32,27 +32,27 @@ export struct VideoInfoView { Image(this.videoViewModel.getVideo(this.secondLevelIndex)) .objectFit(ImageFit.Fill) .width('100%') - .borderRadius(12) + .borderRadius($r('sys.float.corner_radius_level6')) Row() - .height(16) + .height($r('app.float.size_16')) .width('50%') - .borderRadius(12) + .borderRadius($r('sys.float.corner_radius_level6')) .backgroundColor($r('sys.color.ohos_id_color_click_effect')) .margin({ top: new BreakpointType({ - sm: 10, - md: 10, - lg: 12, - xl: 11 + sm: $r('sys.float.padding_level5'), + md: $r('sys.float.padding_level5'), + lg: $r('sys.float.padding_level6'), + xl: $r('sys.float.padding_level6') }).getValue(this.currentWidthBreakpoint), - bottom: 6 + bottom: $r('sys.float.padding_level3') }) Row() - .height(14) + .height($r('app.float.size_14')) .width('100%') - .borderRadius(12) + .borderRadius($r('sys.float.corner_radius_level6')) .backgroundColor($r('sys.color.ohos_id_color_hover')) } .width('100%') @@ -72,36 +72,36 @@ export struct VideoInfoView { .getValue(this.currentWidthBreakpoint)) .width('100%') .rowsGap(new BreakpointType({ - sm: 12, - md: 16, - lg: 16, - xl: 16 + sm: $r('sys.float.padding_level6'), + md: $r('sys.float.padding_level8'), + lg: $r('sys.float.padding_level8'), + xl: $r('sys.float.padding_level8') }).getValue(this.currentWidthBreakpoint)) .columnsGap(new BreakpointType({ - sm: 16, - md: 12, - lg: 16, - xl: 16 + sm: $r('sys.float.padding_level8'), + md: $r('sys.float.padding_level6'), + lg: $r('sys.float.padding_level8'), + xl: $r('sys.float.padding_level8'), }).getValue(this.currentWidthBreakpoint)) .padding({ left: new BreakpointType({ - sm: 16, - md: 24, - lg: 36, - xl: 24 + sm: $r('sys.float.padding_level8'), + md: $r('sys.float.padding_level12'), + lg: $r('app.float.padding_level18'), + xl: $r('sys.float.padding_level12') }).getValue(this.currentWidthBreakpoint), right: new BreakpointType({ - sm: 16, - md: 24, - lg: 36, - xl: 24 + sm: $r('sys.float.padding_level8'), + md: $r('sys.float.padding_level12'), + lg: $r('app.float.padding_level18'), + xl: $r('sys.float.padding_level12') }).getValue(this.currentWidthBreakpoint), - top: 12, + top: $r('sys.float.padding_level6'), bottom: new BreakpointType({ - sm: 6, - md: 6, - lg: 20, - xl: 20 + sm: $r('sys.float.padding_level3'), + md: $r('sys.float.padding_level3'), + lg: $r('sys.float.padding_level10'), + xl: $r('sys.float.padding_level10') }).getValue(this.currentWidthBreakpoint) }) } diff --git a/multinavbarlibrary/src/main/resources/base/element/color.json b/multinavbarlibrary/src/main/resources/base/element/color.json index 79b11c2..ebe9fb7 100644 --- a/multinavbarlibrary/src/main/resources/base/element/color.json +++ b/multinavbarlibrary/src/main/resources/base/element/color.json @@ -1,8 +1,16 @@ { "color": [ { - "name": "start_window_background", - "value": "#000000" + "name": "tab_bar_color_normal", + "value": "#00FFFFFF" + }, + { + "name": "tab_bar_color_selected", + "value": "#1A0A59F7" + }, + { + "name": "side_bar_backgroundColor", + "value": "#0D000000" } ] } \ No newline at end of file diff --git a/multinavbarlibrary/src/main/resources/base/element/float.json b/multinavbarlibrary/src/main/resources/base/element/float.json new file mode 100644 index 0000000..523360e --- /dev/null +++ b/multinavbarlibrary/src/main/resources/base/element/float.json @@ -0,0 +1,56 @@ +{ + "float": [ + { + "name": "padding_level18", + "value": "36vp" + }, + { + "name": "size_14", + "value": "14vp" + }, + { + "name": "size_16", + "value": "16vp" + }, + { + "name": "size_20", + "value": "20vp" + }, + { + "name": "size_24", + "value": "24vp" + }, + { + "name": "size_36", + "value": "36vp" + }, + { + "name": "size_40", + "value": "40vp" + }, + { + "name": "size_56", + "value": "56vp" + }, + { + "name": "top_tab_button_width", + "value": "110vp" + }, + { + "name": "top_tab_button_height", + "value": "100vp" + }, + { + "name": "side_bar_width", + "value": "240vp" + }, + { + "name": "tab_bar_width", + "value": "96vp" + }, + { + "name": "tab_bar_height", + "value": "76vp" + } + ] +} \ No newline at end of file diff --git a/multinavbarlibrary/src/main/resources/base/element/string.json b/multinavbarlibrary/src/main/resources/base/element/string.json index 9b439b3..c898828 100644 --- a/multinavbarlibrary/src/main/resources/base/element/string.json +++ b/multinavbarlibrary/src/main/resources/base/element/string.json @@ -1,15 +1,7 @@ { "string": [ { - "name": "module_desc", - "value": "module description" - }, - { - "name": "EntryAbility_desc", - "value": "description" - }, - { - "name": "EntryAbility_label", + "name": "project_name", "value": "MultiNavBar" }, { diff --git a/multinavbarlibrary/src/main/resources/en_US/element/string.json b/multinavbarlibrary/src/main/resources/en_US/element/string.json index 9b439b3..c898828 100644 --- a/multinavbarlibrary/src/main/resources/en_US/element/string.json +++ b/multinavbarlibrary/src/main/resources/en_US/element/string.json @@ -1,15 +1,7 @@ { "string": [ { - "name": "module_desc", - "value": "module description" - }, - { - "name": "EntryAbility_desc", - "value": "description" - }, - { - "name": "EntryAbility_label", + "name": "project_name", "value": "MultiNavBar" }, { diff --git a/multinavbarlibrary/src/main/resources/zh_CN/element/string.json b/multinavbarlibrary/src/main/resources/zh_CN/element/string.json index e794cd2..35bf324 100644 --- a/multinavbarlibrary/src/main/resources/zh_CN/element/string.json +++ b/multinavbarlibrary/src/main/resources/zh_CN/element/string.json @@ -1,15 +1,7 @@ { "string": [ { - "name": "module_desc", - "value": "module description" - }, - { - "name": "EntryAbility_desc", - "value": "description" - }, - { - "name": "EntryAbility_label", + "name": "project_name", "value": "一多分级导航栏" }, { diff --git a/multinavbarsample/src/main/ets/entryability/EntryAbility.ets b/multinavbarsample/src/main/ets/entryability/EntryAbility.ets index bb56195..a79a572 100644 --- a/multinavbarsample/src/main/ets/entryability/EntryAbility.ets +++ b/multinavbarsample/src/main/ets/entryability/EntryAbility.ets @@ -13,7 +13,7 @@ * limitations under the License. */ -import { UIAbility } from '@kit.AbilityKit'; +import { ConfigurationConstant, UIAbility } from '@kit.AbilityKit'; import { window } from '@kit.ArkUI'; import { BusinessError } from '@kit.BasicServicesKit'; import { hilog } from '@kit.PerformanceAnalysisKit'; @@ -24,6 +24,7 @@ const TAG: string = '[EntryAbility]'; export default class EntryAbility extends UIAbility { onCreate(): void { hilog.info(0x0000, TAG, 'Ability onCreate'); + this.context.getApplicationContext().setColorMode(ConfigurationConstant.ColorMode.COLOR_MODE_NOT_SET); } onWindowStageCreate(windowStage: window.WindowStage): void { diff --git a/multinavbarsample/src/main/module.json5 b/multinavbarsample/src/main/module.json5 index eedde12..f96c82a 100644 --- a/multinavbarsample/src/main/module.json5 +++ b/multinavbarsample/src/main/module.json5 @@ -9,7 +9,7 @@ "tablet", "2in1" ], - "deliveryWithInstall": true, + "deliveryWithInstall": false, "installationFree": false, "pages": "$profile:main_pages", "abilities": [ diff --git a/multinavbarsample/src/main/resources/base/element/color.json b/multinavbarsample/src/main/resources/base/element/color.json new file mode 100644 index 0000000..79b11c2 --- /dev/null +++ b/multinavbarsample/src/main/resources/base/element/color.json @@ -0,0 +1,8 @@ +{ + "color": [ + { + "name": "start_window_background", + "value": "#000000" + } + ] +} \ No newline at end of file diff --git a/multinavbarsample/src/main/resources/base/element/string.json b/multinavbarsample/src/main/resources/base/element/string.json new file mode 100644 index 0000000..4d9705a --- /dev/null +++ b/multinavbarsample/src/main/resources/base/element/string.json @@ -0,0 +1,16 @@ +{ + "string": [ + { + "name": "module_desc", + "value": "module description" + }, + { + "name": "EntryAbility_desc", + "value": "description" + }, + { + "name": "EntryAbility_label", + "value": "MultiNavBar" + } + ] +} \ No newline at end of file diff --git a/multinavbarlibrary/src/main/resources/base/media/background.png b/multinavbarsample/src/main/resources/base/media/background.png similarity index 100% rename from multinavbarlibrary/src/main/resources/base/media/background.png rename to multinavbarsample/src/main/resources/base/media/background.png diff --git a/multinavbarlibrary/src/main/resources/base/media/foreground.png b/multinavbarsample/src/main/resources/base/media/foreground.png similarity index 100% rename from multinavbarlibrary/src/main/resources/base/media/foreground.png rename to multinavbarsample/src/main/resources/base/media/foreground.png diff --git a/multinavbarlibrary/src/main/resources/base/media/layered_image.json b/multinavbarsample/src/main/resources/base/media/layered_image.json similarity index 100% rename from multinavbarlibrary/src/main/resources/base/media/layered_image.json rename to multinavbarsample/src/main/resources/base/media/layered_image.json diff --git a/multinavbarsample/src/main/resources/base/media/startIcon.png b/multinavbarsample/src/main/resources/base/media/startIcon.png new file mode 100644 index 0000000000000000000000000000000000000000..205ad8b5a8a42e8762fbe4899b8e5e31ce822b8b GIT binary patch literal 20093 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

c)ijgxDm}8EsRXFt3h@+Ufr7@DN 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 literal 0 HcmV?d00001 diff --git a/multinavbarsample/src/main/resources/en_US/element/string.json b/multinavbarsample/src/main/resources/en_US/element/string.json new file mode 100644 index 0000000..4d9705a --- /dev/null +++ b/multinavbarsample/src/main/resources/en_US/element/string.json @@ -0,0 +1,16 @@ +{ + "string": [ + { + "name": "module_desc", + "value": "module description" + }, + { + "name": "EntryAbility_desc", + "value": "description" + }, + { + "name": "EntryAbility_label", + "value": "MultiNavBar" + } + ] +} \ No newline at end of file diff --git a/multinavbarsample/src/main/resources/zh_CN/element/string.json b/multinavbarsample/src/main/resources/zh_CN/element/string.json new file mode 100644 index 0000000..c2cef1e --- /dev/null +++ b/multinavbarsample/src/main/resources/zh_CN/element/string.json @@ -0,0 +1,16 @@ +{ + "string": [ + { + "name": "module_desc", + "value": "模块描述" + }, + { + "name": "EntryAbility_desc", + "value": "描述" + }, + { + "name": "EntryAbility_label", + "value": "一多分级导航栏" + } + ] +} \ No newline at end of file -- Gitee From 08ccaf76508224063d8975326a6e74898e90c205 Mon Sep 17 00:00:00 2001 From: EasyGuohf <163991322+EasyGuohf@users.noreply.github.com> Date: Thu, 17 Jul 2025 18:24:36 +0800 Subject: [PATCH 8/8] =?UTF-8?q?=E8=B5=84=E6=BA=90=E5=8F=8A=E8=A7=84?= =?UTF-8?q?=E8=8C=83=E6=95=B4=E6=94=B9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../main/ets/common/utils/BreakpointSystem.ets | 15 +++++++++++---- .../src/main/ets/common/utils/WindowUtils.ets | 7 +++---- multinavbarlibrary/src/main/ets/view/Home.ets | 8 +++++--- .../src/main/ets/view/TopTabView.ets | 2 +- 4 files changed, 20 insertions(+), 12 deletions(-) diff --git a/multinavbarlibrary/src/main/ets/common/utils/BreakpointSystem.ets b/multinavbarlibrary/src/main/ets/common/utils/BreakpointSystem.ets index 75e6e95..3675879 100644 --- a/multinavbarlibrary/src/main/ets/common/utils/BreakpointSystem.ets +++ b/multinavbarlibrary/src/main/ets/common/utils/BreakpointSystem.ets @@ -28,6 +28,13 @@ export enum BreakpointTypeEnum { XL = 'xl', } +export enum BreakpointWidthEnum { + WIDTH_XS = 320, + WIDTH_SM = 600, + WIDTH_MD = 840, + WIDTH_LG = 1440, +} + export interface BreakpointTypes { xs?: T; sm: T; @@ -100,13 +107,13 @@ export class BreakpointSystem { const windowWidth: number = mainWindow.windowRect.width; const windowWidthVp = window.getUIContext().px2vp(windowWidth); let widthBp: BreakpointTypeEnum = BreakpointTypeEnum.MD; - if (windowWidthVp < 320) { + if (windowWidthVp < BreakpointWidthEnum.WIDTH_XS) { widthBp = BreakpointTypeEnum.XS; - } else if (windowWidthVp >= 320 && windowWidthVp < 600) { + } else if (windowWidthVp >= BreakpointWidthEnum.WIDTH_XS && windowWidthVp < BreakpointWidthEnum.WIDTH_SM) { widthBp = BreakpointTypeEnum.SM; - } else if (windowWidthVp >= 600 && windowWidthVp < 840) { + } else if (windowWidthVp >= BreakpointWidthEnum.WIDTH_SM && windowWidthVp < BreakpointWidthEnum.WIDTH_MD) { widthBp = BreakpointTypeEnum.MD; - } else if (windowWidthVp >= 840 && windowWidthVp < 1440) { + } else if (windowWidthVp >= BreakpointWidthEnum.WIDTH_MD && windowWidthVp < BreakpointWidthEnum.WIDTH_LG) { widthBp = BreakpointTypeEnum.LG; } else { widthBp = BreakpointTypeEnum.XL; diff --git a/multinavbarlibrary/src/main/ets/common/utils/WindowUtils.ets b/multinavbarlibrary/src/main/ets/common/utils/WindowUtils.ets index 3da1091..d3992ea 100644 --- a/multinavbarlibrary/src/main/ets/common/utils/WindowUtils.ets +++ b/multinavbarlibrary/src/main/ets/common/utils/WindowUtils.ets @@ -14,7 +14,7 @@ */ import { window } from '@kit.ArkUI'; -import { BusinessError, deviceInfo } from '@kit.BasicServicesKit'; +import { BusinessError } from '@kit.BasicServicesKit'; import { hilog } from '@kit.PerformanceAnalysisKit'; import { Constants } from '../Constants'; import { BreakpointSystem } from './BreakpointSystem'; @@ -60,12 +60,11 @@ export class WindowUtil { WindowUtil.setAvoidArea(data, window.AvoidAreaType.TYPE_SYSTEM, systemAvoidArea); WindowUtil.setAvoidArea(data, window.AvoidAreaType.TYPE_NAVIGATION_INDICATOR, navIndicatorAvoidArea); data.on('windowSizeChange', () => BreakpointSystem.getInstance().onWindowSizeChange(data)); - if (deviceInfo.deviceType === '2in1' && canIUse('SystemCapability.Window.SessionManager')) { + if (canIUse('SystemCapability.Window.SessionManager')) { data.setWindowDecorVisible(false); data.setWindowDecorHeight(Constants.WINDOW_DECOR_HEIGHT); - } else { - WindowUtil.requestFullScreen(data); } + WindowUtil.requestFullScreen(data); data.on('avoidAreaChange', (avoidAreaOption) => { WindowUtil.setAvoidArea(data, avoidAreaOption.type, avoidAreaOption.area); }); diff --git a/multinavbarlibrary/src/main/ets/view/Home.ets b/multinavbarlibrary/src/main/ets/view/Home.ets index 2adad6e..55be112 100644 --- a/multinavbarlibrary/src/main/ets/view/Home.ets +++ b/multinavbarlibrary/src/main/ets/view/Home.ets @@ -24,6 +24,7 @@ import { VideoInfoView } from './VideoInfoView'; @Component export struct Home { @StorageLink(Constants.KEY_BREAKPOINT) currentWidthBreakpoint: string = BreakpointTypeEnum.SM; + @StorageLink(Constants.KEY_STATUS_BAR_HEIGHT) statusBarHeight: number = 0; @State firstLevelIndex: number = 0; @State secondLevelIndex: number = 0; @State tabViewModel: TabViewModel = new TabViewModel(); @@ -62,15 +63,16 @@ export struct Home { this.secondLevelIndex)) .fontSize($r('sys.float.Title_S')) .fontWeight(FontWeight.Bold) + .textAlign(TextAlign.Center) + .height(Constants.WINDOW_DECOR_HEIGHT) .margin({ - left: $r('sys.float.padding_level16'), - top: $r('sys.float.padding_level36'), - bottom: $r('sys.float.padding_level7') + left: $r('sys.float.padding_level16') }) VideoInfoView({ secondLevelIndex: this.secondLevelIndex }) } + .padding({ top: this.statusBarHeight }) .alignItems(HorizontalAlign.Start) } .autoHide(false) diff --git a/multinavbarlibrary/src/main/ets/view/TopTabView.ets b/multinavbarlibrary/src/main/ets/view/TopTabView.ets index fb2556e..7d7502d 100644 --- a/multinavbarlibrary/src/main/ets/view/TopTabView.ets +++ b/multinavbarlibrary/src/main/ets/view/TopTabView.ets @@ -25,8 +25,8 @@ const TAG: string = '[TopTabView]'; @Component export struct TopTabView { @StorageLink(Constants.KEY_BREAKPOINT) currentWidthBreakpoint: string = BreakpointTypeEnum.SM; + @StorageLink(Constants.KEY_STATUS_BAR_HEIGHT) statusBarHeight: number = 0; @State secondLevelIndex: number = 0; - @State statusBarHeight: number = AppStorage.get(Constants.KEY_STATUS_BAR_HEIGHT)!; @Link tabData: TabDataModel; private firstLevel: string = ''; -- Gitee