From bdbe7bb71e7d2d2882f3053fe21f8a7a230bdd61 Mon Sep 17 00:00:00 2001 From: chenbosongcode Date: Tue, 28 Oct 2025 15:00:48 +0800 Subject: [PATCH] =?UTF-8?q?Fixed=20synchronize=20openharmony=20sample=20in?= =?UTF-8?q?clude=20ChooseComponent=20=E3=80=81=20DialogProject=E3=80=81Int?= =?UTF-8?q?erAction=E3=80=81StyledStringNDK?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Issue: https://gitee.com/harmonyos_samples/guide-snippets/issues/ID3TOS Description: isues ID3TOS is synchronize openharmony sample Signed-off-by: chenbosongcode --- ArkUIKit/ChooseComponent/README_zh.md | 5 + .../src/main/ets/pages/button/ButtonCase1.ets | 140 ++++++ .../src/main/ets/pages/button/ButtonCase2.ets | 49 ++ .../ets/pages/button/ButtonCustomStyle.ets | 31 +- .../main/ets/pages/button/CreateButton.ets | 20 +- .../ets/pages/button/HoverButtonExample.ets | 64 +++ .../entry/src/main/ets/pages/button/Index.ets | 27 +- .../main/ets/pages/button/SetButtonType.ets | 30 +- .../main/resources/base/element/string.json | 32 ++ .../src/ohosTest/ets/test/Index.test.ets | 104 +++++ ArkUIKit/ChooseComponent/ohosTest.md | 17 +- ArkUIKit/DialogProject/.gitignore | 12 + ArkUIKit/DialogProject/README_zh.md | 85 +++- .../src/main/ets/common/PromptActionClass1.ts | 86 ++++ .../entry/src/main/ets/pages/Index.ets | 7 + .../main/ets/pages/Menu/BindComponentMenu.ets | 56 +++ .../pages/Menu/EventTransSubWindowMenu.ets | 57 +++ .../entry/src/main/ets/pages/Menu/Index.ets | 35 +- .../main/ets/pages/Menu/PopVibrateMenu.ets | 99 ++++ .../Menu/SupportAvoidCentralAxisMenu.ets | 121 +++++ .../customdialog/CreateCustomDialog1.ets | 51 +++ .../pages/customdialog/DialogAnimation1.ets | 79 ++++ .../customdialog/DialogAvoidSoftKeyboard.ets | 74 +++ .../pages/customdialog/DialogInteraction1.ets | 10 +- .../pages/customdialog/DialogInteraction2.ets | 79 ++++ .../pages/customdialog/DialogInteraction3.ets | 115 +++++ .../ets/pages/customdialog/DialogStyle1.ets | 77 ++++ .../customdialog/DialogWithPhysicalBack.ets | 113 +++++ .../pages/customdialog/GetDialogStatus.ets | 75 ++++ .../src/main/ets/pages/customdialog/Index.ets | 71 +++ .../main/ets/pages/customdialog/Index2.ets | 43 ++ .../ets/pages/customdialog/NestDialog1.ets | 126 ++++++ .../pages/fixedstyledialog/ActionSheet.ets | 1 + .../pages/fixedstyledialog/AlertDialog.ets | 1 + .../fixedstyledialog/CalendarPickerDialog.ets | 2 + .../DatePickerCustomDialog.ets | 57 +++ .../fixedstyledialog/DatePickerDialog.ets | 1 + .../main/ets/pages/fixedstyledialog/Index.ets | 18 +- .../ets/pages/fixedstyledialog/ShowDialog.ets | 11 +- .../fixedstyledialog/TextPickerDialog.ets | 1 + .../fixedstyledialog/TimePickerDialog.ets | 3 + .../maskdialog/CustomDialogAnimation.ets | 77 ++++ .../pages/maskdialog/CustomDialogControl.ets | 158 +++++++ .../src/main/ets/pages/maskdialog/Index.ets | 76 ++++ .../main/ets/pages/opencustomdialog/Index.ets | 24 + .../opencustomdialog/OpenDialogAndUpdate.ets | 97 ++++ .../customDialogComponentWithTransition.ets | 81 ++++ .../customDialogWithKeyboardAvoidDistance.ets | 65 +++ .../src/main/ets/pages/popup/ButtonPopup.ets | 2 + .../src/main/ets/pages/popup/CustomPopup.ets | 2 + .../entry/src/main/ets/pages/popup/Index.ets | 31 +- .../main/ets/pages/popup/PopupAnimation.ets | 8 +- .../pages/popup/PopupAvoidSoftKeyboard.ets | 58 +++ .../pages/popup/PopupPolymorphicEffect.ets | 114 +++++ .../main/ets/pages/popup/PopupStateChange.ets | 2 + .../src/main/ets/pages/popup/PopupStyle.ets | 2 + .../pages/popup/PopupSupportedAvoidAxis.ets | 104 +++++ .../src/main/ets/pages/popup/TextPrompts.ets | 2 + .../DialogProject/entry/src/main/module.json5 | 9 +- .../main/resources/base/element/string.json | 268 +++++++++++ .../DialogProject/entry/src/main/syscap.json | 30 +- .../src/ohosTest/ets/test/Index.test.ets | 422 ++++++++++++++++-- .../entry/src/ohosTest/ets/test/List.test.ets | 7 +- .../entry/src/ohosTest/ets/test/Menu.test.ets | 181 ++++++++ .../src/ohosTest/ets/test/Popup.test.ets | 375 ++++++++++++++++ ArkUIKit/DialogProject/ohosTest.md | 70 ++- ArkUIKit/InterAction/.gitignore | 12 + ArkUIKit/InterAction/AppScope/app.json5 | 24 + .../resources/base/element/string.json | 8 + .../resources/base/media/background.png | Bin 0 -> 91942 bytes .../resources/base/media/foreground.png | Bin 0 -> 15325 bytes .../resources/base/media/layered_image.json | 7 + ArkUIKit/InterAction/README_zh.md | 97 ++++ ArkUIKit/InterAction/build-profile.json5 | 57 +++ ArkUIKit/InterAction/code-linter.json5 | 46 ++ ArkUIKit/InterAction/entry/.gitignore | 6 + .../InterAction/entry/build-profile.json5 | 47 ++ ArkUIKit/InterAction/entry/hvigorfile.ts | 21 + .../InterAction/entry/obfuscation-rules.txt | 23 + ArkUIKit/InterAction/entry/oh-package.json5 | 24 + .../entry/src/main/ets/common/resource.ets | 25 ++ .../main/ets/entryability/EntryAbility.ets | 95 ++++ .../entrybackupability/EntryBackupAbility.ets | 30 ++ .../FocusOnclickExample.ets | 50 +++ .../entry/src/main/ets/pages/Index.ets | 208 +++++++++ .../ets/pages/MouseButton/MouseButton.ets | 141 ++++++ .../ets/pages/MouseWheel/ListDataSource.ets | 72 +++ .../main/ets/pages/MouseWheel/MouseWheel.ets | 75 ++++ .../MultipleFingerInformation.ets | 56 +++ .../pages/PreventBubbling/PreventBubbling.ets | 47 ++ .../entry/src/main/ets/pages/common/Index.ets | 23 + .../main/ets/pages/mouseMove/MouseMove.ets | 61 +++ .../src/main/ets/pages/onHover/OnHover.ets | 40 ++ .../src/main/ets/pages/sampling/Sampling.ets | 39 ++ .../pages/stopPropagation/StopPropagation.ets | 62 +++ .../InterAction/entry/src/main/module.json5 | 65 +++ .../main/resources/base/element/color.json | 8 + .../main/resources/base/element/float.json | 8 + .../main/resources/base/element/string.json | 112 +++++ .../main/resources/base/media/background.png | Bin 0 -> 91942 bytes .../main/resources/base/media/foreground.png | Bin 0 -> 8805 bytes .../resources/base/media/layered_image.json | 7 + .../main/resources/base/media/startIcon.png | Bin 0 -> 20093 bytes .../resources/base/profile/backup_config.json | 3 + .../resources/base/profile/main_pages.json | 14 + .../main/resources/dark/element/color.json | 8 + .../InterAction/entry/src/main/syscap.json | 20 + .../entry/src/mock/mock-config.json5 | 16 + .../src/ohosTest/ets/test/Ability.test.ets | 50 +++ .../src/ohosTest/ets/test/Index.test.ets | 189 ++++++++ .../entry/src/ohosTest/ets/test/List.test.ets | 20 + .../entry/src/ohosTest/module.json5 | 26 ++ .../InterAction/entry/src/test/List.test.ets | 20 + .../entry/src/test/LocalUnit.test.ets | 48 ++ .../InterAction/hvigor/hvigor-config.json5 | 37 ++ ArkUIKit/InterAction/hvigorfile.ts | 21 + ArkUIKit/InterAction/oh-package.json5 | 25 ++ ArkUIKit/InterAction/ohosTest.md | 8 + .../InterAction/screenshots/device/image1.png | Bin 0 -> 23450 bytes .../InterAction/screenshots/device/image2.png | Bin 0 -> 15616 bytes .../InterAction/screenshots/device/image3.png | Bin 0 -> 30811 bytes ArkUIKit/StyledStringNDK/README.md | 12 +- ArkUIKit/StyledStringNDK/build-profile.json5 | 2 + .../StyledStringNDK/entry/build-profile.json5 | 19 +- .../entry/src/main/cpp/manager.cpp | 34 +- .../entry/src/main/cpp/manager.h | 4 +- .../entry/src/main/cpp/napi_init.cpp | 30 +- .../src/main/cpp/types/libentry/Index.d.ts | 3 +- .../entry/src/main/ets/pages/Index.ets | 14 +- .../entry/src/main/module.json5 | 3 +- .../entry/src/main/syscap.json | 12 + .../src/ohosTest/ets/test/Ability.test.ets | 22 +- .../ohosTest/ets/testability/TestAbility.ets | 66 +++ .../ohosTest/ets/testability/pages/Index.ets | 36 ++ .../ets/testrunner/OpenHarmonyTestRunner.ts | 64 +++ .../entry/src/ohosTest/module.json5 | 25 +- .../resources/base/element/color.json | 8 + .../resources/base/element/string.json | 16 + .../ohosTest/resources/base/media/icon.png | Bin 0 -> 7536 bytes .../resources/base/profile/test_pages.json | 5 + .../entry/src/ohosTest/syscap.json | 12 + ArkUIKit/StyledStringNDK/oh-package.json5 | 3 +- ArkUIKit/TextAreaEventNDK/README.md | 12 +- ArkUIKit/TextAreaEventNDK/build-profile.json5 | 2 + .../entry/build-profile.json5 | 5 +- .../entry/src/main/cpp/manager.cpp | 16 +- .../entry/src/main/cpp/manager.h | 8 +- .../entry/src/main/cpp/napi_init.cpp | 31 +- .../src/main/cpp/types/libentry/Index.d.ts | 3 +- .../entry/src/main/ets/pages/Index.ets | 15 +- .../entry/src/main/module.json5 | 3 +- .../entry/src/main/syscap.json | 12 + .../src/ohosTest/ets/test/Ability.test.ets | 22 +- .../ohosTest/ets/testability/TestAbility.ets | 66 +++ .../ohosTest/ets/testability/pages/Index.ets | 48 ++ .../ets/testrunner/OpenHarmonyTestRunner.ts | 64 +++ .../entry/src/ohosTest/module.json5 | 25 +- .../resources/base/element/color.json | 8 + .../resources/base/element/string.json | 16 + .../ohosTest/resources/base/media/icon.png | Bin 0 -> 7536 bytes .../resources/base/profile/test_pages.json | 5 + .../entry/src/ohosTest/syscap.json | 12 + ArkUIKit/TextAreaEventNDK/oh-package.json5 | 3 +- 163 files changed, 7026 insertions(+), 191 deletions(-) create mode 100644 ArkUIKit/ChooseComponent/entry/src/main/ets/pages/button/ButtonCase1.ets create mode 100644 ArkUIKit/ChooseComponent/entry/src/main/ets/pages/button/ButtonCase2.ets create mode 100644 ArkUIKit/ChooseComponent/entry/src/main/ets/pages/button/HoverButtonExample.ets create mode 100644 ArkUIKit/DialogProject/.gitignore create mode 100644 ArkUIKit/DialogProject/entry/src/main/ets/common/PromptActionClass1.ts create mode 100644 ArkUIKit/DialogProject/entry/src/main/ets/pages/Menu/BindComponentMenu.ets create mode 100644 ArkUIKit/DialogProject/entry/src/main/ets/pages/Menu/EventTransSubWindowMenu.ets create mode 100644 ArkUIKit/DialogProject/entry/src/main/ets/pages/Menu/PopVibrateMenu.ets create mode 100644 ArkUIKit/DialogProject/entry/src/main/ets/pages/Menu/SupportAvoidCentralAxisMenu.ets create mode 100644 ArkUIKit/DialogProject/entry/src/main/ets/pages/customdialog/CreateCustomDialog1.ets create mode 100644 ArkUIKit/DialogProject/entry/src/main/ets/pages/customdialog/DialogAnimation1.ets create mode 100644 ArkUIKit/DialogProject/entry/src/main/ets/pages/customdialog/DialogAvoidSoftKeyboard.ets create mode 100644 ArkUIKit/DialogProject/entry/src/main/ets/pages/customdialog/DialogInteraction2.ets create mode 100644 ArkUIKit/DialogProject/entry/src/main/ets/pages/customdialog/DialogInteraction3.ets create mode 100644 ArkUIKit/DialogProject/entry/src/main/ets/pages/customdialog/DialogStyle1.ets create mode 100644 ArkUIKit/DialogProject/entry/src/main/ets/pages/customdialog/DialogWithPhysicalBack.ets create mode 100644 ArkUIKit/DialogProject/entry/src/main/ets/pages/customdialog/GetDialogStatus.ets create mode 100644 ArkUIKit/DialogProject/entry/src/main/ets/pages/customdialog/Index2.ets create mode 100644 ArkUIKit/DialogProject/entry/src/main/ets/pages/customdialog/NestDialog1.ets create mode 100644 ArkUIKit/DialogProject/entry/src/main/ets/pages/fixedstyledialog/DatePickerCustomDialog.ets create mode 100644 ArkUIKit/DialogProject/entry/src/main/ets/pages/maskdialog/CustomDialogAnimation.ets create mode 100644 ArkUIKit/DialogProject/entry/src/main/ets/pages/maskdialog/CustomDialogControl.ets create mode 100644 ArkUIKit/DialogProject/entry/src/main/ets/pages/maskdialog/Index.ets create mode 100644 ArkUIKit/DialogProject/entry/src/main/ets/pages/opencustomdialog/OpenDialogAndUpdate.ets create mode 100644 ArkUIKit/DialogProject/entry/src/main/ets/pages/opencustomdialog/customDialogComponentWithTransition.ets create mode 100644 ArkUIKit/DialogProject/entry/src/main/ets/pages/opencustomdialog/customDialogWithKeyboardAvoidDistance.ets create mode 100644 ArkUIKit/DialogProject/entry/src/main/ets/pages/popup/PopupAvoidSoftKeyboard.ets create mode 100644 ArkUIKit/DialogProject/entry/src/main/ets/pages/popup/PopupPolymorphicEffect.ets create mode 100644 ArkUIKit/DialogProject/entry/src/main/ets/pages/popup/PopupSupportedAvoidAxis.ets create mode 100644 ArkUIKit/DialogProject/entry/src/ohosTest/ets/test/Menu.test.ets create mode 100644 ArkUIKit/DialogProject/entry/src/ohosTest/ets/test/Popup.test.ets create mode 100644 ArkUIKit/InterAction/.gitignore create mode 100644 ArkUIKit/InterAction/AppScope/app.json5 create mode 100644 ArkUIKit/InterAction/AppScope/resources/base/element/string.json create mode 100644 ArkUIKit/InterAction/AppScope/resources/base/media/background.png create mode 100644 ArkUIKit/InterAction/AppScope/resources/base/media/foreground.png create mode 100644 ArkUIKit/InterAction/AppScope/resources/base/media/layered_image.json create mode 100644 ArkUIKit/InterAction/README_zh.md create mode 100644 ArkUIKit/InterAction/build-profile.json5 create mode 100644 ArkUIKit/InterAction/code-linter.json5 create mode 100644 ArkUIKit/InterAction/entry/.gitignore create mode 100644 ArkUIKit/InterAction/entry/build-profile.json5 create mode 100644 ArkUIKit/InterAction/entry/hvigorfile.ts create mode 100644 ArkUIKit/InterAction/entry/obfuscation-rules.txt create mode 100644 ArkUIKit/InterAction/entry/oh-package.json5 create mode 100644 ArkUIKit/InterAction/entry/src/main/ets/common/resource.ets create mode 100644 ArkUIKit/InterAction/entry/src/main/ets/entryability/EntryAbility.ets create mode 100644 ArkUIKit/InterAction/entry/src/main/ets/entrybackupability/EntryBackupAbility.ets create mode 100644 ArkUIKit/InterAction/entry/src/main/ets/pages/FocusOnclickExample/FocusOnclickExample.ets create mode 100644 ArkUIKit/InterAction/entry/src/main/ets/pages/Index.ets create mode 100644 ArkUIKit/InterAction/entry/src/main/ets/pages/MouseButton/MouseButton.ets create mode 100644 ArkUIKit/InterAction/entry/src/main/ets/pages/MouseWheel/ListDataSource.ets create mode 100644 ArkUIKit/InterAction/entry/src/main/ets/pages/MouseWheel/MouseWheel.ets create mode 100644 ArkUIKit/InterAction/entry/src/main/ets/pages/MultipleFingerInformation/MultipleFingerInformation.ets create mode 100644 ArkUIKit/InterAction/entry/src/main/ets/pages/PreventBubbling/PreventBubbling.ets create mode 100644 ArkUIKit/InterAction/entry/src/main/ets/pages/common/Index.ets create mode 100644 ArkUIKit/InterAction/entry/src/main/ets/pages/mouseMove/MouseMove.ets create mode 100644 ArkUIKit/InterAction/entry/src/main/ets/pages/onHover/OnHover.ets create mode 100644 ArkUIKit/InterAction/entry/src/main/ets/pages/sampling/Sampling.ets create mode 100644 ArkUIKit/InterAction/entry/src/main/ets/pages/stopPropagation/StopPropagation.ets create mode 100644 ArkUIKit/InterAction/entry/src/main/module.json5 create mode 100644 ArkUIKit/InterAction/entry/src/main/resources/base/element/color.json create mode 100644 ArkUIKit/InterAction/entry/src/main/resources/base/element/float.json create mode 100644 ArkUIKit/InterAction/entry/src/main/resources/base/element/string.json create mode 100644 ArkUIKit/InterAction/entry/src/main/resources/base/media/background.png create mode 100644 ArkUIKit/InterAction/entry/src/main/resources/base/media/foreground.png create mode 100644 ArkUIKit/InterAction/entry/src/main/resources/base/media/layered_image.json create mode 100644 ArkUIKit/InterAction/entry/src/main/resources/base/media/startIcon.png create mode 100644 ArkUIKit/InterAction/entry/src/main/resources/base/profile/backup_config.json create mode 100644 ArkUIKit/InterAction/entry/src/main/resources/base/profile/main_pages.json create mode 100644 ArkUIKit/InterAction/entry/src/main/resources/dark/element/color.json create mode 100644 ArkUIKit/InterAction/entry/src/main/syscap.json create mode 100644 ArkUIKit/InterAction/entry/src/mock/mock-config.json5 create mode 100644 ArkUIKit/InterAction/entry/src/ohosTest/ets/test/Ability.test.ets create mode 100644 ArkUIKit/InterAction/entry/src/ohosTest/ets/test/Index.test.ets create mode 100644 ArkUIKit/InterAction/entry/src/ohosTest/ets/test/List.test.ets create mode 100644 ArkUIKit/InterAction/entry/src/ohosTest/module.json5 create mode 100644 ArkUIKit/InterAction/entry/src/test/List.test.ets create mode 100644 ArkUIKit/InterAction/entry/src/test/LocalUnit.test.ets create mode 100644 ArkUIKit/InterAction/hvigor/hvigor-config.json5 create mode 100644 ArkUIKit/InterAction/hvigorfile.ts create mode 100644 ArkUIKit/InterAction/oh-package.json5 create mode 100644 ArkUIKit/InterAction/ohosTest.md create mode 100644 ArkUIKit/InterAction/screenshots/device/image1.png create mode 100644 ArkUIKit/InterAction/screenshots/device/image2.png create mode 100644 ArkUIKit/InterAction/screenshots/device/image3.png create mode 100644 ArkUIKit/StyledStringNDK/entry/src/main/syscap.json create mode 100644 ArkUIKit/StyledStringNDK/entry/src/ohosTest/ets/testability/TestAbility.ets create mode 100644 ArkUIKit/StyledStringNDK/entry/src/ohosTest/ets/testability/pages/Index.ets create mode 100644 ArkUIKit/StyledStringNDK/entry/src/ohosTest/ets/testrunner/OpenHarmonyTestRunner.ts create mode 100644 ArkUIKit/StyledStringNDK/entry/src/ohosTest/resources/base/element/color.json create mode 100644 ArkUIKit/StyledStringNDK/entry/src/ohosTest/resources/base/element/string.json create mode 100644 ArkUIKit/StyledStringNDK/entry/src/ohosTest/resources/base/media/icon.png create mode 100644 ArkUIKit/StyledStringNDK/entry/src/ohosTest/resources/base/profile/test_pages.json create mode 100644 ArkUIKit/StyledStringNDK/entry/src/ohosTest/syscap.json create mode 100644 ArkUIKit/TextAreaEventNDK/entry/src/main/syscap.json create mode 100644 ArkUIKit/TextAreaEventNDK/entry/src/ohosTest/ets/testability/TestAbility.ets create mode 100644 ArkUIKit/TextAreaEventNDK/entry/src/ohosTest/ets/testability/pages/Index.ets create mode 100644 ArkUIKit/TextAreaEventNDK/entry/src/ohosTest/ets/testrunner/OpenHarmonyTestRunner.ts create mode 100644 ArkUIKit/TextAreaEventNDK/entry/src/ohosTest/resources/base/element/color.json create mode 100644 ArkUIKit/TextAreaEventNDK/entry/src/ohosTest/resources/base/element/string.json create mode 100644 ArkUIKit/TextAreaEventNDK/entry/src/ohosTest/resources/base/media/icon.png create mode 100644 ArkUIKit/TextAreaEventNDK/entry/src/ohosTest/resources/base/profile/test_pages.json create mode 100644 ArkUIKit/TextAreaEventNDK/entry/src/ohosTest/syscap.json diff --git a/ArkUIKit/ChooseComponent/README_zh.md b/ArkUIKit/ChooseComponent/README_zh.md index e1a335f5c..07f29630f 100644 --- a/ArkUIKit/ChooseComponent/README_zh.md +++ b/ArkUIKit/ChooseComponent/README_zh.md @@ -29,9 +29,12 @@ entry/src/main/ets/ |---entryability |---pages | |---button +| | |---ButtionCase1.ets // 按钮创建示例代码 +| | |---ButtionCase2.ets // 按钮创建示例代码 | | |---CreateButton.ets // 按钮创建示例代码 | | |---ButtonCustomStyle.ets // 按钮自定义示例代码 | | |---FloatingButton.ets // 按钮悬浮场景示例代码 +| | |---HoverButtonExample.ets // 按钮悬浮场景示例代码 | | |---Index.ets // 第二层级目录 | | |---SetButtonType.ets // 按钮类型设置示例代码 | | |---SubmitForm.ets // 按钮注册场景示例代码 @@ -50,6 +53,8 @@ entry/src/ohosTest/ |---ets | |---index.test.ets // 示例代码测试代码 ``` +## 具体实现 +Button是按钮组件,通常用于响应用户的点击操作,其类型包括胶囊按钮、圆形按钮、普通按钮、圆角矩形按钮。Button作为容器使用时可以通过添加子组件实现包含文字、图片等元素的按钮 ### 相关权限 diff --git a/ArkUIKit/ChooseComponent/entry/src/main/ets/pages/button/ButtonCase1.ets b/ArkUIKit/ChooseComponent/entry/src/main/ets/pages/button/ButtonCase1.ets new file mode 100644 index 000000000..565f6bd33 --- /dev/null +++ b/ArkUIKit/ChooseComponent/entry/src/main/ets/pages/button/ButtonCase1.ets @@ -0,0 +1,140 @@ +/* + * 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 { hilog } from '@kit.PerformanceAnalysisKit'; +// [Start button_case_1] +const DOMAIN = 0x0000; +// xxx.ets +@Entry +@Component +export struct ButtonCase1 { + pathStack: NavPathStack = new NavPathStack(); + + @Builder + PageMap(name: string) { + if (name === 'first_page') { + pageOneTmp() + } else if (name === 'second_page') { + pageTwoTmp() + } else if (name === 'third_page') { + pageThreeTmp() + } + } + + build() { + // [StartExclude button_case_1] + NavDestination() { + // [EndExclude button_case_1] + + Navigation(this.pathStack) { + List({ space: 4 }) { + ListItem() { + Button('First').onClick(() => { + this.pathStack.pushPath({ name: 'first_page' }); + }) + .width('100%') + } + + ListItem() { + Button('Second').onClick(() => { + this.pathStack.pushPath({ name: 'second_page' }); + }) + .width('100%') + } + + ListItem() { + Button('Third').onClick(() => { + this.pathStack.pushPath({ name: 'third_page' }); + }) + .width('100%') + } + } + .listDirection(Axis.Vertical) + .backgroundColor(0xDCDCDC).padding(20) + } + .mode(NavigationMode.Stack) + .navDestination(this.PageMap) + // [StartExclude button_case_1] + } + // [EndExclude button_case_1] + } +} + +// pageOne +@Component +export struct pageOneTmp { + pathStack: NavPathStack = new NavPathStack(); + + build() { + NavDestination() { + Column() { + Text('first_page') + }.width('100%').height('100%') + }.title('pageOne') + .onBackPressed(() => { + const popDestinationInfo = this.pathStack.pop(); // 弹出路由栈栈顶元素 + hilog.info(DOMAIN, 'testTag', 'pop' + '返回值' + JSON.stringify(popDestinationInfo)); + return true + }) + .onReady((context: NavDestinationContext) => { + this.pathStack = context.pathStack; + }) + } +} + +// pageTwo +@Component +export struct pageTwoTmp { + pathStack: NavPathStack = new NavPathStack(); + + build() { + NavDestination() { + Column() { + Text('second_page') + }.width('100%').height('100%') + }.title('pageTwo') + .onBackPressed(() => { + const popDestinationInfo = this.pathStack.pop(); // 弹出路由栈栈顶元素 + hilog.info(DOMAIN, 'testTag', 'pop' + '返回值' + JSON.stringify(popDestinationInfo)); + return true + }) + .onReady((context: NavDestinationContext) => { + this.pathStack = context.pathStack; + }) + } +} + +// pageThree +@Component +export struct pageThreeTmp { + pathStack: NavPathStack = new NavPathStack(); + + build() { + NavDestination() { + Column() { + Text('third_page') + }.width('100%').height('100%') + }.title('pageThree') + .onBackPressed(() => { + const popDestinationInfo = this.pathStack.pop(); // 弹出路由栈栈顶元素 + hilog.info(DOMAIN, 'testTag', 'pop' + '返回值' + JSON.stringify(popDestinationInfo)); + return true + }) + .onReady((context: NavDestinationContext) => { + this.pathStack = context.pathStack; + }) + } +} +// [End button_case_1] \ No newline at end of file diff --git a/ArkUIKit/ChooseComponent/entry/src/main/ets/pages/button/ButtonCase2.ets b/ArkUIKit/ChooseComponent/entry/src/main/ets/pages/button/ButtonCase2.ets new file mode 100644 index 000000000..cedb508b6 --- /dev/null +++ b/ArkUIKit/ChooseComponent/entry/src/main/ets/pages/button/ButtonCase2.ets @@ -0,0 +1,49 @@ +/* + * 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 { hilog } from '@kit.PerformanceAnalysisKit'; +// [Start button_case_2] +// xxx.ets +const DOMAIN = 0x0000; +@Entry +@Component +export struct ButtonCase2 { + build() { + // [StartExclude button_case_2] + NavDestination() { + // [EndExclude button_case_2] + Column() { + TextInput({ placeholder: 'input your username' }).margin({ top: 20 }) + TextInput({ placeholder: 'input your password' }).type(InputType.Password).margin({ top: 20 }) + Button('Register').width(300).margin({ top: 20 }) + .onClick(() => { + // 需要执行的操作 + }) + // [StartExclude button_case_2] + + // [Start button_case2_add_event] + Button('Ok', { type: ButtonType.Normal, stateEffect: true }) + .onClick(()=>{ + hilog.info(DOMAIN, 'testTag', 'Button onClick') + }).margin(10) + // [Start button_case2_add_event] + // [EndExclude button_case_2] + }.padding(20) + // [StartExclude button_case_2] + } + // [EndExclude button_case_2] + } +} +// [End button_case_2] \ No newline at end of file diff --git a/ArkUIKit/ChooseComponent/entry/src/main/ets/pages/button/ButtonCustomStyle.ets b/ArkUIKit/ChooseComponent/entry/src/main/ets/pages/button/ButtonCustomStyle.ets index dfbc79820..da855939a 100644 --- a/ArkUIKit/ChooseComponent/entry/src/main/ets/pages/button/ButtonCustomStyle.ets +++ b/ArkUIKit/ChooseComponent/entry/src/main/ets/pages/button/ButtonCustomStyle.ets @@ -1,5 +1,5 @@ /* - * Copyright (c) 2024 Huawei Device Co., Ltd. + * Copyright (c) 2024-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 @@ -36,6 +36,12 @@ export struct ButtonCustomStyle { .id('circle_border') .borderRadius(10) // [End custom_button_border_radius] + + // [Start custom_button_border_radius2] + Button('circle border', { type: ButtonType.Normal }) + .borderRadius(20) + .height(40) + // [End custom_button_border_radius2] } ComponentCard({ @@ -48,6 +54,14 @@ export struct ButtonCustomStyle { .fontColor(Color.Pink) .fontWeight(800) // [End custom_font_style] + + + // [Start custom_font_style2] + Button('font style', { type: ButtonType.Normal }) + .fontSize(20) + .fontColor(Color.Pink) + .fontWeight(800) + // [End custom_font_style2] } ComponentCard({ @@ -58,6 +72,21 @@ export struct ButtonCustomStyle { Button('Button').id('background_color') .backgroundColor(Color.Red) // [End custom_background_color] + // [Start custom_background_color2] + Button('background color').backgroundColor(0xF55A42) + // [Start custom_background_color2] + } + + ComponentCard({ + title: $r('app.string.SetButtonType_titleFive'), + description: $r('app.string.SetButtonType_descriptionFive') + }) { + //图片需要更换,left使用方式做了修改 + // [Start custom_create_function_button] + Button({ type: ButtonType.Circle, stateEffect: true }) { + Image($r('sys.media.ohos_ic_public_cancel')).width(30).height(30) + }.width(55).height(55).margin({ 'left': 20 }).backgroundColor(0xF55A42) + // [End custom_create_function_button] } } .width('100%') diff --git a/ArkUIKit/ChooseComponent/entry/src/main/ets/pages/button/CreateButton.ets b/ArkUIKit/ChooseComponent/entry/src/main/ets/pages/button/CreateButton.ets index d903c8599..c35769b9b 100644 --- a/ArkUIKit/ChooseComponent/entry/src/main/ets/pages/button/CreateButton.ets +++ b/ArkUIKit/ChooseComponent/entry/src/main/ets/pages/button/CreateButton.ets @@ -1,5 +1,5 @@ /* - * Copyright (c) 2024 Huawei Device Co., Ltd. + * Copyright (c) 2024-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 @@ -32,6 +32,14 @@ export struct CreateButton { Button('Button', { type: ButtonType.Capsule, stateEffect: true }) .id('button') // [End create_button_by_label] + + // [Start create_button_by_label2] + Button('Ok', { type: ButtonType.Normal, stateEffect: true }) + .borderRadius(8) + .backgroundColor(0x317aff) + .width(90) + .height(40) + // [End create_button_by_label2] } ComponentCard({ @@ -46,6 +54,16 @@ export struct CreateButton { }.alignItems(VerticalAlign.Center).justifyContent(FlexAlign.Center).width(90).height(40) }.id('button_back') // [End create_button_by_button_options] + + // [Start create_button_by_button_options2] + //注意图片不一致 + Button({ type: ButtonType.Normal, stateEffect: true }) { + Row() { + Image($r('sys.media.ohos_ic_back')).width(20).height(40).margin({ left: 12 }) + Text('loading').fontSize(12).fontColor(0xffffff).margin({ left: 5, right: 12 }) + }.alignItems(VerticalAlign.Center) + }.borderRadius(8).backgroundColor(0x317aff).width(90).height(40) + // [Start create_button_by_button_options2] } } .width('100%') diff --git a/ArkUIKit/ChooseComponent/entry/src/main/ets/pages/button/HoverButtonExample.ets b/ArkUIKit/ChooseComponent/entry/src/main/ets/pages/button/HoverButtonExample.ets new file mode 100644 index 000000000..927e3ce4e --- /dev/null +++ b/ArkUIKit/ChooseComponent/entry/src/main/ets/pages/button/HoverButtonExample.ets @@ -0,0 +1,64 @@ +/* + * 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. + */ + + +// xxx.ets +@Entry +@Component +export struct HoverButtonExample { + private arr: number[] = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]; + build() { + // [StartExclude hover_button_example] + NavDestination() { + // [EndExclude hover_button_example] + Stack() { + List({ space: 20, initialIndex: 0 }) { + ForEach(this.arr, (item: number) => { + ListItem() { + Text('' + item) + .width('100%') + .height(100) + .fontSize(16) + .textAlign(TextAlign.Center) + .borderRadius(10) + .backgroundColor(0xFFFFFF) + } + }, (item: number) => item.toString()) + }.width('90%') + + Button() { + //注意图片需要替换 + Image($r('sys.media.ohos_ic_public_add')) + .width(50) + .height(50) + } + .width(60) + .height(60) + .position({ x: '80%', y: 600 }) + .shadow({ radius: 10 }) + .onClick(() => { + // 需要执行的操作 + }) + } + .width('100%') + .height('100%') + .backgroundColor(0xDCDCDC) + .padding({ top: 5 }) + // [StartExclude hover_button_example] + } + // [EndExclude hover_button_example] + } +} +// [End button_case_1] \ No newline at end of file diff --git a/ArkUIKit/ChooseComponent/entry/src/main/ets/pages/button/Index.ets b/ArkUIKit/ChooseComponent/entry/src/main/ets/pages/button/Index.ets index f37f6f3bd..a51d7b931 100644 --- a/ArkUIKit/ChooseComponent/entry/src/main/ets/pages/button/Index.ets +++ b/ArkUIKit/ChooseComponent/entry/src/main/ets/pages/button/Index.ets @@ -1,5 +1,5 @@ /* - * Copyright (c) 2024 Huawei Device Co., Ltd. + * Copyright (c) 2024-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 @@ -21,6 +21,9 @@ import { Route } from '../../common/Route'; import { SetButtonType } from './SetButtonType'; import { SubmitForm } from './SubmitForm'; import resource from '../../common/resource' +import { ButtonCase1 } from './ButtonCase1'; +import { ButtonCase2 } from './ButtonCase2'; +import { HoverButtonExample } from './HoverButtonExample'; export const BUTTON_ROUTE_PREFIX: string = 'button'; @@ -50,7 +53,21 @@ const routes: Route[] = [ title: resource.resourceToString($r('app.string.FloatingButton_title')), description: $r('app.string.FloatingButton_description') }, -] + { + name: `${BUTTON_ROUTE_PREFIX}/ButtonCase1`, + title: resource.resourceToString($r('app.string.ButtonCase1_title')), + description: $r('app.string.ButtonCase1_desc') + }, + { + name: `${BUTTON_ROUTE_PREFIX}/ButtonCase2`, + title: resource.resourceToString($r('app.string.ButtonCase2_title')), + description: $r('app.string.ButtonCase2_desc') + }, + { + name: `${BUTTON_ROUTE_PREFIX}/HoverButtonExample`, + title: resource.resourceToString($r('app.string.HoverButtonExample_title')), + description: $r('app.string.HoverButtonExample_desc') + }] @Builder export function buttonDestination(name: string) { @@ -66,6 +83,12 @@ export function buttonDestination(name: string) { SubmitForm(); } else if (name === routes[4].name) { FloatingButton(); + } else if (name === routes[5].name) { + ButtonCase1(); + } else if (name === routes[6].name) { + ButtonCase2(); + } else if (name === routes[7].name) { + HoverButtonExample(); } } diff --git a/ArkUIKit/ChooseComponent/entry/src/main/ets/pages/button/SetButtonType.ets b/ArkUIKit/ChooseComponent/entry/src/main/ets/pages/button/SetButtonType.ets index 489944cc9..7d397b7d7 100644 --- a/ArkUIKit/ChooseComponent/entry/src/main/ets/pages/button/SetButtonType.ets +++ b/ArkUIKit/ChooseComponent/entry/src/main/ets/pages/button/SetButtonType.ets @@ -1,5 +1,5 @@ /* - * Copyright (c) 2024 Huawei Device Co., Ltd. + * Copyright (c) 2024-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 @@ -35,6 +35,13 @@ export struct SetButtonType { Button('Button', { type: ButtonType.Capsule }) .id('Capsule') // [End create_capsule_button] + + // [Start create_capsule_button2] + Button('Disable', { type: ButtonType.Capsule, stateEffect: false }) + .backgroundColor(0x317aff) + .width(90) + .height(40) + // [End create_capsule_button2] } ComponentCard({ @@ -46,6 +53,13 @@ export struct SetButtonType { .id('Circle') .width(80) // [End create_circle_button] + + // [Start create_circle_button2] + Button('Circle', { type: ButtonType.Circle, stateEffect: false }) + .backgroundColor(0x317aff) + .width(90) + .height(90) + // [End create_circle_button2] } ComponentCard({ @@ -56,6 +70,14 @@ export struct SetButtonType { Button('Button', { type: ButtonType.Normal }) .id('Normal') // [End create_normal_button] + + // [Start create_normal_button2] + Button('Ok', { type: ButtonType.Normal, stateEffect: true }) + .borderRadius(8) + .backgroundColor(0x317aff) + .width(90) + .height(40) + // [End create_normal_button2] } ComponentCard({ @@ -64,6 +86,12 @@ export struct SetButtonType { }) { Button('Button', { type: ButtonType.ROUNDED_RECTANGLE }) .id('Round') + + // [Start create_rounded_rectangle_button] + Button('Disable', { type: ButtonType.ROUNDED_RECTANGLE, stateEffect: true }) + .backgroundColor(0x317aff) + .width(90) + // [End create_rounded_rectangle_button] } } .width('100%') diff --git a/ArkUIKit/ChooseComponent/entry/src/main/resources/base/element/string.json b/ArkUIKit/ChooseComponent/entry/src/main/resources/base/element/string.json index 7de4f7438..682837839 100644 --- a/ArkUIKit/ChooseComponent/entry/src/main/resources/base/element/string.json +++ b/ArkUIKit/ChooseComponent/entry/src/main/resources/base/element/string.json @@ -112,6 +112,10 @@ "name": "SetButtonType_titleFour", "value": "圆角矩形按钮" }, + { + "name": "SetButtonType_titleFive", + "value": "创建功能型按钮" + }, { "name": "SetButtonType_description", "value": "Button 组件的类型的设置,共有四种类型:胶囊按钮、圆形按钮、普通按钮、圆角矩形按钮。" @@ -132,6 +136,10 @@ "name": "SetButtonType_descriptionFour", "value": "通过type属性为ButtonType.ROUNDED_RECTANGLE,将按钮类型设置为圆角矩形按钮。" }, + { + "name": "SetButtonType_descriptionFive", + "value": "创建删除操作的按钮。" + }, { "name": "ButtonCustomStyle_test", "value": "按钮样式" @@ -207,6 +215,30 @@ "name": "toggle", "value": "切换按钮/Toggle" }, + { + "name": "ButtonCase1_title", + "value": "启动操作" + }, + { + "name": "ButtonCase1_desc", + "value": "可以用按钮启动任何用户界面元素,按钮会根据用户的操作触发相应的事件。" + }, + { + "name": "ButtonCase2_title", + "value": "提交表单" + }, + { + "name": "ButtonCase2_desc", + "value": "在用户登录/注册页面,使用按钮进行登录或注册操作" + }, + { + "name": "HoverButtonExample_title", + "value": "悬浮按钮" + }, + { + "name": "HoverButtonExample_desc", + "value": "在可以滑动的界面,滑动时按钮始终保持悬浮状态" + }, { "name": "RadioSample2_title", "value": "单选框示例2" diff --git a/ArkUIKit/ChooseComponent/entry/src/ohosTest/ets/test/Index.test.ets b/ArkUIKit/ChooseComponent/entry/src/ohosTest/ets/test/Index.test.ets index 40ebdd1f0..05d6f070e 100644 --- a/ArkUIKit/ChooseComponent/entry/src/ohosTest/ets/test/Index.test.ets +++ b/ArkUIKit/ChooseComponent/entry/src/ohosTest/ets/test/Index.test.ets @@ -70,6 +70,12 @@ export default function IndexTest() { expect(button_back === null).assertFalse(); await button_normal.click(); await button_back.click(); + + let buttons = await driver.findComponents(ON.type('Button')) + let ok_normal = buttons[1] + let loading_button = buttons[3] + await ok_normal.click(); + await loading_button.click(); await driver.pressBack(); await driver.pressBack(); done(); @@ -98,6 +104,12 @@ export default function IndexTest() { await button_Circle.click(); await button_Normal.click(); await button_Round.click(); + + let buttons = await driver.findComponents(ON.type('Button')) + await buttons[1].click(); + await buttons[3].click(); + await buttons[5].click(); + await buttons[7].click(); await driver.pressBack(); await driver.pressBack(); done(); @@ -123,6 +135,13 @@ export default function IndexTest() { await button_circle.click(); await button_font.click(); await button_color.click(); + + let buttons = await driver.findComponents(ON.type('Button')) + await buttons[1].click(); + await buttons[3].click(); + await buttons[5].click(); + await buttons[6].click(); + await driver.pressBack(); await driver.pressBack(); done(); @@ -183,6 +202,91 @@ export default function IndexTest() { done(); }) + it('testButtonCase1', 0, async (done: Function) => { + let driver = Driver.create(); + let button_list = await driver.findComponent(ON.text('Button', MatchPattern.CONTAINS)); + expect(button_list === null).assertFalse(); + await button_list.click(); + let str = await getResourceString($r('app.string.ButtonCase1_title')); + let button_search = await driver.findComponent(ON.text(str, MatchPattern.CONTAINS)); + expect(button_search === null).assertFalse(); + await button_search.click(); + let button_first = await driver.findComponent(ON.text('First', MatchPattern.CONTAINS)); + expect(button_first === null).assertFalse(); + await button_first.click(); + await driver.pressBack() + + let button_second = await driver.findComponent(ON.text('Second', MatchPattern.CONTAINS)); + expect(button_second === null).assertFalse(); + await button_second.click(); + await driver.pressBack() + + let button_third = await driver.findComponent(ON.text('Third', MatchPattern.CONTAINS)); + expect(button_third === null).assertFalse(); + await button_third.click(); + await driver.pressBack() + + await driver.pressBack(); + done(); + }) + + it('testButtonCase2', 0, async (done: Function) => { + let driver = Driver.create(); + let button_list = await driver.findComponent(ON.text('Button', MatchPattern.CONTAINS)); + expect(button_list === null).assertFalse(); + await button_list.click(); + let str = await getResourceString($r('app.string.ButtonCase2_title')); + let button_search = await driver.findComponent(ON.text(str, MatchPattern.CONTAINS)); + expect(button_search === null).assertFalse(); + await button_search.click(); + let input_buttons = await driver.findComponents(ON.type('TextInput')) + let username = input_buttons[0] + let password = input_buttons[1] + let registerButton = await driver.findComponent(ON.text('Register', MatchPattern.CONTAINS)); + let okButton = await driver.findComponent(ON.text('Ok', MatchPattern.CONTAINS)); + expect(username === null).assertFalse(); + expect(password === null).assertFalse(); + expect(registerButton === null).assertFalse(); + expect(okButton === null).assertFalse(); + await username.inputText('username'); + await password.inputText('password'); + expect(await username.getText() === 'username').assertTrue(); + + let point = await password.getBoundsCenter(); + await driver.mouseClick({ + x: point.x + 300, y: point.y + }, MouseButton.MOUSE_BUTTON_LEFT, 0, 0); + expect(await password.getText() === 'password').assertTrue(); + await registerButton.click(); + await okButton.click(); + await driver.pressBack(); + await driver.pressBack(); + await driver.pressBack(); + done(); + }) + + + it('testHoverButtonExample', 0, async (done: Function) => { + let driver = Driver.create(); + let button_list = await driver.findComponent(ON.text('Button', MatchPattern.CONTAINS)); + expect(button_list === null).assertFalse(); + await button_list.click(); + let str = await getResourceString($r('app.string.HoverButtonExample_title')); + let button_search = await driver.findComponent(ON.text(str, MatchPattern.CONTAINS)); + expect(button_search === null).assertFalse(); + await button_search.click(); + + let floatingButton = await driver.findComponent(ON.id('Button')); + let stackList = await driver.findComponent(ON.id('List')); + expect(floatingButton === null).assertFalse(); + expect(stackList === null).assertFalse(); + await floatingButton.click(); + await stackList.scrollToBottom(); + await driver.pressBack(); + await driver.pressBack(); + done(); + }) + it('testToggleUiExample1', 0, async (done: Function) => { let driver: Driver = Driver.create(); let button_list = await driver.findComponent(ON.text('Toggle', MatchPattern.CONTAINS)); diff --git a/ArkUIKit/ChooseComponent/ohosTest.md b/ArkUIKit/ChooseComponent/ohosTest.md index 95d1ceb49..ac419f406 100644 --- a/ArkUIKit/ChooseComponent/ohosTest.md +++ b/ArkUIKit/ChooseComponent/ohosTest.md @@ -1,5 +1,20 @@ + +# Button 测试用例归档 + +## 用例表 + +| 测试功能 | 预置条件 | 输入 | 预期输出 | 是否自动 | 测试结果 | +|---------------------------------| -------------- |-------------------------------------------------------|-----------------------------------| :------- | -------- | +| 悬浮按钮 | 设备正常运行 | 进入示例页面,点击"Button"按钮,滚动到底部,返回 | 在可以滑动的界面,滑动时按钮始终保持悬浮状态 | 是 | Pass | +| 按钮用于启动操作 | 设备正常运行 | 进入示例页面,点击"First"按钮,返回。点击"Second"按钮,返回 。点击"Third"按钮,返回 | 可以用按钮启动任何用户界面元素,按钮会根据用户的操作触发相应的事件 | 是 | Pass | +| 按钮用于提交表单 | 设备正常运行 | 进入示例页面,输入用户名和密码,点击"Register"按钮,返回 | 在用户登录/注册页面,使用按钮进行登录或注册操作 | 是 | Pass | +| 按钮用于提交表单 | 设备正常运行 | 进入示例页面,输入用户名和密码,点击"Register"按钮,返回 | 在用户登录/注册页面,使用按钮进行登录或注册操作 | 是 | Pass | + +# Radio 测试用例归档 + | 组件 | 测试功能 | 预置条件 | 输入 | 预期输出 | 测试结果 | |-----------------------------------| ------------ | ---------------------- |-----------| -------- | -------- | | Radio | 首页加载测试 | 设备正常运行 | 验证基础元素展示 | 检查标题和列表组件 | Pass | | Radio | 单选框示例示例页面加载,页面按钮响应 | 设备正常运行 | 1. 点击"单选框示例示例"。
2. 单选框示例示例页面分别点击ratio按钮:
点击"Ringing"按钮,提示词“Ringing",打印文字”Ringing mode."
点击"Vibration"按钮,提示词“Vibration",打印文字”Vibration mode."
点击"Silent"按钮,提示词“Silent",打印文字”Silent mode." | 页面加载成功
按钮点击响应正常 | Pass | -| Radio | 单选框示例2页面 | 设备正常运行 | 点击"单选框示例2" | 页面加载成功 | Pass | \ No newline at end of file +| Radio | 单选框示例2页面 | 设备正常运行 | 点击"单选框示例2" | 页面加载成功 | Pass | + diff --git a/ArkUIKit/DialogProject/.gitignore b/ArkUIKit/DialogProject/.gitignore new file mode 100644 index 000000000..d2ff20141 --- /dev/null +++ b/ArkUIKit/DialogProject/.gitignore @@ -0,0 +1,12 @@ +/node_modules +/oh_modules +/local.properties +/.idea +**/build +/.hvigor +.cxx +/.clangd +/.clang-format +/.clang-tidy +**/.test +/.appanalyzer \ No newline at end of file diff --git a/ArkUIKit/DialogProject/README_zh.md b/ArkUIKit/DialogProject/README_zh.md index fe49c9e72..71f6b5827 100644 --- a/ArkUIKit/DialogProject/README_zh.md +++ b/ArkUIKit/DialogProject/README_zh.md @@ -2,7 +2,7 @@ ### 介绍 -本示例通过使用[ArkUI指南文档](https://gitcode.com/openharmony/docs/tree/master/zh-cn/application-dev/ui)中各场景的开发示例,展示在工程中,帮助开发者更好地理解ArkUI提供的组件及组件属性并合理使用。该工程中展示的代码详细描述可查如下链接: +本示例通过使用[ArkUI指南文档](https://gitCode.com/openharmony/docs/tree/master/zh-cn/application-dev/ui)中各场景的开发示例,展示在工程中,帮助开发者更好地理解ArkUI提供的组件及组件属性并合理使用。该工程中展示的代码详细描述可查如下链接: 1. [不依赖UI组件的全局自定义弹出框 (openCustomDialog)](https://gitcode.com/openharmony/docs/blob/OpenHarmony-5.0.1-Release/zh-cn/application-dev/ui/arkts-uicontext-custom-dialog.md)。 2. [基础自定义弹出框 (CustomDialog)](https://gitcode.com/openharmony/docs/blob/OpenHarmony-5.0.1-Release/zh-cn/application-dev/ui/arkts-common-components-custom-dialog.md)。 @@ -11,6 +11,7 @@ 5. [气泡提示 (Popup)](https://gitcode.com/openharmony/docs/blob/OpenHarmony-5.0.1-Release/zh-cn/application-dev/ui/arkts-popup-and-menu-components-popup.md) 6. [即时反馈 (Toast)](https://gitcode.com/openharmony/docs/blob/OpenHarmony-5.0.1-Release/zh-cn/application-dev/ui/arkts-create-toast.md) 7. [设置浮层 (OverlayManager)](https://gitcode.com/openharmony/docs/blob/master/zh-cn/application-dev/ui/arkts-create-overlaymanager.md) +8. [弹出框蒙层控制](https://gitcode.com/openharmony/docs/blob/OpenHarmony-6.0-Release/zh-cn/application-dev/ui/arkts-dialog-mask.md) ### 效果预览 | 首页 | 弹窗类组件目录 | 自定义弹窗示例 | | | @@ -34,28 +35,50 @@ entry/src/main/ets/ |---pages | |---customdialog //自定义弹出框 | | |---CreateCustomDialog.ets +| | |---CreateCustomDialog1.ets | | |---DialogAnimation.ets +| | |---DialogAnimation1.ets +| | |---DialogAvoidSoftKeyboard.ets | | |---DialogInteraction.ets | | |---DialogInteraction1.ets +| | |---DialogInteraction2.ets +| | |---DialogInteraction3.ets | | |---DialogStyle.ets +| | |---DialogStyle1.ets +| | |---DialogWithPhysicalBack.ets +| | |---GetDialogStatus.ets | | |---Index.ets +| | |---Index2.ets | | |---NestDialog.ets +| | |---NestDialog1.ets | |---fixedstyledialog //固定样式弹出框 | | |---ActionSheet.ets | | |---AlertDialog.ets | | |---CalendarPickerDialog.ets | | |---DatePickerDialog.ets +| | |---DatePickerCustomDialog.ets | | |---Index.ets | | |---ShowActionMenu.ets | | |---ShowDialog.ets | | |---TextPickerDialog.ets | | |---TimePickerDialog.ets +| |---maskdialog //弹出框蒙层控制 +| | |---CustomDialogAnimation.ets +| | |---CustomDialogControl.ets +| | |---Index.ets | |---Menu //菜单 +| | |---BindComponentMenu.ets //基于绑定组件指定位置弹出菜单 | | |---CreateMenu.ets +| | |---EventTransSubWindowMenu.ets //控制子窗菜单的事件透传 | | |---Index.ets +| | |---PopVibrateMenu.ets //菜单弹出时振动效果 +| | |---SupportAvoidCentralAxisMenu.ets //菜单支持避让中轴 | |---opencustomdialog //不依赖UI组件的全局自定义弹出框 | | |---Index.ets | | |---openCustomDialog.ets +| | |---customDialogComponentWithTransition.ets +| | |---customDialogWithKeyboardAvoidDistance.ets +| | |---OpenDialogAndUpdate.ets | |---OverlayManager //设置浮层 | | |---Index.ets | | |---OverlayManagerDemo1.ets @@ -66,8 +89,11 @@ entry/src/main/ets/ | | |---CustomPopup.ets | | |---Index.ets | | |---PopupAnimation.ets +| | |---PopupAvoidSoftKeyboard.ets //气泡避让软键盘示例 +| | |---PopupPolymorphicEffect.ets //设置气泡内的多态效果示例 | | |---PopupStateChange.ets | | |---PopupStyle.ets +| | |---PopupSupportedAvoidAxis.ets //气泡支持避让中轴示例 | | |---TextPrompts.ets | |---Toast //即使反馈 | | |---CreateToast.ets @@ -85,15 +111,56 @@ entry/src/ohosTest/ 1. 设置浮层(OverlayManager):可以通过使用UIContext中的getOverlayManager方法获取当前UI上下文关联的OverlayManager对象,再通过该对象调用对应方法。 - * 在OverlayManager上新增指定节点、删除指定节点、显示所有节点和隐藏所有节点。代码参考[OverlayManagerDemo1.ets](https://gitcode.com/openharmony/applications_app_samples/tree/master/code/DocsSample/ArkUISample/DialogProject/entry/src/main/ets/pages/OverlayManager/OverlayManagerDemo1.ets) + * 在OverlayManager上新增指定节点、删除指定节点、显示所有节点和隐藏所有节点。代码参考[OverlayManagerDemo1.ets](https://gitcode.com/openharmony/applications_app_samples/tree/master/code/DocsSample/ArkUISample/DialogProject/entry/src/main/ets/pages/OverlayManager/OverlayManagerDemo1.ets) - * 显示一个始终在屏幕左侧的悬浮球,点击可以弹出alertDialog弹窗。代码参考[OverlayManagerDemo2.ets](https://gitcode.com/openharmony/applications_app_samples/tree/master/code/DocsSample/ArkUISample/DialogProject/entry/src/main/ets/pages/OverlayManager/OverlayManagerDemo2.ets) + * 显示一个始终在屏幕左侧的悬浮球,点击可以弹出alertDialog弹窗。代码参考[OverlayManagerDemo2.ets](https://gitcode.com/openharmony/applications_app_samples/tree/master/code/DocsSample/ArkUISample/DialogProject/entry/src/main/ets/pages/OverlayManager/OverlayManagerDemo2.ets) - * 调用UIContext中getOverlayManager方法获取OverlayManager对象,并利用该对象在指定层级上新增指定节点(addComponentContentWithOrder),层次高的浮层会覆盖在层级低的浮层之上。代码参考[OverlayManagerDemo3.ets](https://gitcode.com/openharmony/applications_app_samples/tree/master/code/DocsSample/ArkUISample/DialogProject/entry/src/main/ets/pages/OverlayManager/OverlayManagerDemo3.ets) + * 调用UIContext中getOverlayManager方法获取OverlayManager对象,并利用该对象在指定层级上新增指定节点(addComponentContentWithOrder),层次高的浮层会覆盖在层级低的浮层之上。代码参考[OverlayManagerDemo3.ets](https://gitcode.com/openharmony/applications_app_samples/tree/master/code/DocsSample/ArkUISample/DialogProject/entry/src/main/ets/pages/OverlayManager/OverlayManagerDemo3.ets) -### 相关权限 +2. 气泡提示(Popup) -不涉及。 + * 气泡分为两种类型,一种是系统提供的气泡PopupOptions,一种是开发者可以自定义的气泡CustomPopupOptions。其中,PopupOptions通过配置primaryButton和secondaryButton来设置带按钮的气泡;CustomPopupOptions通过配置builder来设置自定义的气泡。其中系统提供的气泡PopupOptions,字体的最大放大倍数为2。 + + * 气泡可以通过配置mask来实现模态和非模态窗口,mask为true或者颜色值的时候,气泡为模态窗口,mask为false时,气泡为非模态窗口。 + + * 多个气泡同时弹出时,子窗内显示的气泡比主窗内显示的气泡层级高,所处窗口相同时,后面弹出的气泡层级比先弹出的气泡层级高。 + +3. 菜单控制(Menu) + + * Menu是菜单接口,一般用于鼠标右键弹窗、点击弹窗等。具体用法请参考菜单控制。 + + * 使用bindContextMenu并设置预览图,菜单弹出时有蒙层,此时为模态。 + + * 使用bindMenu或bindContextMenu未设置预览图时,菜单弹出无蒙层,此时为非模态。 + +4. 基础自定义弹出框 (CustomDialog) + + * CustomDialog是自定义弹出框,可用于广告、中奖、警告、软件更新等与用户交互响应操作。 + + * 开发者可以通过CustomDialogController类显示自定义弹出框。具体用法请参考自定义弹出框。 + + * 默认为模态弹窗且有蒙层,不可与蒙层下方控件进行交互(不支持点击和手势等向下透传)。 + + * 可以通过配置CustomDialogControllerOptions中的isModal属性来实现模态和非模态弹窗,详细说明可参考弹窗的种类。 + +5. 不依赖UI组件的全局自定义弹出框 (openCustomDialog) + + * 推荐使用UIContext中获取到的PromptAction对象提供的openCustomDialog接口在相对应用复杂的场景来实现自定义弹出框,相较于CustomDialogController优势点在于页面解耦,支持动态刷新。 + + * 弹出框(openCustomDialog)默认为模态弹窗且有蒙层,不可与蒙层下方控件进行交互(不支持点击和手势等向下透传)。 + + * 可以通过配置promptAction.BaseDialogOptions类型中的isModal属性来实现模态和非模态弹窗,详细说明可参考弹窗的种类。 + + * 当isModal为true时,弹出框为模态弹窗,且弹窗周围的蒙层区不支持透传。isModal为false时,弹出框为非模态弹窗,且弹窗周围的蒙层区可以透传。因此如果需要同时允许弹出框的交互和弹出框外页面的交互行为,需要将弹出框设置为非模态。 + +5. 弹出框蒙层控制(MaskDialog) + + * 开发者对弹出框的定制不仅限于弹出框里的内容,对弹出框蒙层的定制需求也逐渐增加。 + + * 本文介绍ArkUI弹出框的蒙层控制,包括点击蒙层时是否消失、蒙层区域、蒙层颜色和蒙层动画等特性。 + +### 相关权限 + 不涉及。 ### 依赖 @@ -103,9 +170,9 @@ entry/src/ohosTest/ 1.本示例仅支持标准系统上运行, 支持设备:RK3568。 -2.本示例为Stage模型,支持API18版本SDK,版本号:5.1.0.56,镜像版本号:OpenHarmony_5.1.0.56。 +2.本示例为Stage模型,支持API22版本full-SDK,版本号:6.0.0.47,镜像版本号:OpenHarmony_6.0.0 Release。 -3.本示例需要使用DevEco Studio NEXT Developer Preview2 (Build Version: 5.0.5.306, built on December 12, 2024)及以上版本才可编译运行。 +3.本示例需要使用DevEco Studio 6.0.0 Release (Build Version: 6.0.0.858, built on September 24, 2025)及以上版本才可编译运行。 ### 下载 @@ -115,6 +182,6 @@ entry/src/ohosTest/ git init git config core.sparsecheckout true echo code/DocsSample/ArkUISample/DialogProject > .git/info/sparse-checkout -git remote add origin https://gitcode.com/openharmony/applications_app_samples.git +git remote add origin https://gitCode.com/openharmony/applications_app_samples.git git pull origin master ```` \ No newline at end of file diff --git a/ArkUIKit/DialogProject/entry/src/main/ets/common/PromptActionClass1.ts b/ArkUIKit/DialogProject/entry/src/main/ets/common/PromptActionClass1.ts new file mode 100644 index 000000000..904a0d400 --- /dev/null +++ b/ArkUIKit/DialogProject/entry/src/main/ets/common/PromptActionClass1.ts @@ -0,0 +1,86 @@ +/* + * 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. + */ + +// [Start prompt_action_class1] +// PromptActionClass1.ets +import { BusinessError } from '@kit.BasicServicesKit'; +import { ComponentContent, promptAction, UIContext } from '@kit.ArkUI'; + +export class PromptActionClass1 { + static ctx: UIContext; + static contentNode: ComponentContent; + static options: promptAction.BaseDialogOptions; + + static setContext(context: UIContext) { + PromptActionClass1.ctx = context; + } + + static setContentNode(node: ComponentContent) { + PromptActionClass1.contentNode = node; + } + + static setOptions(options: promptAction.BaseDialogOptions) { + PromptActionClass1.options = options; + } + + static openDialog() { + if (PromptActionClass1.contentNode !== null) { + // [Start prompt_action_class_open_custom_dialog] + PromptActionClass1.ctx.getPromptAction().openCustomDialog(PromptActionClass1.contentNode, PromptActionClass1.options) + .then(() => { + console.info('OpenCustomDialog complete.'); + }) + .catch((error: BusinessError) => { + let message = (error as BusinessError).message; + let code = (error as BusinessError).code; + console.error(`OpenCustomDialog args error code is ${code}, message is ${message}`); + }) + // [End prompt_action_class_open_custom_dialog] + } + } + + static closeDialog() { + if (PromptActionClass1.contentNode !== null) { + // [Start prompt_action_class_close_custom_dialog] + PromptActionClass1.ctx.getPromptAction().closeCustomDialog(PromptActionClass1.contentNode) + .then(() => { + console.info('CloseCustomDialog complete.'); + }) + .catch((error: BusinessError) => { + let message = (error as BusinessError).message; + let code = (error as BusinessError).code; + console.error(`CloseCustomDialog args error code is ${code}, message is ${message}`); + }) + // [End prompt_action_class_close_custom_dialog] + } + } + + static updateDialog(options: promptAction.BaseDialogOptions) { + if (PromptActionClass1.contentNode !== null) { + // [Start prompt_action_class_update_options] + PromptActionClass1.ctx.getPromptAction().updateCustomDialog(PromptActionClass1.contentNode, options) + .then(() => { + console.info('UpdateCustomDialog complete.'); + }) + .catch((error: BusinessError) => { + let message = (error as BusinessError).message; + let code = (error as BusinessError).code; + console.error(`UpdateCustomDialog args error code is ${code}, message is ${message}`); + }) + // [End prompt_action_class_update_options] + } + } +} +// [End prompt_action_class1] \ No newline at end of file diff --git a/ArkUIKit/DialogProject/entry/src/main/ets/pages/Index.ets b/ArkUIKit/DialogProject/entry/src/main/ets/pages/Index.ets index 25b508393..70d3ac112 100644 --- a/ArkUIKit/DialogProject/entry/src/main/ets/pages/Index.ets +++ b/ArkUIKit/DialogProject/entry/src/main/ets/pages/Index.ets @@ -23,6 +23,7 @@ import { MenuDestination, Menu_ROUTE_PREFIX } from './Menu/Index'; import { CustomDialogDestination, CustomDialog_ROUTE_PREFIX } from './opencustomdialog/Index'; import { PopupDestination, Popup_ROUTE_PREFIX } from './popup/Index'; import { ToastDestination, Toast_ROUTE_PREFIX } from './Toast/Index'; +import { MaskDestination, Mask_ROUTE_PREFIX } from './maskdialog/Index'; import { OverlayManagerDestination, OverlayManager_ROUTE_PREFIX } from './OverlayManager/Index'; const routes: Route[] = [ @@ -38,6 +39,10 @@ const routes: Route[] = [ title: resource.resourceToString($r('app.string.FixedStyleDialog1')), name: Fixed_ROUTE_PREFIX }, + { + title: resource.resourceToString($r('app.string.MaskDialog')), + name: Mask_ROUTE_PREFIX + }, { title: resource.resourceToString($r('app.string.Menu1')), name: Menu_ROUTE_PREFIX @@ -70,6 +75,8 @@ function Destination(name: string) { ToastDestination(name); } else if (name.startsWith(Popup_ROUTE_PREFIX)) { PopupDestination(name); + } else if (name.startsWith(Mask_ROUTE_PREFIX)) { + MaskDestination(name); } else if (name.startsWith(OverlayManager_ROUTE_PREFIX)) { OverlayManagerDestination(name); } diff --git a/ArkUIKit/DialogProject/entry/src/main/ets/pages/Menu/BindComponentMenu.ets b/ArkUIKit/DialogProject/entry/src/main/ets/pages/Menu/BindComponentMenu.ets new file mode 100644 index 000000000..02ba747a2 --- /dev/null +++ b/ArkUIKit/DialogProject/entry/src/main/ets/pages/Menu/BindComponentMenu.ets @@ -0,0 +1,56 @@ +/* + * 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. + */ +// [Start bindComponent_menu] +@Entry +@Component +export struct BindComponentMenuExample { + @Builder + MenuBuilder() { + Column() { + Menu() { + MenuItemGroup() { + // $r('app.media.app_icon')需要替换为开发者所需的图像资源文件。 + MenuItem({ startIcon: $r('app.media.app_icon'), content: 'Select Mixed Menu 1', labelInfo: '' }) + MenuItem({ startIcon: $r('app.media.app_icon'), content: 'Select Mixed Menu 2', labelInfo: '' }) + MenuItem({ startIcon: $r('app.media.app_icon'), content: 'Select Mixed Menu 3', labelInfo: '' }) + } + } + } + } + + build() { + NavDestination() { + Column() { + Text() + .borderRadius(10) + .width(200) + .height(150) + .borderWidth(1) + .backgroundColor(Color.White) + .borderColor(Color.Red) + .margin({ top: 200, left: 125 }) + .bindContextMenu(this.MenuBuilder, ResponseType.RightClick, { + anchorPosition: { x: 45, y: 50 }, + }) + } + .alignItems(HorizontalAlign.Start) + .width('100%') + .height('100%') + .backgroundColor('#F5F5F5') + }.backgroundColor('#f1f2f3') + .title($r('app.string.BindComponentMenu_title')) + } +} +// [End bindComponent_menu] \ No newline at end of file diff --git a/ArkUIKit/DialogProject/entry/src/main/ets/pages/Menu/EventTransSubWindowMenu.ets b/ArkUIKit/DialogProject/entry/src/main/ets/pages/Menu/EventTransSubWindowMenu.ets new file mode 100644 index 000000000..6d6ff0907 --- /dev/null +++ b/ArkUIKit/DialogProject/entry/src/main/ets/pages/Menu/EventTransSubWindowMenu.ets @@ -0,0 +1,57 @@ +/* + * 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. + */ +// [Start eventTrans_menu] +@Entry +@Component +export struct EventTransSubWindowMenuExample { + build() { + NavDestination() { + Column() { + } + .id('click') + .bindContextMenu(this.contextMenuBuilder, ResponseType.RightClick, { + modalMode: ModalMode.TARGET_WINDOW + }) + .onClick(() => { + this.getUIContext().getPromptAction().showToast({ + message: 'Clicked!' + }) + }) + .width('100%') + .height('100%') + }.backgroundColor('#f1f2f3') + // $r('app.string.EventTransSubWindowMenu_title')需要替换为开发者所需的资源文件。 + .title($r('app.string.EventTransSubWindowMenu_title')) + } + + @Builder + bindMenuBuilder() { + Menu() { + MenuItem({ content: 'bindMenu item' }) { + + } + } + } + + @Builder + contextMenuBuilder() { + Menu() { + MenuItem({ content: 'contextMenu item' }) { + + } + } + } +} +// [End eventTrans_menu] \ No newline at end of file diff --git a/ArkUIKit/DialogProject/entry/src/main/ets/pages/Menu/Index.ets b/ArkUIKit/DialogProject/entry/src/main/ets/pages/Menu/Index.ets index 60c4eca1d..66401c68f 100644 --- a/ArkUIKit/DialogProject/entry/src/main/ets/pages/Menu/Index.ets +++ b/ArkUIKit/DialogProject/entry/src/main/ets/pages/Menu/Index.ets @@ -18,7 +18,10 @@ import resource from '../../common/resource'; import { Route } from '../../common/Route'; import { menuExample } from './CreateMenu'; import { OpenPopup } from './globalmenusindependentofuicomponents//GlobalOpenMenu'; - +import { PopVibrateMenuExample } from './PopVibrateMenu'; +import { SupportAvoidCentralAxisMenuExample } from './SupportAvoidCentralAxisMenu'; +import { EventTransSubWindowMenuExample } from './EventTransSubWindowMenu'; +import { BindComponentMenuExample } from './BindComponentMenu' export const Menu_ROUTE_PREFIX: string = 'Menu_ROUTE_PREFIX'; @@ -32,6 +35,26 @@ const routes: Route[] = [ name: `${Menu_ROUTE_PREFIX}/OpenMenu`, title: resource.resourceToString($r('app.string.OpenMenu_title')), description: $r('app.string.OpenMenu_des'), + }, + { + name: `${Menu_ROUTE_PREFIX}/PopVibrateMenu`, + title: resource.resourceToString($r('app.string.PopVibrateMenu_title')), + description: $r('app.string.PopVibrateMenu_des'), + }, + { + name: `${Menu_ROUTE_PREFIX}/SupportAvoidCentralAxisMenu`, + title: resource.resourceToString($r('app.string.SupportAvoidCentralAxisMenu_title')), + description: $r('app.string.SupportAvoidCentralAxisMenu_des'), + }, + { + name: `${Menu_ROUTE_PREFIX}/EventTransSubWindowMenu`, + title: resource.resourceToString($r('app.string.EventTransSubWindowMenu_title')), + description: $r('app.string.EventTransSubWindowMenu_des'), + }, + { + name: `${Menu_ROUTE_PREFIX}/BindComponentMenu`, + title: resource.resourceToString($r('app.string.BindComponentMenu_title')), + description: $r('app.string.BindComponentMenu_des'), } ] @@ -41,8 +64,16 @@ export function MenuDestination(name: string) { MenuExample(); } else if (name === routes[0].name) { menuExample(); - } else if (name === routes[1].name) { + } else if (name === routes[1].name) { OpenPopup(); + } else if (name === routes[2].name) { + PopVibrateMenuExample(); + } else if (name === routes[3].name) { + SupportAvoidCentralAxisMenuExample(); + } else if (name === routes[4].name) { + EventTransSubWindowMenuExample(); + } else if (name === routes[5].name) { + BindComponentMenuExample(); } } diff --git a/ArkUIKit/DialogProject/entry/src/main/ets/pages/Menu/PopVibrateMenu.ets b/ArkUIKit/DialogProject/entry/src/main/ets/pages/Menu/PopVibrateMenu.ets new file mode 100644 index 000000000..468949595 --- /dev/null +++ b/ArkUIKit/DialogProject/entry/src/main/ets/pages/Menu/PopVibrateMenu.ets @@ -0,0 +1,99 @@ +/* + * 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 { PromptAction } from '@kit.ArkUI'; + +// $r('app.media.xxx')需要替换为开发者所需的资源文件。 +// $r('app.string.xxx')需要替换为开发者所需的资源文件。 +class Tmp { + private iconStr2: ResourceStr = $r('app.media.app_icon') + + set(val: Resource) { + this.iconStr2 = val; + } +} + +@Entry +@Component +export struct PopVibrateMenuExample { + @State select: boolean = true; + private iconStr: ResourceStr = $r('app.media.app_icon'); + private iconStr2: ResourceStr = $r('app.media.app_icon'); + + @Builder + SubMenu() { + Menu() { + MenuItem({ content: 'copy', labelInfo: 'Ctrl+C' }) + MenuItem({ content: 'paste', labelInfo: 'Ctrl+V' }) + } + } + + @Builder + MyMenu() { + Menu() { + MenuItem({ startIcon: $r('app.media.app_icon'), content: $r('app.string.menu_single') }) + MenuItem({ startIcon: $r('app.media.app_icon'), content: $r('app.string.menu_forbid') }).enabled(false) + MenuItem({ + startIcon: this.iconStr, + content: $r('app.string.menu_more'), + endIcon: $r('app.media.app_icon'), + // 当builder参数进行配置时,表示与menuItem项绑定了子菜单。鼠标hover在该菜单项时,会显示子菜单。 + builder: this.SubMenu + }) + MenuItemGroup({ header: $r('app.string.menu_subtitle') }) { + MenuItem({ content: $r('app.string.menu_selection') }) + .selectIcon(true) + .selected(this.select) + .onChange((selected) => { + console.info('menuItem select' + selected); + let str: Tmp = new Tmp(); + str.set($r('app.media.app_icon')); + }) + MenuItem({ + startIcon: $r('app.media.app_icon'), + content: $r('app.string.menu_more'), + endIcon: $r('app.media.foreground'), + builder: this.SubMenu + }) + } + + MenuItem({ + startIcon: this.iconStr2, + content: $r('app.string.menu_single'), + endIcon: $r('app.media.app_icon') + }) + } + } + build() { + NavDestination() { + Column({ space: 12 }) { + + // [Start popVibrate_menu] + Button($r('app.string.Click_for_menu')) + .id('click for Menu') + .bindContextMenu(this.MyMenu, ResponseType.RightClick, { hapticFeedbackMode: HapticFeedbackMode.ENABLED}) + // [End popVibrate_menu] + .width(160) + .height(50) + + } + .width('100%') + .height('100%') + .padding({ left: 12, right: 12 }) + } + .backgroundColor('#f1f2f3') + .title($r('app.string.PopVibrateMenu_title')) + } +} \ No newline at end of file diff --git a/ArkUIKit/DialogProject/entry/src/main/ets/pages/Menu/SupportAvoidCentralAxisMenu.ets b/ArkUIKit/DialogProject/entry/src/main/ets/pages/Menu/SupportAvoidCentralAxisMenu.ets new file mode 100644 index 000000000..427885ab2 --- /dev/null +++ b/ArkUIKit/DialogProject/entry/src/main/ets/pages/Menu/SupportAvoidCentralAxisMenu.ets @@ -0,0 +1,121 @@ +/* + * 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. + */ + +// [Start avoid_central_axis_menu] +// $r('app.media.xxx')需要替换为开发者所需的资源文件。 +// $r('app.string.xxx')需要替换为开发者所需的资源文件。 +@Entry +@Component +export struct SupportAvoidCentralAxisMenuExample { + @State message: string = 'Hello World'; + @State upScreen: string = + this.getUIContext().getHostContext()?.resourceManager.getStringByNameSync('Upper_half_screen') as string; + @State middleAxle: string = + this.getUIContext().getHostContext()?.resourceManager.getStringByNameSync('Middle_axle') as string; + @State lowerScreen: string = + this.getUIContext().getHostContext()?.resourceManager.getStringByNameSync('Lower_half_screen') as string; + @State zone: string = + this.getUIContext().getHostContext()?.resourceManager.getStringByNameSync('zone') as string; + @State hoverModeStart: string = + this.getUIContext().getHostContext()?.resourceManager.getStringByNameSync('hoverMode_start') as string; + private iconStr: Resource = $r('app.media.startIcon'); + @State index: number = 0; + @State arrayStr: Array = [this.upScreen, this.middleAxle, this.lowerScreen]; + @State enableHoverMode: boolean | undefined = true; + @State showInSubwindow: boolean = false; + @State placement: Placement | undefined = undefined; + + @Builder + MyMenu1() { + Menu() { + MenuItem({ startIcon: this.iconStr, content: $r('app.string.menu_selection') }) + MenuItem({ startIcon: this.iconStr, content: $r('app.string.menu_selection') }) + MenuItem({ startIcon: this.iconStr, content: $r('app.string.menu_selection') }) + MenuItem({ startIcon: this.iconStr, content: $r('app.string.menu_selection') }) + } + } + + @State isShow: boolean = false; + + build() { + NavDestination() { + RelativeContainer() { + Column() { + Button(this.zone + this.arrayStr[this.index]) + .onClick(() => { + if (this.index < 2) { + this.index++ + } else { + this.index = 0 + } + }) + + Button(this.hoverModeStart + this.enableHoverMode) + .id('hoverMode_start') + .onClick(() => { + if (this.enableHoverMode === undefined) { + this.enableHoverMode = true + } else if (this.enableHoverMode === true) { + this.enableHoverMode = false + } else { + this.enableHoverMode = undefined + } + }) + + Button('MenuPlacement:' + this.placement) + .onClick(() => { + if (this.placement === undefined) { + this.placement = Placement.Bottom + } else if (this.placement === Placement.Bottom) { + this.placement = Placement.Top + } else { + this.placement = undefined + } + }) + } + + Row() { + Button('Menu') + .fontWeight(FontWeight.Bold) + .bindMenu(this.MyMenu1(), { + enableHoverMode: this.enableHoverMode, + showInSubWindow: this.showInSubwindow, + placement: this.placement + }) + + Select([{ value: 'text1' }, { value: 'text2' }, { value: 'text3' }, { value: 'text4' }, { value: 'text5' }, + { value: 'text6' }, { value: 'text7' }, { value: 'text8' }, { value: 'text9' }, { value: 'text10' }, + { value: 'text11' }, + { value: 'text12' }]) + .value('Select') + + } + .alignRules({ + center: { anchor: '__container__', align: VerticalAlign.Center }, + middle: { anchor: '__container__', align: HorizontalAlign.Center } + }) + .margin({ + top: this.index === 2 ? 330 : this.index === 1 ? 50 : 0, + bottom: this.index === 0 ? 330 : 0 + }) + } + .height('100%') + .width('100%') + } + .backgroundColor('#f1f2f3') + .title($r('app.string.SupportAvoidCentralAxisMenu_title')) + } +} +// [End avoid_central_axis_menu] \ No newline at end of file diff --git a/ArkUIKit/DialogProject/entry/src/main/ets/pages/customdialog/CreateCustomDialog1.ets b/ArkUIKit/DialogProject/entry/src/main/ets/pages/customdialog/CreateCustomDialog1.ets new file mode 100644 index 000000000..75495218c --- /dev/null +++ b/ArkUIKit/DialogProject/entry/src/main/ets/pages/customdialog/CreateCustomDialog1.ets @@ -0,0 +1,51 @@ +/* + * 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. + */ + +// [Start create_custom_dialog_1] +@CustomDialog +struct CustomDialogExample { + controller: CustomDialogController; + + build() { + Column() { + Text($r('app.string.i_am_content')) + .fontSize(20) + }.height(60).justifyContent(FlexAlign.Center) + } +} + +@Entry +@Component +export struct CreateCustomDialog1 { + dialogController: CustomDialogController = new CustomDialogController({ + builder: CustomDialogExample(), + }) + + build() { + // [StartExclude create_custom_dialog_1] + NavDestination() { + // [EndExclude create_custom_dialog_1] + Column() { + Button('click me') + .onClick(() => { + this.dialogController.open(); + }) + }.width('100%').margin({ top: 5 }) + // [StartExclude create_custom_dialog_1] + } + // [EndExclude create_custom_dialog_1] + } +} +// [End create_custom_dialog_1] diff --git a/ArkUIKit/DialogProject/entry/src/main/ets/pages/customdialog/DialogAnimation1.ets b/ArkUIKit/DialogProject/entry/src/main/ets/pages/customdialog/DialogAnimation1.ets new file mode 100644 index 000000000..fc7be7346 --- /dev/null +++ b/ArkUIKit/DialogProject/entry/src/main/ets/pages/customdialog/DialogAnimation1.ets @@ -0,0 +1,79 @@ +/* + * 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 { hilog } from '@kit.PerformanceAnalysisKit'; +const DOMAIN = 0x0000; +// [Start dialog_animation_1] +@CustomDialog +struct CustomDialogExample { + controller?: CustomDialogController; + + build() { + NavDestination() { + Column() { + Text('Whether to change a text?').fontSize(16).margin({ bottom: 10 }) + } + } + } +} + +@Entry +@Component +export struct DialogAnimation1 { + @State textValue: string = ''; + @State inputValue: string = 'click me'; + dialogController: CustomDialogController | null = new CustomDialogController({ + builder: CustomDialogExample(), + openAnimation: { + duration: 1200, + curve: Curve.Friction, + delay: 500, + playMode: PlayMode.Alternate, + onFinish: () => { + hilog.info(DOMAIN, 'testTag', 'play end') + } + }, + autoCancel: true, + alignment: DialogAlignment.Bottom, + offset: { dx: 0, dy: -20 }, + gridCount: 4, + customStyle: false, + backgroundColor: 0xd9ffffff, + cornerRadius: 10, + }); + + // 在自定义组件即将析构销毁时将dialogController置空 + aboutToDisappear() { + this.dialogController = null; // 将dialogController置空 + } + + build() { + // [StartExclude dialog_animation_1] + NavDestination() { + // [EndExclude dialog_animation_1] + Column() { + Button(this.inputValue) + .onClick(() => { + if (this.dialogController !== null) { + this.dialogController.open(); + } + }).backgroundColor(0x317aff) + }.width('100%').margin({ top: 5 }) + // [StartExclude dialog_animation_1] + } + // [EndExclude dialog_animation_1] + } +} +// [End dialog_animation_1] \ No newline at end of file diff --git a/ArkUIKit/DialogProject/entry/src/main/ets/pages/customdialog/DialogAvoidSoftKeyboard.ets b/ArkUIKit/DialogProject/entry/src/main/ets/pages/customdialog/DialogAvoidSoftKeyboard.ets new file mode 100644 index 000000000..1854516cd --- /dev/null +++ b/ArkUIKit/DialogProject/entry/src/main/ets/pages/customdialog/DialogAvoidSoftKeyboard.ets @@ -0,0 +1,74 @@ +/* + * 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. + */ + +// [Start dialog_avoid_soft_key_board] +// xxx.ets +import { LengthMetrics } from '@kit.ArkUI'; + +@CustomDialog +struct CustomDialogExample { + controller?: CustomDialogController; + build() { + Column() { + Column() { + Text('keyboardAvoidDistance: 0vp') + .fontSize(20) + .margin({ bottom: 36 }) + TextInput({ placeholder: '' }) + }.backgroundColor('#FFF0F0F0') + } + } +} + +@Entry +@Component +export struct DialogAvoidSoftKeyboard { + dialogController: CustomDialogController | null = new CustomDialogController({ + builder: CustomDialogExample({ + }), + autoCancel: true, + gridCount: 4, + showInSubWindow: true, + isModal: true, + customStyle: false, + cornerRadius: 30, + alignment:DialogAlignment.Bottom, + keyboardAvoidMode: KeyboardAvoidMode.DEFAULT, // 软键盘弹出时,弹出框自动避让 + keyboardAvoidDistance: LengthMetrics.vp(0) // 软键盘弹出时与弹出框的距离为0vp + }) + + build() { + // [StartExclude dialog_avoid_soft_key_board] + NavDestination() { + // [EndExclude dialog_avoid_soft_key_board] + Row() { + Row({ space: 20 }) { + Text($r('app.string.open_windows')) + .fontSize(30) + .onClick(() => { + if (this.dialogController !== null) { + this.dialogController.open(); + } + }) + } + .width('100%') + } + .height('100%') + // [StartExclude dialog_avoid_soft_key_board] + } + // [EndExclude dialog_avoid_soft_key_board] + } +} +// [End dialog_avoid_soft_key_board] \ No newline at end of file diff --git a/ArkUIKit/DialogProject/entry/src/main/ets/pages/customdialog/DialogInteraction1.ets b/ArkUIKit/DialogProject/entry/src/main/ets/pages/customdialog/DialogInteraction1.ets index f2d21b0f9..47ad82e05 100644 --- a/ArkUIKit/DialogProject/entry/src/main/ets/pages/customdialog/DialogInteraction1.ets +++ b/ArkUIKit/DialogProject/entry/src/main/ets/pages/customdialog/DialogInteraction1.ets @@ -25,7 +25,7 @@ struct CustomDialogExample { build() { Column() { - if (this.textValue != '') { + if (this.textValue !== '') { Text(`The next content is:${this.textValue}`) .padding({ top: 24, right: 24, left: 24 }) } else { @@ -42,7 +42,7 @@ struct CustomDialogExample { .lineHeight(21) } .onClick(() => { - if (this.controller != undefined) { + if (this.controller !== undefined) { this.controller.close(); this.cancel(); }; @@ -60,9 +60,9 @@ struct CustomDialogExample { .fontColor($r('sys.color.font_emphasize')) } .onClick(() => { - if (this.controller != undefined && this.textValue != '') { + if (this.controller !== undefined && this.textValue !== '') { this.controller.close(); - } else if (this.controller != undefined) { + } else if (this.controller !== undefined) { this.getUIContext().getRouter().pushUrl({ url: 'pages/Index2' }); @@ -134,7 +134,7 @@ export struct DialogInteraction1 { Column() { Button('click me') .onClick(() => { - if (this.dialogController != null) { + if (this.dialogController !== null) { this.dialogController.open(); } }).backgroundColor(0x317aff) diff --git a/ArkUIKit/DialogProject/entry/src/main/ets/pages/customdialog/DialogInteraction2.ets b/ArkUIKit/DialogProject/entry/src/main/ets/pages/customdialog/DialogInteraction2.ets new file mode 100644 index 000000000..62bc6d2c2 --- /dev/null +++ b/ArkUIKit/DialogProject/entry/src/main/ets/pages/customdialog/DialogInteraction2.ets @@ -0,0 +1,79 @@ +/* + * 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 { hilog } from '@kit.PerformanceAnalysisKit'; +const DOMAIN = 0x0000; +// [Start dialog_interaction_2] +@CustomDialog +struct CustomDialogExample { + cancel: () => void = () => { + } + confirm: () => void = () => { + } + controller: CustomDialogController; + + build() { + Column() { + Text($r('app.string.i_am_content')).fontSize(20).margin({ top: 10, bottom: 10 }) + Flex({ justifyContent: FlexAlign.SpaceAround }) { + Button('cancel') + .onClick(() => { + this.controller.close(); + if (this.cancel) { + this.cancel(); + } + }).backgroundColor(0xffffff).fontColor(Color.Black) + Button('confirm') + .onClick(() => { + this.controller.close(); + if (this.confirm) { + this.confirm(); + } + }).backgroundColor(0xffffff).fontColor(Color.Red) + }.margin({ bottom: 10 }) + } + } +} + +@Entry +@Component +export struct DialogInteraction2 { + dialogController: CustomDialogController = new CustomDialogController({ + builder: CustomDialogExample({ + cancel: ()=> { this.onCancel() }, + confirm: ()=> { this.onAccept() }, + }), + }); + + onCancel() { + hilog.info(DOMAIN, 'testTag', 'Callback when the first button is clicked'); + } + + onAccept() { + hilog.info(DOMAIN, 'testTag', 'Callback when the second button is clicked'); + } + + build() { + Column() { + NavDestination() { + Button('click me') + .onClick(() => { + this.dialogController.open(); + }) + }.width('100%').margin({ top: 5 }) + } + } +} +// [End dialog_interaction_2] \ No newline at end of file diff --git a/ArkUIKit/DialogProject/entry/src/main/ets/pages/customdialog/DialogInteraction3.ets b/ArkUIKit/DialogProject/entry/src/main/ets/pages/customdialog/DialogInteraction3.ets new file mode 100644 index 000000000..deefe611f --- /dev/null +++ b/ArkUIKit/DialogProject/entry/src/main/ets/pages/customdialog/DialogInteraction3.ets @@ -0,0 +1,115 @@ +/* + * 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 { hilog } from '@kit.PerformanceAnalysisKit'; +const DOMAIN = 0x0000; +// [Start dialog_interaction_3] +@CustomDialog +struct CustomDialogExample { + @Link textValue: string; + controller?: CustomDialogController; + cancel: () => void = () => { + } + confirm: () => void = () => { + } + + build() { + Column({ space: 20 }) { + if (this.textValue !== '') { + Text($r('app.string.the_second_page_is')+`:${this.textValue}`) + .fontSize(20) + } else { + Text($r('app.string.wether_to_get_the_second_page')) + .fontSize(20) + } + Flex({ justifyContent: FlexAlign.SpaceAround }) { + Button('cancel') + .onClick(() => { + if (this.controller !== undefined) { + this.controller.close(); + this.cancel(); + } + }).backgroundColor(0xffffff).fontColor(Color.Black) + Button('confirm') + .onClick(() => { + if (this.controller !== undefined && this.textValue !== '') { + this.controller.close(); + } else if (this.controller !== undefined) { + this.getUIContext().getRouter().pushUrl({ + url: 'pages/Index2' + }); + this.controller.close(); + } + }).backgroundColor(0xffffff).fontColor(Color.Red) + }.margin({ bottom: 10 }) + }.borderRadius(10).padding({ top: 20 }) + } +} + +@Entry +@Component +export struct DialogInteraction3 { + @State textValue: string = ''; + dialogController: CustomDialogController | null = new CustomDialogController({ + builder: CustomDialogExample({ + cancel: () => { + this.onCancel() + }, + confirm: () => { + this.onAccept() + }, + textValue: this.textValue + }) + }); + + // 在自定义组件即将析构销毁时将dialogController置空 + aboutToDisappear() { + this.dialogController = null; // 将dialogController置空 + } + + onPageShow() { + const params = this.getUIContext().getRouter().getParams() as Record; // 获取传递过来的参数对象 + if (params) { + this.dialogController?.open(); + this.textValue = params.info as string; // 获取info属性的值 + } + } + + onCancel() { + hilog.info(DOMAIN, 'testTag', 'testTag', 'Callback when the first button is clicked'); + } + + onAccept() { + hilog.info(DOMAIN, 'testTag', 'testTag', 'Callback when the second button is clicked'); + } + + exitApp() { + hilog.info(DOMAIN, 'testTag', 'testTag', 'Click the callback in the blank area'); + } + + build() { + Column() { + NavDestination() { + Button('click me') + .onClick(() => { + if (this.dialogController !== null) { + this.dialogController.open(); + } + }).backgroundColor(0x317aff) + }.width('100%').margin({ top: 5 }) + } + } +} +// [End dialog_interaction_3] \ No newline at end of file diff --git a/ArkUIKit/DialogProject/entry/src/main/ets/pages/customdialog/DialogStyle1.ets b/ArkUIKit/DialogProject/entry/src/main/ets/pages/customdialog/DialogStyle1.ets new file mode 100644 index 000000000..c9e5db160 --- /dev/null +++ b/ArkUIKit/DialogProject/entry/src/main/ets/pages/customdialog/DialogStyle1.ets @@ -0,0 +1,77 @@ +/* + * 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. + */ + +// [Start dialog_style_1] +@CustomDialog +struct CustomDialogExample { + controller?: CustomDialogController; + + build() { + Column() { + Text($r('app.string.i_am_content')).fontSize(16).margin({ bottom: 10 }) + } + } +} + +@Entry +@Component +export struct DialogStyle1 { + @State textValue: string = ''; + @State inputValue: string = 'click me'; + dialogController: CustomDialogController | null = new CustomDialogController({ + builder: CustomDialogExample(), + autoCancel: true, + alignment: DialogAlignment.Center, + offset: { dx: 0, dy: -20 }, + gridCount: 4, + customStyle: false, + backgroundColor: 0xd9ffffff, + cornerRadius: 20, + width: '80%', + height: '100px', + borderWidth: 1, + borderStyle: BorderStyle.Dashed, //使用borderStyle属性,需要和borderWidth属性一起使用 + borderColor: Color.Blue, //使用borderColor属性,需要和borderWidth属性一起使用 + shadow: ({ + radius: 20, + color: Color.Grey, + offsetX: 50, + offsetY: 0 + }), + }); + + // 在自定义组件即将析构销毁时将dialogController置空 + aboutToDisappear() { + this.dialogController = null; // 将dialogController置空 + } + + build() { + // [StartExclude dialog_style_1] + NavDestination() { + // [EndExclude dialog_style_1] + Column() { + Button(this.inputValue) + .onClick(() => { + if (this.dialogController !== null) { + this.dialogController.open(); + } + }).backgroundColor(0x317aff) + }.width('100%').margin({ top: 5 }) + // [StartExclude dialog_style_1] + } + // [EndExclude dialog_style_1] + } +} +// [End dialog_style_1] \ No newline at end of file diff --git a/ArkUIKit/DialogProject/entry/src/main/ets/pages/customdialog/DialogWithPhysicalBack.ets b/ArkUIKit/DialogProject/entry/src/main/ets/pages/customdialog/DialogWithPhysicalBack.ets new file mode 100644 index 000000000..1a647eca3 --- /dev/null +++ b/ArkUIKit/DialogProject/entry/src/main/ets/pages/customdialog/DialogWithPhysicalBack.ets @@ -0,0 +1,113 @@ +/* + * 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 { hilog } from '@kit.PerformanceAnalysisKit'; +const DOMAIN = 0x0000; +// [Start dialog_with_physical_back] +@CustomDialog +struct CustomDialogExample { + cancel: () => void = () => { + } + confirm: () => void = () => { + } + controller?: CustomDialogController; + + build() { + Column() { + Text('Are you sure?') + .fontSize(20) + .margin({ + top: 10, + bottom: 10 + }) + Row() { + Button('cancel') + .onClick(() => { + if (this.controller !== undefined) { + this.controller.close(); + } + }) + .backgroundColor(0xffffff) + .fontColor(Color.Black) + Button('confirm') + .onClick(() => { + if (this.controller !== undefined) { + this.controller.close(); + } + }) + .backgroundColor(0xffffff) + .fontColor(Color.Red) + } + .width('100%') + .justifyContent(FlexAlign.SpaceAround) + .margin({ bottom: 10 }) + } + } +} + +@Entry +@Component +export struct DialogWithPhysicalBack { + dialogController: CustomDialogController = new CustomDialogController({ + builder: CustomDialogExample({ + cancel: () => { + this.onCancel(); + }, + confirm: () => { + this.onAccept(); + } + }), + onWillDismiss: (dismissDialogAction: DismissDialogAction) => { + hilog.info(DOMAIN, 'testTag', 'dialog onWillDismiss reason: ' + dismissDialogAction.reason); + // 1、PRESS_BACK 点击三键back、侧滑(左滑/右滑)、键盘ESC。 + // 2、TOUCH_OUTSIDE 点击遮障层时 + // 3、CLOSE_BUTTON 点击关闭按钮 + if (dismissDialogAction.reason === DismissReason.PRESS_BACK) { + // 处理业务逻辑后通过dismiss主动关闭对话框 + dismissDialogAction.dismiss(); + } + if (dismissDialogAction.reason === DismissReason.TOUCH_OUTSIDE) { + dismissDialogAction.dismiss(); + } + }, + alignment: DialogAlignment.Bottom, + offset: { dx: 0, dy: -20 } + }) + + onCancel() { + hilog.info(DOMAIN, 'testTag', 'Callback when the first button is clicked'); + } + + onAccept() { + hilog.info(DOMAIN, 'testTag', 'Callback when the second button is clicked'); + } + + build() { + // [StartExclude dialog_with_physical_back] + NavDestination() { + // [EndExclude dialog_with_physical_back] + Column() { + Button('click me') + .onClick(() => { + this.dialogController.open(); + }) + } + .width('100%') + // [StartExclude dialog_with_physical_back] + } + // [EndExclude dialog_with_physical_back] + } +} +// [End dialog_with_physical_back] \ No newline at end of file diff --git a/ArkUIKit/DialogProject/entry/src/main/ets/pages/customdialog/GetDialogStatus.ets b/ArkUIKit/DialogProject/entry/src/main/ets/pages/customdialog/GetDialogStatus.ets new file mode 100644 index 000000000..be6df1a70 --- /dev/null +++ b/ArkUIKit/DialogProject/entry/src/main/ets/pages/customdialog/GetDialogStatus.ets @@ -0,0 +1,75 @@ +/* + * 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 { hilog } from '@kit.PerformanceAnalysisKit'; +const DOMAIN = 0x0000; +// [Start get_dialog_status] +// xxx.ets +@CustomDialog +struct CustomDialogExample { + controller?: CustomDialogController; + + build() { + Column() { + Button($r('app.string.closeDialog_by_dialog')) + .onClick(() => { + if (this.getDialogController() !== undefined) { + hilog.info(DOMAIN, 'testTag', 'state:' + this.getDialogController().getState()) + } else { + hilog.info(DOMAIN, 'testTag', 'state: no exist') + } + }).margin(20) + Button($r('app.string.closeDialog_by_dialog_controller')) + .onClick(() => { + hilog.info(DOMAIN, 'testTag', 'state:' + this.controller?.getState()) + }).margin(20) + Button($r('app.string.close_widows')) + .onClick(() => { + if (this.getDialogController() !== undefined) { + this.getDialogController().close() + } + }).margin(20) + + } + } +} + +@Entry +@Component +export struct GetDialogStatus { + dialogController: CustomDialogController | null = new CustomDialogController({ + builder: CustomDialogExample({ + }), + autoCancel: false + }) + + build() { + // [StartExclude get_dialog_status] + NavDestination() { + // [EndExclude get_dialog_status] + Column() { + Button('click me') + .onClick(() => { + if (this.dialogController !== null) { + this.dialogController.open() + } + }) + }.width('100%').margin({ top: 5 }) + // [StartExclude get_dialog_status] + } + // [EndExclude get_dialog_status] + } +} +// [End get_dialog_status] \ No newline at end of file diff --git a/ArkUIKit/DialogProject/entry/src/main/ets/pages/customdialog/Index.ets b/ArkUIKit/DialogProject/entry/src/main/ets/pages/customdialog/Index.ets index 8f2f6a43a..2c81a26d7 100644 --- a/ArkUIKit/DialogProject/entry/src/main/ets/pages/customdialog/Index.ets +++ b/ArkUIKit/DialogProject/entry/src/main/ets/pages/customdialog/Index.ets @@ -22,6 +22,15 @@ import { DialogInteraction } from './DialogInteraction'; import { DialogInteraction1 } from './DialogInteraction1'; import { DialogStyle } from './DialogStyle'; import { NestDialog } from './NestDialog'; +import { CreateCustomDialog1 } from './CreateCustomDialog1'; +import { DialogInteraction2 } from './DialogInteraction2'; +import { DialogInteraction3 } from './DialogInteraction3'; +import { DialogAnimation1 } from './DialogAnimation1'; +import { DialogStyle1 } from './DialogStyle1'; +import { NestDialog1 } from './NestDialog1'; +import { DialogWithPhysicalBack } from './DialogWithPhysicalBack'; +import { DialogAvoidSoftKeyboard } from './DialogAvoidSoftKeyboard'; +import { GetDialogStatus } from './GetDialogStatus'; import { DialogFocusStrategy } from './dialogboxfocuspolicy/DialogFocusStrategy'; import { DialogController } from './dialogcontroller/DialogController'; import { PageLevelDialogBox } from './pageleveldialogbox/PageLevelDialogBox'; @@ -60,6 +69,51 @@ const routes: Route[] = [ title: resource.resourceToString($r('app.string.CustomDialog_nest')), description: $r('app.string.CustomDialog_nest_des'), }, + { + name: `${Custom_ROUTE_PREFIX}/CreateCustomDialog1`, + title: resource.resourceToString($r('app.string.CreateCustomDialog1_title')), + description: $r('app.string.CreateCustomDialog1_desc'), + }, + { + name: `${Custom_ROUTE_PREFIX}/DialogInteraction2`, + title: resource.resourceToString($r('app.string.DialogInteraction2_title')), + description: $r('app.string.DialogInteraction2_desc'), + }, + { + name: `${Custom_ROUTE_PREFIX}/DialogInteraction3`, + title: resource.resourceToString($r('app.string.DialogInteraction3_title')), + description: $r('app.string.DialogInteraction3_desc'), + }, + { + name: `${Custom_ROUTE_PREFIX}/DialogAnimation1`, + title: resource.resourceToString($r('app.string.DialogAnimation1_title')), + description: $r('app.string.DialogAnimation1_desc'), + }, + { + name: `${Custom_ROUTE_PREFIX}/DialogStyle1`, + title: resource.resourceToString($r('app.string.DialogStyle1_title')), + description: $r('app.string.DialogStyle1_desc'), + }, + { + name: `${Custom_ROUTE_PREFIX}/NestDialog1`, + title: resource.resourceToString($r('app.string.NestDialog1_title')), + description: $r('app.string.NestDialog1_desc'), + }, + { + name: `${Custom_ROUTE_PREFIX}/DialogWithPhysicalBack`, + title: resource.resourceToString($r('app.string.DialogWithPhysicalBack_title')), + description: $r('app.string.DialogWithPhysicalBack_desc'), + }, + { + name: `${Custom_ROUTE_PREFIX}/DialogAvoidSoftKeyboard`, + title: resource.resourceToString($r('app.string.DialogAvoidSoftKeyboard_title')), + description: $r('app.string.DialogAvoidSoftKeyboard_desc'), + }, + { + name: `${Custom_ROUTE_PREFIX}/GetDialogStatus`, + title: resource.resourceToString($r('app.string.GetDialogStatus_title')), + description: $r('app.string.GetDialogStatus_desc'), + }, { name: `${Custom_ROUTE_PREFIX}/DialogFocusStrategy`, title: resource.resourceToString($r('app.string.CustomDialog_focus')), @@ -99,6 +153,23 @@ export function CustomDestination(name: string) { } else if (name === routes[5].name) { NestDialog(); } else if (name === routes[6].name) { + CreateCustomDialog1(); + } else if (name === routes[7].name) { + DialogInteraction2(); + } else if (name === routes[8].name) { + DialogInteraction3(); + } else if (name === routes[9].name) { + DialogAnimation1(); + } else if (name === routes[10].name) { + DialogStyle1(); + } else if (name === routes[11].name) { + NestDialog1(); + } else if (name === routes[12].name) { + DialogWithPhysicalBack(); + } else if (name === routes[13].name) { + DialogAvoidSoftKeyboard(); + } else if (name === routes[14].name) { + GetDialogStatus(); DialogFocusStrategy(); } else if (name === routes[7].name) { DialogController(); diff --git a/ArkUIKit/DialogProject/entry/src/main/ets/pages/customdialog/Index2.ets b/ArkUIKit/DialogProject/entry/src/main/ets/pages/customdialog/Index2.ets new file mode 100644 index 000000000..6b4b3d039 --- /dev/null +++ b/ArkUIKit/DialogProject/entry/src/main/ets/pages/customdialog/Index2.ets @@ -0,0 +1,43 @@ +/* + * 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. + */ + +// [Start index_2] +@Entry +@Component +struct Index2 { + @State message: string = $r('app.string.click_and_return'); + + build() { + // [StartExclude index_2] + NavDestination() { + // [EndExclude index_2] + Column() { + Button(this.message) + .type(ButtonType.Capsule) + .onClick(() => { + this.getUIContext().getRouter().back({ + url: 'pages/Index', + params: { + info: 'Hello World' + } + }); + }) + }.width('100%').height('100%').margin({ top: 20 }) + // [StartExclude index_2] + } + // [EndExclude index_2] + } +} +// [End index_2] \ No newline at end of file diff --git a/ArkUIKit/DialogProject/entry/src/main/ets/pages/customdialog/NestDialog1.ets b/ArkUIKit/DialogProject/entry/src/main/ets/pages/customdialog/NestDialog1.ets new file mode 100644 index 000000000..88201726d --- /dev/null +++ b/ArkUIKit/DialogProject/entry/src/main/ets/pages/customdialog/NestDialog1.ets @@ -0,0 +1,126 @@ +/* + * 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 { hilog } from '@kit.PerformanceAnalysisKit'; +const DOMAIN = 0x0000; +// [Start nest_dialog_1] +@CustomDialog +struct CustomDialogExampleTwo { + controllerTwo?: CustomDialogController; + @State message: string = 'I am the second dialog box.'; + @State showIf: boolean = false; + + build() { + Column() { + if (this.showIf) { + Text('Text') + .fontSize(30) + .height(100) + } + Text(this.message) + .fontSize(30) + .height(100) + Button('Create Text') + .onClick(() => { + this.showIf = true; + }) + Button('Close Second Dialog Box') + .onClick(() => { + if (this.controllerTwo !== undefined) { + this.controllerTwo.close(); + } + }) + .margin(20) + } + } +} + +@CustomDialog +struct CustomDialogExample { + openSecondBox?: () => void; + controller?: CustomDialogController; + + build() { + Column() { + Button('Open Second Dialog Box and close this box') + .onClick(() => { + this.controller!.close(); + this.openSecondBox!(); + }) + .margin(20) + }.borderRadius(10) + } +} + +@Entry +@Component +export struct NestDialog1 { + @State inputValue: string = 'Click Me'; + dialogController: CustomDialogController | null = new CustomDialogController({ + builder: CustomDialogExample({ + openSecondBox: () => { + if (this.dialogControllerTwo !== null) { + this.dialogControllerTwo.open() + } + } + }), + cancel: this.exitApp, + autoCancel: true, + alignment: DialogAlignment.Bottom, + offset: { dx: 0, dy: -20 }, + gridCount: 4, + customStyle: false + }); + dialogControllerTwo: CustomDialogController | null = new CustomDialogController({ + builder: CustomDialogExampleTwo(), + alignment: DialogAlignment.Bottom, + offset: { dx: 0, dy: -25 } + }); + + aboutToDisappear() { + this.dialogController = null; + this.dialogControllerTwo = null; + } + + onCancel() { + hilog.info(DOMAIN, 'testTag', 'Callback when the first button is clicked'); + } + + onAccept() { + hilog.info(DOMAIN, 'testTag', 'Callback when the second button is clicked'); + } + + exitApp() { + hilog.info(DOMAIN, 'testTag', 'Click the callback in the blank area'); + } + + build() { + // [StartExclude nest_dialog_1] + NavDestination() { + // [EndExclude nest_dialog_1] + Column() { + Button(this.inputValue) + .onClick(() => { + if (this.dialogController !== null) { + this.dialogController.open(); + } + }).backgroundColor(0x317aff) + }.width('100%').margin({ top: 5 }) + // [StartExclude nest_dialog_1] + } + // [EndExclude nest_dialog_1] + } +} +// [End nest_dialog_1] \ No newline at end of file diff --git a/ArkUIKit/DialogProject/entry/src/main/ets/pages/fixedstyledialog/ActionSheet.ets b/ArkUIKit/DialogProject/entry/src/main/ets/pages/fixedstyledialog/ActionSheet.ets index edc3baea8..536beb3dc 100644 --- a/ArkUIKit/DialogProject/entry/src/main/ets/pages/fixedstyledialog/ActionSheet.ets +++ b/ArkUIKit/DialogProject/entry/src/main/ets/pages/fixedstyledialog/ActionSheet.ets @@ -79,6 +79,7 @@ export struct showActionSheetExample { .padding({ left: 12, right: 12 }) } .backgroundColor('#f1f2f3') + // $r('app.string.xxx')Ҫ滻ΪַԴļ .title($r('app.string.CustomDialog_ActionSheet')) } } diff --git a/ArkUIKit/DialogProject/entry/src/main/ets/pages/fixedstyledialog/AlertDialog.ets b/ArkUIKit/DialogProject/entry/src/main/ets/pages/fixedstyledialog/AlertDialog.ets index 825c1f7ed..248287b2c 100644 --- a/ArkUIKit/DialogProject/entry/src/main/ets/pages/fixedstyledialog/AlertDialog.ets +++ b/ArkUIKit/DialogProject/entry/src/main/ets/pages/fixedstyledialog/AlertDialog.ets @@ -69,6 +69,7 @@ export struct showAlertDialogExample { .padding({ left: 12, right: 12 }) } .backgroundColor('#f1f2f3') + // $r('app.string.xxx')Ҫ滻ΪַԴļ .title($r('app.string.CustomDialog_AlertDialog')) } } diff --git a/ArkUIKit/DialogProject/entry/src/main/ets/pages/fixedstyledialog/CalendarPickerDialog.ets b/ArkUIKit/DialogProject/entry/src/main/ets/pages/fixedstyledialog/CalendarPickerDialog.ets index c12418f2f..3d935d6bd 100644 --- a/ArkUIKit/DialogProject/entry/src/main/ets/pages/fixedstyledialog/CalendarPickerDialog.ets +++ b/ArkUIKit/DialogProject/entry/src/main/ets/pages/fixedstyledialog/CalendarPickerDialog.ets @@ -14,6 +14,7 @@ */ // [Start calender_picker_dialog] +// xxx.ets import { PromptAction } from '@kit.ArkUI'; @Entry @@ -58,6 +59,7 @@ export struct CalendarDialog { .padding({ left: 12, right: 12 }) } .backgroundColor('#f1f2f3') + // $r('app.string.xxx')需要替换为开发者所需的字符串资源文件 .title($r('app.string.CustomDialog_calender')) } } diff --git a/ArkUIKit/DialogProject/entry/src/main/ets/pages/fixedstyledialog/DatePickerCustomDialog.ets b/ArkUIKit/DialogProject/entry/src/main/ets/pages/fixedstyledialog/DatePickerCustomDialog.ets new file mode 100644 index 000000000..e1ecc228c --- /dev/null +++ b/ArkUIKit/DialogProject/entry/src/main/ets/pages/fixedstyledialog/DatePickerCustomDialog.ets @@ -0,0 +1,57 @@ +/* + * 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. + */ + +// [Start date_picker_custom_dialog] +import { PromptAction } from '@kit.ArkUI'; + +@Entry +@Component +export struct DatePickerCustomDialogExample { + @State selectTime: Date = new Date('2023-12-25T08:30:00'); + + build() { + NavDestination() { + Column() { + Button('showDatePickerCustomDialog') + .margin(30) + .onClick(() => { + this.getUIContext().showDatePickerDialog({ + start: new Date('2000-1-1'), + end: new Date('2100-12-31'), + selected: this.selectTime, + textStyle: { color: '#2787d9', font: { size: '14fp', weight: FontWeight.Normal } }, + selectedTextStyle: { color: '#004aaf', font: { size: '18fp', weight: FontWeight.Regular } }, + acceptButtonStyle: { + fontColor: '#2787d9', + fontSize: '16fp', + backgroundColor: '#f7f7f7', + borderRadius: 10 + }, + cancelButtonStyle: { + fontColor: Color.Red, + fontSize: '16fp', + backgroundColor: '#f7f7f7', + borderRadius: 10 + } + }) + }) + }.width('100%').margin({ top: 5 }) + } + .backgroundColor('#f1f2f3') + // $r('app.string.xxx')需要替换为开发者所需的字符串资源文件 + .title($r('app.string.CustomCustomDialog_date')) + } +} +// [End date_picker_custom_dialog] \ No newline at end of file diff --git a/ArkUIKit/DialogProject/entry/src/main/ets/pages/fixedstyledialog/DatePickerDialog.ets b/ArkUIKit/DialogProject/entry/src/main/ets/pages/fixedstyledialog/DatePickerDialog.ets index 28caa25d6..38ba9a089 100644 --- a/ArkUIKit/DialogProject/entry/src/main/ets/pages/fixedstyledialog/DatePickerDialog.ets +++ b/ArkUIKit/DialogProject/entry/src/main/ets/pages/fixedstyledialog/DatePickerDialog.ets @@ -49,6 +49,7 @@ export struct DatePickerDialogExample { .padding({ left: 12, right: 12 }) } .backgroundColor('#f1f2f3') + // $r('app.string.xxx')Ҫ滻ΪַԴļ .title($r('app.string.CustomDialog_date')) } } diff --git a/ArkUIKit/DialogProject/entry/src/main/ets/pages/fixedstyledialog/Index.ets b/ArkUIKit/DialogProject/entry/src/main/ets/pages/fixedstyledialog/Index.ets index b8e1c0703..a87d0fbfb 100644 --- a/ArkUIKit/DialogProject/entry/src/main/ets/pages/fixedstyledialog/Index.ets +++ b/ArkUIKit/DialogProject/entry/src/main/ets/pages/fixedstyledialog/Index.ets @@ -18,6 +18,7 @@ import { Route } from '../../common/Route'; import { showActionSheetExample } from './ActionSheet'; import { CalendarDialog } from './CalendarPickerDialog'; import { DatePickerDialogExample } from './DatePickerDialog'; +import { DatePickerCustomDialogExample } from './DatePickerCustomDialog'; import { TextPickerDialogExample } from './TextPickerDialog'; import { TimePickerDialogExample } from './TimePickerDialog'; import { showAlertDialogExample } from './AlertDialog'; @@ -39,6 +40,11 @@ const routes: Route[] = [ title: resource.resourceToString($r('app.string.DatePicker_title')), description: $r('app.string.DatePicker_des'), }, + { + name: `${Fixed_ROUTE_PREFIX}/DatePickerCustomDialogExample`, + title: resource.resourceToString($r('app.string.DatePickerCustom_title')), + description: $r('app.string.DatePickerCustom_des'), + }, { name: `${Fixed_ROUTE_PREFIX}/TimePickerDialog`, title: resource.resourceToString($r('app.string.TimePicker_title')), @@ -80,16 +86,18 @@ export function FixedDialogDestination(name: string) { } else if (name === routes[1].name) { DatePickerDialogExample(); } else if (name === routes[2].name) { - TimePickerDialogExample(); + DatePickerCustomDialogExample(); } else if (name === routes[3].name) { - TextPickerDialogExample(); + TimePickerDialogExample(); } else if (name === routes[4].name) { - showActionSheetExample(); + TextPickerDialogExample(); } else if (name === routes[5].name) { - showAlertDialogExample(); + showActionSheetExample(); } else if (name === routes[6].name) { - ShowActionMenuExample(); + showAlertDialogExample(); } else if (name === routes[7].name) { + ShowActionMenuExample(); + } else if (name === routes[8].name) { ShowDialogExample(); } } diff --git a/ArkUIKit/DialogProject/entry/src/main/ets/pages/fixedstyledialog/ShowDialog.ets b/ArkUIKit/DialogProject/entry/src/main/ets/pages/fixedstyledialog/ShowDialog.ets index 73da39ba0..b341e0fec 100644 --- a/ArkUIKit/DialogProject/entry/src/main/ets/pages/fixedstyledialog/ShowDialog.ets +++ b/ArkUIKit/DialogProject/entry/src/main/ets/pages/fixedstyledialog/ShowDialog.ets @@ -12,14 +12,17 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - +// [Start show_dialog_example] +// xxx.ets import { PromptAction } from '@kit.ArkUI'; @Entry @Component export struct ShowDialogExample { build() { + // [StartExclude show_dialog_example] NavDestination() { + // [EndExclude show_dialog_example] Column({ space: 12 }) { Column() { Button('ShowDialog') @@ -56,8 +59,12 @@ export struct ShowDialogExample { .width('100%') .height('100%') .padding({ left: 12, right: 12 }) + // [StartExclude show_dialog_example] } + // [EndExclude show_dialog_example] .backgroundColor('#f1f2f3') + // $r('app.string.xxx')Ҫ滻ΪַԴļ .title($r('app.string.ShowDialog_title')) } -} \ No newline at end of file +} +// [End show_dialog_example] \ No newline at end of file diff --git a/ArkUIKit/DialogProject/entry/src/main/ets/pages/fixedstyledialog/TextPickerDialog.ets b/ArkUIKit/DialogProject/entry/src/main/ets/pages/fixedstyledialog/TextPickerDialog.ets index 165285fbc..7443d8602 100644 --- a/ArkUIKit/DialogProject/entry/src/main/ets/pages/fixedstyledialog/TextPickerDialog.ets +++ b/ArkUIKit/DialogProject/entry/src/main/ets/pages/fixedstyledialog/TextPickerDialog.ets @@ -62,6 +62,7 @@ export struct TextPickerDialogExample { .padding({ left: 12, right: 12 }) } .backgroundColor('#f1f2f3') + // $r('app.string.xxx')Ҫ滻ΪַԴļ .title($r('app.string.CustomDialog_text')) } } diff --git a/ArkUIKit/DialogProject/entry/src/main/ets/pages/fixedstyledialog/TimePickerDialog.ets b/ArkUIKit/DialogProject/entry/src/main/ets/pages/fixedstyledialog/TimePickerDialog.ets index 7f0393367..f7c732c4f 100644 --- a/ArkUIKit/DialogProject/entry/src/main/ets/pages/fixedstyledialog/TimePickerDialog.ets +++ b/ArkUIKit/DialogProject/entry/src/main/ets/pages/fixedstyledialog/TimePickerDialog.ets @@ -14,6 +14,8 @@ */ // [Start time_picker_dialog] +// xxx.ets + import { PromptAction } from '@kit.ArkUI'; @Entry @@ -55,6 +57,7 @@ export struct TimePickerDialogExample { .padding({ left: 12, right: 12 }) } .backgroundColor('#f1f2f3') + // $r('app.string.xxx')Ҫ滻ΪַԴļ .title($r('app.string.CustomDialog_time')) } } diff --git a/ArkUIKit/DialogProject/entry/src/main/ets/pages/maskdialog/CustomDialogAnimation.ets b/ArkUIKit/DialogProject/entry/src/main/ets/pages/maskdialog/CustomDialogAnimation.ets new file mode 100644 index 000000000..cf4965e4e --- /dev/null +++ b/ArkUIKit/DialogProject/entry/src/main/ets/pages/maskdialog/CustomDialogAnimation.ets @@ -0,0 +1,77 @@ +/* + * 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. + */ + +// [Start custom_dialog_animation] +// xxx.ets + +@CustomDialog +@Component +struct CustomDialogAnimationBuilder { + controller?: CustomDialogController; + + build() { + Column() { + Text('title') + .margin(10) + .fontSize(20) + Button('button1') + .margin(10) + .fontSize(20) + .onClick(() => { + this.controller?.close(); + }) + Button('button2') + .margin(10) + .fontSize(20) + .onClick(() => { + this.controller?.close(); + }) + }.width('100%') + .height('50%') + } +} + +@Entry +@Component +export struct CustomDialogAnimation { + animationController: CustomDialogController | null = + new CustomDialogController({ + builder: CustomDialogAnimationBuilder(), + closeAnimation: { duration: 2000 }, + openAnimation: { duration: 2000 } + }); + + aboutToDisappear(): void { + this.animationController = null; + } + + build() { + // [StartExclude custom_dialog_animation] + NavDestination() { + // [EndExclude custom_dialog_animation] + Column() { + Button('CustomDialogController animate') + .width('100%') + .margin({ top: 10 }) + .onClick(() => { + this.animationController?.open(); + }) + } + // [StartExclude custom_dialog_animation] + } + // [EndExclude custom_dialog_animation] + } +} +// [End custom_dialog_animation] \ No newline at end of file diff --git a/ArkUIKit/DialogProject/entry/src/main/ets/pages/maskdialog/CustomDialogControl.ets b/ArkUIKit/DialogProject/entry/src/main/ets/pages/maskdialog/CustomDialogControl.ets new file mode 100644 index 000000000..3cea4486a --- /dev/null +++ b/ArkUIKit/DialogProject/entry/src/main/ets/pages/maskdialog/CustomDialogControl.ets @@ -0,0 +1,158 @@ +/* + * 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. + */ + +// [Start custom_dialog_control] +// xxx.ets +import { ImmersiveMode, LevelMode, promptAction } from '@kit.ArkUI'; + +@Entry +@Component +export struct CustomDialogControl { + // [Start custom_dialog_control_immersive_default] + @State immersiveMode: ImmersiveMode = ImmersiveMode.DEFAULT; + // [End custom_dialog_control_immersive_default] + + // [Start custom_dialog_control_autoCancel_opt] + autoCancelOpt: promptAction.CustomDialogOptions = { + builder: () => { + this.myBuilder(); + }, + autoCancel: false, + } as promptAction.CustomDialogOptions; + // [End custom_dialog_control_autoCancel_opt] + + // [Start custom_dialog_control_modal_opt] + modalOpt: promptAction.CustomDialogOptions = { + builder: () => { + this.myBuilder(); + }, + isModal: false, + } as promptAction.CustomDialogOptions; + // [End custom_dialog_control_modal_opt] + + // [Start custom_dialog_control_mask_opt] + maskOpt: promptAction.CustomDialogOptions = { + builder: () => { + this.myBuilder(); + }, + maskRect: { + x: 0, + y: 10, + width: '100%', + height: '90%' + }, + maskColor: '#33AA0000' + } as promptAction.CustomDialogOptions; + // [End custom_dialog_control_mask_opt] + + // [Start custom_dialog_control_transition_opt] + transitionOpt: promptAction.CustomDialogOptions = { + builder: () => { + this.myBuilder(); + }, + transition: TransitionEffect.OPACITY.animation({ duration: 3000 }) + } as promptAction.CustomDialogOptions; + // [End custom_dialog_control_transition_opt] + + @Builder + myBuilder() { + Column() { + Text('title').margin(10).fontSize(20) + Button('button1').margin(10).fontSize(20) + Button('button2').margin(10).fontSize(20) + }.width('100%').height('50%') + } + + build() { + // [StartExclude custom_dialog_control] + NavDestination() { + // [EndExclude custom_dialog_control] + Column() { + // [Start custom_dialog_control_autoCance_btn] + Button('openCustomDialog autoCancel:false') + .width('100%') + .margin({ top: 10 }) + .onClick(() => { + this.getUIContext().getPromptAction().openCustomDialog(this.autoCancelOpt) + }) + // [End custom_dialog_control_autoCance_btn] + + // [Start custom_dialog_control_modal_btn] + Button('openCustomDialog isModal:false') + .width('100%') + .margin({ top: 10 }) + .onClick(() => { + this.getUIContext().getPromptAction().openCustomDialog(this.modalOpt) + }) + // [End custom_dialog_control_modal_btn] + + // [Start custom_dialog_control_mask_btn] + Button('openCustomDialog maskOpt') + .width('100%') + .margin({ top: 10 }) + .onClick(() => { + this.getUIContext().getPromptAction().openCustomDialog(this.maskOpt) + }) + // [End custom_dialog_control_mask_btn] + + // [Start custom_dialog_control_transition_btn] + Button('openCustomDialog transition') + .width('100%') + .margin({ top: 10 }) + .onClick(() => { + this.getUIContext().getPromptAction().openCustomDialog(this.transitionOpt); + }) + // [End custom_dialog_control_transition_btn] + + // [Start custom_dialog_control_immersive_btn] + Button('openCustomDialog immersiveMode') + .width('100%') + .margin({ top: 10 }) + .onClick(() => { + this.immersiveMode = + this.immersiveMode == ImmersiveMode.DEFAULT ? ImmersiveMode.EXTEND : ImmersiveMode.DEFAULT; + this.getUIContext().getPromptAction().openCustomDialog({ + builder: () => { + this.myBuilder(); + }, + levelMode: LevelMode.EMBEDDED, + immersiveMode: this.immersiveMode, + }) + }) + // [End custom_dialog_control_immersive_btn] + + // [Start custom_dialog_control_mask_transition] + Button('openCustomDialog maskTransition') + .width('100%') + .margin({ top: 10 }) + .onClick(() => { + this.getUIContext().getPromptAction().openCustomDialog({ + builder: () => { + this.myBuilder(); + }, + maskTransition: TransitionEffect.OPACITY.animation({ duration: 2000 }) + .combine(TransitionEffect.rotate({ z: 1, angle: 180 })), + }); + }) + // [End custom_dialog_control_mask_transition] + } + .width('100%') + .height('100%') + // [StartExclude custom_dialog_control] + } + // [EndExclude custom_dialog_control] + } +} +// [End custom_dialog_control] \ No newline at end of file diff --git a/ArkUIKit/DialogProject/entry/src/main/ets/pages/maskdialog/Index.ets b/ArkUIKit/DialogProject/entry/src/main/ets/pages/maskdialog/Index.ets new file mode 100644 index 000000000..da7d036d9 --- /dev/null +++ b/ArkUIKit/DialogProject/entry/src/main/ets/pages/maskdialog/Index.ets @@ -0,0 +1,76 @@ +/* + * 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 { CompletedRoutableCard } from '../../common/Card'; +import resource from '../../common/resource'; +import { Route } from '../../common/Route'; +import { CustomDialogAnimation } from './CustomDialogAnimation'; +import { CustomDialogControl } from './CustomDialogControl'; + +export const Mask_ROUTE_PREFIX: string = 'Mask_Mask_ROUTE_PREFIX'; + +const routes: Route[] = [ + { + name: `${Mask_ROUTE_PREFIX}/CustomDialogAnimation`, + title: resource.resourceToString($r('app.string.CustomDialogAnimation_title')), + description: $r('app.string.CustomDialogAnimation_desc'), + }, + { + name: `${Mask_ROUTE_PREFIX}/CustomDialogControl`, + title: resource.resourceToString($r('app.string.CustomDialogControl_title')), + description: $r('app.string.CustomDialogControl_desc'), + } +] + +@Builder +export function MaskDestination(name: string) { + if (name === Mask_ROUTE_PREFIX) { + MaskCustomExample(); + } else if (name === routes[0].name) { + CustomDialogAnimation(); + } else if (name === routes[1].name) { + CustomDialogControl(); + } +} + +@Entry +@Component +struct MaskCustomExample { + @Consume pathStack: NavPathStack; + + build() { + NavDestination() { + List({ space: 12 }) { + ForEach(routes, (route: Route) => { + ListItem() { + CompletedRoutableCard({ title: route.title, description: route.description }) + } + .width('100%') + .onClick(() => { + this.pathStack.pushPath({ name: route.name }); + }) + }) + } + .contentStartOffset(20) + .padding({ left: 16, right: 16 }) + } + .backgroundColor('#f1f3f5') + .title('', { + backgroundBlurStyle: BlurStyle.COMPONENT_THICK, + barStyle: BarStyle.STACK + }) + .title($r('app.string.Mask_CustomDialog_dialog')) + } +} \ No newline at end of file diff --git a/ArkUIKit/DialogProject/entry/src/main/ets/pages/opencustomdialog/Index.ets b/ArkUIKit/DialogProject/entry/src/main/ets/pages/opencustomdialog/Index.ets index 3d1b31b01..b1e70b807 100644 --- a/ArkUIKit/DialogProject/entry/src/main/ets/pages/opencustomdialog/Index.ets +++ b/ArkUIKit/DialogProject/entry/src/main/ets/pages/opencustomdialog/Index.ets @@ -17,6 +17,9 @@ import { CompletedRoutableCard } from '../../common/Card'; import resource from '../../common/resource'; import { Route } from '../../common/Route'; import { openCustomDialog } from './openCustomDialog'; +import { customDialogComponentWithTransition } from './customDialogComponentWithTransition'; +import { customDialogWithKeyboardAvoidDistance } from './customDialogWithKeyboardAvoidDistance'; +import { OpenDialogAndUpdate } from './OpenDialogAndUpdate'; export const CustomDialog_ROUTE_PREFIX: string = 'CustomDialog_ROUTE_PREFIX'; @@ -25,6 +28,21 @@ const routes: Route[] = [ name: `${CustomDialog_ROUTE_PREFIX}/Customdialog`, title: resource.resourceToString($r('app.string.Customdialog_title')), description: $r('app.string.Customdialog_des'), + }, + { + name: `${CustomDialog_ROUTE_PREFIX}/customDialogComponentWithTransition`, + title: resource.resourceToString($r('app.string.customDialogComponentWithTransition_title')), + description: $r('app.string.customDialogComponentWithTransition_desc'), + }, + { + name: `${CustomDialog_ROUTE_PREFIX}/customDialogWithKeyboardAvoidDistance`, + title: resource.resourceToString($r('app.string.customDialogWithKeyboardAvoidDistance_title')), + description: $r('app.string.customDialogWithKeyboardAvoidDistance_desc'), + }, + { + name: `${CustomDialog_ROUTE_PREFIX}/OpenDialogAndUpdate`, + title: resource.resourceToString($r('app.string.OpenDialogAndUpdate_title')), + description: $r('app.string.OpenDialogAndUpdate_desc'), } ] @@ -34,6 +52,12 @@ export function CustomDialogDestination(name: string) { CustomDialogExample(); } else if (name === routes[0].name) { openCustomDialog(); + } else if (name === routes[1].name) { + customDialogComponentWithTransition(); + } else if (name === routes[2].name) { + customDialogWithKeyboardAvoidDistance(); + } else if (name === routes[3].name) { + OpenDialogAndUpdate(); } } diff --git a/ArkUIKit/DialogProject/entry/src/main/ets/pages/opencustomdialog/OpenDialogAndUpdate.ets b/ArkUIKit/DialogProject/entry/src/main/ets/pages/opencustomdialog/OpenDialogAndUpdate.ets new file mode 100644 index 000000000..02e7e7828 --- /dev/null +++ b/ArkUIKit/DialogProject/entry/src/main/ets/pages/opencustomdialog/OpenDialogAndUpdate.ets @@ -0,0 +1,97 @@ +/* + * 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. + */ + +// [Start open_dialog_and_update] +// Index.ets +import { ComponentContent } from '@kit.ArkUI'; +import { PromptActionClass1 } from '../../common/PromptActionClass1'; + +class Params { + public text: string = ''; + + constructor(text: string) { + this.text = text; + } +} + +@Builder +function buildText(params: Params) { + Column() { + Text(params.text) + .fontSize(50) + .fontWeight(FontWeight.Bold) + .margin({ bottom: 36 }) + Button('Close') + .onClick(() => { + PromptActionClass1.closeDialog(); + }) + }.backgroundColor('#FFF0F0F0') +} + +@Entry +@Component +export struct OpenDialogAndUpdate { + @State message: string = 'hello'; + private ctx: UIContext = this.getUIContext(); + // [Start open_dialog_and_update_create_componentContent] + private contentNode: ComponentContent = + new ComponentContent(this.ctx, wrapBuilder(buildText), new Params(this.message)); + // [End open_dialog_and_update_create_componentContent] + aboutToAppear(): void { + PromptActionClass1.setContext(this.ctx); + PromptActionClass1.setContentNode(this.contentNode); + PromptActionClass1.setOptions({ alignment: DialogAlignment.Top, offset: { dx: 0, dy: 50 } }); + } + + build() { + // [StartExclude open_dialog_and_update] + NavDestination() { + // [EndExclude open_dialog_and_update] + Row() { + Column() { + Button('open dialog and update options') + .margin({ top: 50 }) + .onClick(() => { + PromptActionClass1.openDialog(); + + setTimeout(() => { + PromptActionClass1.updateDialog({ + alignment: DialogAlignment.Bottom, + offset: { dx: 0, dy: -50 } + }); + }, 1500) + }) + Button('open dialog and update content') + .margin({ top: 50 }) + .onClick(() => { + PromptActionClass1.openDialog(); + + setTimeout(() => { + // [Start open_dialog_and_update_content] + this.contentNode.update(new Params('update')); + // [End open_dialog_and_update_content] + }, 1500) + }) + } + .width('100%') + .height('100%') + } + .height('100%') + // [StartExclude open_dialog_and_update] + } + // [EndExclude open_dialog_and_update] + } +} +// [End open_dialog_and_update] \ No newline at end of file diff --git a/ArkUIKit/DialogProject/entry/src/main/ets/pages/opencustomdialog/customDialogComponentWithTransition.ets b/ArkUIKit/DialogProject/entry/src/main/ets/pages/opencustomdialog/customDialogComponentWithTransition.ets new file mode 100644 index 000000000..274209275 --- /dev/null +++ b/ArkUIKit/DialogProject/entry/src/main/ets/pages/opencustomdialog/customDialogComponentWithTransition.ets @@ -0,0 +1,81 @@ +/* + * 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. + */ + +// [Start custom_dialog_with_transition] +import { BusinessError } from '@kit.BasicServicesKit'; +import { hilog } from '@kit.PerformanceAnalysisKit'; +const DOMAIN = 0x0000; +@Entry +@Component +export struct customDialogComponentWithTransition { + private customDialogComponentId: number = 0 + @Builder + customDialogComponent() { + Row({ space: 50 }) { + Button($r('app.string.this_is_a_window')) + }.height(200).padding(5) + } + + build() { + // [StartExclude custom_dialog_with_transition] + NavDestination() { + // [EndExclude custom_dialog_with_transition] + Row() { + Row({ space: 20 }) { + Text($r('app.string.open_windows')) + .fontSize(30) + .onClick(() => { + this.getUIContext() + .getPromptAction() + .openCustomDialog({ + builder: () => { + this.customDialogComponent() + }, + isModal: true, + showInSubWindow: false, + maskColor: Color.Pink, + maskRect: { + x: 20, + y: 20, + width: '90%', + height: '90%' + }, + + dialogTransition: // 设置弹窗内容显示的过渡效果 + TransitionEffect.translate({ x: 0, y: 290, z: 0 }) + .animation({ duration: 4000, curve: Curve.Smooth }), // 四秒钟的偏移渐变动画 + + maskTransition: // 设置蒙层显示的过渡效果 + TransitionEffect.opacity(0) + .animation({ duration: 4000, curve: Curve.Smooth }) // 四秒钟的透明渐变动画 + + }) + .then((dialogId: number) => { + this.customDialogComponentId = dialogId + }) + .catch((error: BusinessError) => { + hilog.error(DOMAIN, 'testTag', `openCustomDialog error code is ${error.code}, message is ${error.message}`) + }) + }) + } + .width('100%') + } + .height('100%') + // [StartExclude custom_dialog_with_transition] + } + // [EndExclude custom_dialog_with_transition] + } +} +// [End custom_dialog_with_transition] \ No newline at end of file diff --git a/ArkUIKit/DialogProject/entry/src/main/ets/pages/opencustomdialog/customDialogWithKeyboardAvoidDistance.ets b/ArkUIKit/DialogProject/entry/src/main/ets/pages/opencustomdialog/customDialogWithKeyboardAvoidDistance.ets new file mode 100644 index 000000000..001eccb02 --- /dev/null +++ b/ArkUIKit/DialogProject/entry/src/main/ets/pages/opencustomdialog/customDialogWithKeyboardAvoidDistance.ets @@ -0,0 +1,65 @@ +/* + * 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. + */ + +// [Start custom_dialog_with_key_board_distance] +import { BusinessError } from '@kit.BasicServicesKit'; +import { LengthMetrics } from '@kit.ArkUI' +import resource from '../../common/resource'; +import { hilog } from '@kit.PerformanceAnalysisKit'; +const DOMAIN = 0x0000; + +@Entry +@Component +export struct customDialogWithKeyboardAvoidDistance { + @Builder + customDialogComponent() { + Column() { + Text('keyboardAvoidDistance: 0vp') + .fontSize(20) + .margin({ bottom: 36 }) + TextInput({ placeholder: '' }) + }.backgroundColor('#FFF0F0F0') + } + + build() { + // [StartExclude custom_dialog_with_key_board_distance] + NavDestination() { + // [EndExclude custom_dialog_with_key_board_distance] + Row() { + Row({ space: 20 }) { + Text($r('app.string.open_windows')) + .fontSize(30) + .onClick(() => { + this.getUIContext().getPromptAction().openCustomDialog({ + builder: () => { + this.customDialogComponent() + }, + alignment: DialogAlignment.Bottom, + keyboardAvoidMode: KeyboardAvoidMode.DEFAULT, // 软键盘弹出时,弹出框自动避让 + keyboardAvoidDistance: LengthMetrics.vp(0) // 软键盘弹出时与弹出框的距离为0vp + }).catch((error: BusinessError) => { + hilog.error(DOMAIN, 'testTag', `openCustomDialog error code is ${error.code}, message is ${error.message}`) + }) + }) + } + .width('100%') + } + .height('100%') + // [StartExclude custom_dialog_with_key_board_distance] + } + // [EndExclude custom_dialog_with_key_board_distance] + } +} +// [end custom_dialog_with_key_board_distance] \ No newline at end of file diff --git a/ArkUIKit/DialogProject/entry/src/main/ets/pages/popup/ButtonPopup.ets b/ArkUIKit/DialogProject/entry/src/main/ets/pages/popup/ButtonPopup.ets index 114fc049e..c27b08aa9 100644 --- a/ArkUIKit/DialogProject/entry/src/main/ets/pages/popup/ButtonPopup.ets +++ b/ArkUIKit/DialogProject/entry/src/main/ets/pages/popup/ButtonPopup.ets @@ -25,6 +25,7 @@ export struct ButtonPopupExample { Column() { Button('PopupOptions').margin({ top: 300 }) + .id('PopupOptions') .onClick(() => { this.handlePopup = !this.handlePopup; }) @@ -57,6 +58,7 @@ export struct ButtonPopupExample { .padding({ left: 12, right: 12 }) } .backgroundColor('#f1f2f3') + // $r('app.string.button_popup')需要替换为开发者所需的资源文件。 .title($r('app.string.button_popup')) } } diff --git a/ArkUIKit/DialogProject/entry/src/main/ets/pages/popup/CustomPopup.ets b/ArkUIKit/DialogProject/entry/src/main/ets/pages/popup/CustomPopup.ets index c533a4f49..b2ac7eccc 100644 --- a/ArkUIKit/DialogProject/entry/src/main/ets/pages/popup/CustomPopup.ets +++ b/ArkUIKit/DialogProject/entry/src/main/ets/pages/popup/CustomPopup.ets @@ -34,6 +34,7 @@ export struct CustomPopupExample { Column() { Button('CustomPopupOptions') + .id('CustomPopupOptions') .margin({ top: 300 }) .onClick(() => { this.customPopup = !this.customPopup; @@ -57,6 +58,7 @@ export struct CustomPopupExample { .padding({ left: 12, right: 12 }) } .backgroundColor('#f1f2f3') + // $r('app.string.custom_popup')需要替换为开发者所需的资源文件。 .title($r('app.string.custom_popup')) } } diff --git a/ArkUIKit/DialogProject/entry/src/main/ets/pages/popup/Index.ets b/ArkUIKit/DialogProject/entry/src/main/ets/pages/popup/Index.ets index 6d9896b99..e375ceebb 100644 --- a/ArkUIKit/DialogProject/entry/src/main/ets/pages/popup/Index.ets +++ b/ArkUIKit/DialogProject/entry/src/main/ets/pages/popup/Index.ets @@ -22,9 +22,11 @@ import { AnimationPopupExample } from './PopupAnimation'; import { StatePopupExample } from './PopupStateChange'; import { StylePopupExample } from './PopupStyle'; import { TextPopupExample } from './TextPrompts'; +import { AvoidSoftKeyboardPopupExample } from './PopupAvoidSoftKeyboard'; +import { PolymorphicEffectPopupExample } from './PopupPolymorphicEffect'; +import { SupportedAvoidAxisPopupExample } from './PopupSupportedAvoidAxis'; import { OpenPopup } from './globalpopupsindependentofuicomponents/OpenPopup'; - export const Popup_ROUTE_PREFIX: string = 'Popup_ROUTE_PREFIX'; const routes: Route[] = [ @@ -58,6 +60,27 @@ const routes: Route[] = [ title: resource.resourceToString($r('app.string.StylePopup_title')), description: $r('app.string.StylePopup_des'), }, + { + name: `${Popup_ROUTE_PREFIX}/AvoidSoftKeyboardPopupExample`, + // $r('app.string.AvoidSoftKeyboardPopupExample_title')需要替换为开发者所需的资源文件。 + title: resource.resourceToString($r('app.string.AvoidSoftKeyboardPopupExample_title')), + // $r('app.string.AvoidSoftKeyboardPopupExample_des')需要替换为开发者所需的资源文件。 + description: $r('app.string.AvoidSoftKeyboardPopupExample_des'), + }, + { + name: `${Popup_ROUTE_PREFIX}/PolymorphicEffectPopupExample`, + // $r('app.string.PolymorphicEffectPopupExample_title')需要替换为开发者所需的资源文件。 + title: resource.resourceToString($r('app.string.PolymorphicEffectPopupExample_title')), + // $r('app.string.PolymorphicEffectPopupExample_des')需要替换为开发者所需的资源文件。 + description: $r('app.string.PolymorphicEffectPopupExample_des'), + }, + { + name: `${Popup_ROUTE_PREFIX}/SupportedAvoidAxisPopupExample`, + // $r('app.string.SupportedAvoidAxisPopupExample_title')需要替换为开发者所需的资源文件。 + title: resource.resourceToString($r('app.string.SupportedAvoidAxisPopupExample_title')), + // $r('app.string.SupportedAvoidAxisPopupExample_des')需要替换为开发者所需的资源文件。 + description: $r('app.string.SupportedAvoidAxisPopupExample_des'), + }, { name: `${Popup_ROUTE_PREFIX}/OpenPopupExample`, title: resource.resourceToString($r('app.string.StylePopup_global')), @@ -82,6 +105,12 @@ export function PopupDestination(name: string) { } else if (name === routes[5].name) { StylePopupExample(); } else if (name === routes[6].name) { + AvoidSoftKeyboardPopupExample(); + } else if (name === routes[7].name) { + PolymorphicEffectPopupExample(); + } else if (name === routes[8].name) { + SupportedAvoidAxisPopupExample(); + } else if (name === routes[9].name) { OpenPopup(); } } diff --git a/ArkUIKit/DialogProject/entry/src/main/ets/pages/popup/PopupAnimation.ets b/ArkUIKit/DialogProject/entry/src/main/ets/pages/popup/PopupAnimation.ets index 2ef0e99f8..6335db86d 100644 --- a/ArkUIKit/DialogProject/entry/src/main/ets/pages/popup/PopupAnimation.ets +++ b/ArkUIKit/DialogProject/entry/src/main/ets/pages/popup/PopupAnimation.ets @@ -29,10 +29,9 @@ export struct AnimationPopupExample { build() { NavDestination() { Column({ space: 12 }) { - - // PopupOptions 类型设置弹框内容 Button('PopupOptions') + .id('PopupOptions') .margin({ top: 250 }) .onClick(() => { this.handlePopup = !this.handlePopup; @@ -53,9 +52,9 @@ export struct AnimationPopupExample { TransitionEffect.IDENTITY) }) - // CustomPopupOptions 类型设置弹框内容 Button('CustomPopupOptions') + .id('CustomPopupOptions') .margin({ top: 60 }) .onClick(() => { this.customPopup = !this.customPopup; @@ -72,14 +71,13 @@ export struct AnimationPopupExample { // 设置弹窗显示动效与退出动效为缩放动效 transition:TransitionEffect.scale({ x: 1, y: 0 }).animation({ duration: 500, curve: Curve.Ease }) }) - - } .width('100%') .height('100%') .padding({ left: 12, right: 12 }) } .backgroundColor('#f1f2f3') + // $r('app.string.AnimationPopup_title')需要替换为开发者所需的资源文件。 .title($r('app.string.AnimationPopup_title')) } } diff --git a/ArkUIKit/DialogProject/entry/src/main/ets/pages/popup/PopupAvoidSoftKeyboard.ets b/ArkUIKit/DialogProject/entry/src/main/ets/pages/popup/PopupAvoidSoftKeyboard.ets new file mode 100644 index 000000000..c8bcd9c49 --- /dev/null +++ b/ArkUIKit/DialogProject/entry/src/main/ets/pages/popup/PopupAvoidSoftKeyboard.ets @@ -0,0 +1,58 @@ +/* + * 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. + */ + +// [Start avoidSoftKeyboard_popup] +// xxx.ets +@Entry +@Component +export struct AvoidSoftKeyboardPopupExample { + @State handlePopup: boolean = false; + + @Builder + popupBuilder() { + Column({ space: 2 }) { + Text('Custom Popup').fontSize(20) + .borderWidth(2) + TextInput() + }.width(200).padding(5) + } + + build() { + NavDestination() { + Column({ space: 100 }) { + TextInput() + Button('PopupOptions') + .id('PopupOptions') + .onClick(() => { + this.handlePopup = !this.handlePopup; + }) + .bindPopup(this.handlePopup!!, { + width: 200, + builder: this.popupBuilder(), + placement: Placement.Bottom, + mask: false, + autoCancel: false, + keyboardAvoidMode: KeyboardAvoidMode.DEFAULT + }) + .position({ x: 100, y: 300 }) + } + .width('100%') + }.backgroundColor('#f1f2f3') + // $r('app.string.AvoidSoftKeyboardPopupExample_title')需要替换为开发者所需的资源文件。 + .title($r('app.string.AvoidSoftKeyboardPopupExample_title')) + } +} +// [End avoidSoftKeyboard_popup] + diff --git a/ArkUIKit/DialogProject/entry/src/main/ets/pages/popup/PopupPolymorphicEffect.ets b/ArkUIKit/DialogProject/entry/src/main/ets/pages/popup/PopupPolymorphicEffect.ets new file mode 100644 index 000000000..b1c1679d0 --- /dev/null +++ b/ArkUIKit/DialogProject/entry/src/main/ets/pages/popup/PopupPolymorphicEffect.ets @@ -0,0 +1,114 @@ +/* + * 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 { abilityDelegatorRegistry } from '@kit.TestKit'; + +// [Start polymorphicEffect_popup] +@Entry +@Component +export struct PolymorphicEffectPopupExample { + @State scan: string = + this.getUIContext().getHostContext()?.resourceManager.getStringByNameSync('Scan_title') as string; + @State createGroupChat: string = + this.getUIContext().getHostContext()?.resourceManager.getStringByNameSync('Create_group_chat') as string; + @State electronicWorkCard: string = + this.getUIContext().getHostContext()?.resourceManager.getStringByNameSync('Electronic_work_card') as string; + private menus: Array = [this.scan, this.createGroupChat, this.electronicWorkCard]; + + // popup构造器定义弹框内容 + @Builder + popupItemBuilder(name: string, action: string) { + PopupItemChild({ childName: name, childAction: action }) + } + + // popup构造器定义弹框内容 + @Builder + popupBuilder() { + Column() { + ForEach( + this.menus, + (item: string, index) => { + this.popupItemBuilder(item, String(index)) + }, + (item: string, index) => { + return item + }) + } + .padding(8) + } + + @State customPopup: boolean = false; + + build() { + NavDestination() { + Column() { + Button('click me') + .id('click me') + .onClick(() => { + this.customPopup = !this.customPopup + }) + .bindPopup( + this.customPopup, + { + builder: this.popupBuilder, // 气泡的内容 + placement: Placement.Bottom, // 气泡的弹出位置 + popupColor: Color.White, // 气泡的背景色 + onStateChange: (event) => { + if (!event.isVisible) { + this.customPopup = false + } + } + }) + } + .width('100%') + .justifyContent(FlexAlign.Center) + }.backgroundColor('#f1f2f3') + // $r('app.string.PolymorphicEffectPopupExample_title')需要替换为开发者所需的资源文件。 + .title($r('app.string.PolymorphicEffectPopupExample_title')) + } +} + +@Component +struct PopupItemChild { + @Prop childName: string = ''; + @Prop childAction: string = ''; + @State selected: string = + this.getUIContext().getHostContext()?.resourceManager.getStringByNameSync('Selected') as string; + + build() { + Row({ space: 8 }) { + // $r('app.media.startIcon')需要替换为开发者所需的图像资源文件。 + Image($r('app.media.startIcon')) + .width(24) + .height(24) + Text(this.childName) + .fontSize(16) + } + .width(130) + .height(50) + .padding(8) + .onClick(() => { + this.getUIContext().getPromptAction().showToast({ message: this.selected + this.childName }) + }) + .stateStyles({ + normal: { + .backgroundColor(Color.White) + }, + pressed: { + .backgroundColor('#1fbb7d') + } + }) + } +} +// [End polymorphicEffect_popup] \ No newline at end of file diff --git a/ArkUIKit/DialogProject/entry/src/main/ets/pages/popup/PopupStateChange.ets b/ArkUIKit/DialogProject/entry/src/main/ets/pages/popup/PopupStateChange.ets index a9fc84f98..d8a8da864 100644 --- a/ArkUIKit/DialogProject/entry/src/main/ets/pages/popup/PopupStateChange.ets +++ b/ArkUIKit/DialogProject/entry/src/main/ets/pages/popup/PopupStateChange.ets @@ -25,6 +25,7 @@ export struct StatePopupExample { Column() { Button('PopupOptions') + .id('PopupOptions') .margin({ top: 300 }) .onClick(() => { this.handlePopup = !this.handlePopup; @@ -45,6 +46,7 @@ export struct StatePopupExample { .padding({ left: 12, right: 12 }) } .backgroundColor('#f1f2f3') + // $r('app.string.onStateChange_title')需要替换为开发者所需的资源文件。 .title($r('app.string.onStateChange_title')) } } diff --git a/ArkUIKit/DialogProject/entry/src/main/ets/pages/popup/PopupStyle.ets b/ArkUIKit/DialogProject/entry/src/main/ets/pages/popup/PopupStyle.ets index 32426e332..da2b18db1 100644 --- a/ArkUIKit/DialogProject/entry/src/main/ets/pages/popup/PopupStyle.ets +++ b/ArkUIKit/DialogProject/entry/src/main/ets/pages/popup/PopupStyle.ets @@ -23,6 +23,7 @@ export struct StylePopupExample { @Builder popupBuilder() { Row({ space: 2 }) { + // $r('app.media.app_icon')需要替换为开发者所需的资源文件。 Image($r('app.media.app_icon')).width(24).height(24).margin({ left: 5 }) Text('This is Custom Popup').fontSize(15) }.width(200).height(50).padding(5) @@ -57,6 +58,7 @@ export struct StylePopupExample { .padding({ left: 12, right: 12 }) } .backgroundColor('#f1f2f3') + // $r('app.string.StylePopup_title')需要替换为开发者所需的资源文件。 .title($r('app.string.StylePopup_title')) } } diff --git a/ArkUIKit/DialogProject/entry/src/main/ets/pages/popup/PopupSupportedAvoidAxis.ets b/ArkUIKit/DialogProject/entry/src/main/ets/pages/popup/PopupSupportedAvoidAxis.ets new file mode 100644 index 000000000..a35449867 --- /dev/null +++ b/ArkUIKit/DialogProject/entry/src/main/ets/pages/popup/PopupSupportedAvoidAxis.ets @@ -0,0 +1,104 @@ +/* + * 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. + */ + +// [Start supportedAvoidAxis_popup] +@Entry +@Component +export struct SupportedAvoidAxisPopupExample { + @State upScreen: string = + this.getUIContext().getHostContext()?.resourceManager.getStringByNameSync('Upper_half_screen') as string; + @State middleAxle: string = + this.getUIContext().getHostContext()?.resourceManager.getStringByNameSync('Middle_axle') as string; + @State lowerScreen: string = + this.getUIContext().getHostContext()?.resourceManager.getStringByNameSync('Lower_half_screen') as string; + @State subwindowDisplay: string = + this.getUIContext().getHostContext()?.resourceManager.getStringByNameSync('Subwindow_display') as string; + @State subwindow: string = + this.getUIContext().getHostContext()?.resourceManager.getStringByNameSync('Subwindow') as string; + @State nonSubwindow: string = + this.getUIContext().getHostContext()?.resourceManager.getStringByNameSync('Non_Subwindow') as string; + @State zone: string = + this.getUIContext().getHostContext()?.resourceManager.getStringByNameSync('zone') as string; + @State hoverModeStart: string = + this.getUIContext().getHostContext()?.resourceManager.getStringByNameSync('hoverMode_start') as string; + + @State message: string = 'Hello World'; + @State index: number = 0; + @State arrayStr: Array = [this.upScreen, this.middleAxle, this.lowerScreen]; + @State enableHoverMode: boolean | undefined = true; + @State showInSubwindow: boolean = false; + @State placement: Placement | undefined = undefined; + @State isShow: boolean = false; + + build() { + NavDestination() { + RelativeContainer() { + Column() { + Button(this.zone + this.arrayStr[this.index]) + .onClick(() => { + if (this.index < 2) { + this.index++ + } else { + this.index = 0 + } + }) + + Button(this.subwindowDisplay + (this.showInSubwindow ? this.subwindow : this.nonSubwindow)) + .onClick(() => { + this.showInSubwindow = !this.showInSubwindow + }) + + Button(this.hoverModeStart + this.enableHoverMode) + .onClick(() => { + if (this.enableHoverMode === undefined) { + this.enableHoverMode = true + } else if (this.enableHoverMode === true) { + this.enableHoverMode = false + } else { + this.enableHoverMode = undefined + } + }) + } + + Row() { + Button('Popup') + .id('Popup') + .fontWeight(FontWeight.Bold) + .bindPopup(this.isShow, { + message: 'popup', + enableHoverMode: this.enableHoverMode, + showInSubWindow: this.showInSubwindow, + }) + .onClick(() => { + this.isShow = !this.isShow + }) + } + .alignRules({ + center: { anchor: '__container__', align: VerticalAlign.Center }, + middle: { anchor: '__container__', align: HorizontalAlign.Center } + }) + .margin({ + top: this.index === 2 ? 330 : this.index === 1 ? 50 : 0, + bottom: this.index === 0 ? 330 : 0 + }) + } + .height('100%') + .width('100%') + }.backgroundColor('#f1f2f3') + // $r('app.string.SupportedAvoidAxisPopupExample_title')需要替换为开发者所需的资源文件。 + .title($r('app.string.SupportedAvoidAxisPopupExample_title')) + } +} +// [End supportedAvoidAxis_popup] \ No newline at end of file diff --git a/ArkUIKit/DialogProject/entry/src/main/ets/pages/popup/TextPrompts.ets b/ArkUIKit/DialogProject/entry/src/main/ets/pages/popup/TextPrompts.ets index 4ff872db5..df50c95e2 100644 --- a/ArkUIKit/DialogProject/entry/src/main/ets/pages/popup/TextPrompts.ets +++ b/ArkUIKit/DialogProject/entry/src/main/ets/pages/popup/TextPrompts.ets @@ -25,6 +25,7 @@ export struct TextPopupExample { Column() { Button('PopupOptions') + .id('PopupOptions') .margin({ top: 300 }) .onClick(() => { this.handlePopup = !this.handlePopup; @@ -40,6 +41,7 @@ export struct TextPopupExample { .padding({ left: 12, right: 12 }) } .backgroundColor('#f1f2f3') + // $r('app.string.TextPopup_title')需要替换为开发者所需的资源文件。 .title($r('app.string.TextPopup_title')) } } diff --git a/ArkUIKit/DialogProject/entry/src/main/module.json5 b/ArkUIKit/DialogProject/entry/src/main/module.json5 index f09d09a7b..21cf7f833 100644 --- a/ArkUIKit/DialogProject/entry/src/main/module.json5 +++ b/ArkUIKit/DialogProject/entry/src/main/module.json5 @@ -60,6 +60,13 @@ } ] } - ] + ], + // [Start menu_permissions] + "requestPermissions": [ + { + "name": "ohos.permission.VIBRATE", + } + ], + // [End menu_permissions] } } \ No newline at end of file diff --git a/ArkUIKit/DialogProject/entry/src/main/resources/base/element/string.json b/ArkUIKit/DialogProject/entry/src/main/resources/base/element/string.json index c3c2d7c5c..b145c062a 100644 --- a/ArkUIKit/DialogProject/entry/src/main/resources/base/element/string.json +++ b/ArkUIKit/DialogProject/entry/src/main/resources/base/element/string.json @@ -144,6 +144,10 @@ "name": "CustomDialog_date", "value": "日期滑动选择器弹窗" }, + { + "name": "CustomCustomDialog_date", + "value": "日期滑动选择器自定义弹窗" + }, { "name": "CustomDialog_text", "value": "文本滑动选择器弹窗" @@ -168,6 +172,14 @@ "name": "DatePicker_des", "value": "开发者可以利用指定的日期范围,创建日期滑动选择器弹窗,将日期信息清晰地展示在弹出的窗口上。" }, + { + "name": "DatePickerCustom_title", + "value": "日期滑动选择器自定义弹窗" + }, + { + "name": "DatePickerCustom_des", + "value": "开发者可以利用指定的日期范围,创建日期滑动选择器自定义弹窗,将日期信息清晰地展示在弹出的窗口上。" + }, { "name": "TimePicker_title", "value": "时间滑动选择器弹窗" @@ -436,6 +448,30 @@ "name": "StylePopup_des", "value": "气泡除了可以通过builder实现自定义气泡,还可以通过接口设置气泡的样式和显示效果。" }, + { + "name": "AvoidSoftKeyboardPopupExample_title", + "value": "气泡避让软键盘" + }, + { + "name": "AvoidSoftKeyboardPopupExample_des", + "value": "当软键盘弹出时,气泡默认不会对其避让,可能导致气泡被软键盘覆盖,这时需要设置keyboardAvoidMode为KeyboardAvoidMode.DEFAULT,来使气泡避让键盘。这时如果当前没有位置放下气泡时,气泡会从预设位置平移覆盖宿主组件。" + }, + { + "name": "PolymorphicEffectPopupExample_title", + "value": "设置气泡内的多态效果" + }, + { + "name": "PolymorphicEffectPopupExample_des", + "value": "目前使用@Builder自定义气泡内容时,默认不支持多态样式,可以使用@Component新建一个组件实现按下气泡中的内容时背景变色。" + }, + { + "name": "SupportedAvoidAxisPopupExample_title", + "value": "气泡支持避让中轴" + }, + { + "name": "SupportedAvoidAxisPopupExample_des", + "value": "从API version 18起,气泡支持中轴避让功能。从API version 20开始,在2in1设备上默认启用(仅在窗口处于瀑布模式时产生避让)。开发者可通过PopupOptions中的enableHoverMode属性,控制气泡是否启用中轴避让。" + }, { "name": "StylePopup_global_des", "value": "通过使用全局接口openPopup的方式,在无UI组件的场景下直接或封装使用。" @@ -516,6 +552,150 @@ "name": "DefaultAndTopToast_des", "value": "即时反馈提供了两种显示模式,分别为DEFAULT(显示在应用内)、TOP_MOST(显示在应用之上)。" }, + { + "name": "CreateCustomDialog1_title", + "value": "创建自定义弹出框1" + }, + { + "name": "CreateCustomDialog1_desc", + "value": "使用@CustomDialog装饰器装饰自定义弹出框,可在此装饰器内自定义弹出框内容。CustomDialogController需在@Component内定义。" + }, + { + "name": "DialogInteraction2_title", + "value": "弹出框的交互2" + }, + { + "name": "DialogInteraction2_desc", + "value": "页面内需要在构造器内进行接收,同时创建相应的函数操作。" + }, + { + "name": "DialogInteraction3_title", + "value": "弹出框的交互3" + }, + { + "name": "DialogInteraction3_desc", + "value": "可通过弹出框中的按钮实现路由跳转,同时获取跳转页面向当前页传入的参数。" + }, + { + "name": "DialogAnimation1_title", + "value": "弹出框的动画1" + }, + { + "name": "DialogAnimation1_desc", + "value": "弹出框通过定义openAnimation控制弹出框出现动画的持续时间,速度等参数。" + }, + { + "name": "DialogStyle1_title", + "value": "弹出框的样式1" + }, + { + "name": "DialogStyle1_desc", + "value": "通过定义弹出框的宽度、高度、背景色、阴影等参数,控制其样式。" + }, + { + "name": "NestDialog1_title", + "value": "嵌套自定义弹出框1" + }, + { + "name": "NestDialog1_desc", + "value": "通过第一个弹出框打开第二个弹出框时,最好将第二个弹出框定义在第一个弹出框的父组件处,通过父组件传给第一个弹出框的回调来打开第二个弹出框。" + }, + { + "name": "DialogWithPhysicalBack_title", + "value": "实现弹出框的物理返回拦截" + }, + { + "name": "DialogWithPhysicalBack_desc", + "value": "执行点击遮障层关闭、侧滑(左滑或右滑)、三键Back、键盘ESC关闭等交互操作时,如果注册了CustomDialogControllerOptions中的onWillDismiss回调函数,弹出框不会立即关闭。在回调函数中,通过DismissDialogAction中的reason属性获取阻拦关闭弹出框的操作类型,根据原因决定是否关闭弹出框。" + }, + { + "name": "DialogAvoidSoftKeyboard_title", + "value": "设置弹出框避让软键盘的距离" + }, + { + "name": "DialogAvoidSoftKeyboard_desc", + "value": "为显示弹出框的独立性,弹出框弹出时会与周边进行避让,包括状态栏、导航条以及键盘等留有间距。故当软键盘弹出时,默认情况下,弹出框会自动避开软键盘,并与之保持16vp的距离。从API version 15开始,开发者可以利用CustomDialogControllerOptions中的keyboardAvoidMode和keyboardAvoidDistance这两个配置项,来设置弹出框在软键盘弹出时的行为,包括是否需要避开软键盘以及与软键盘之间的距离。" + }, + { + "name": "GetDialogStatus_title", + "value": "获取弹出框的状态" + }, + { + "name": "GetDialogStatus_desc", + "value": "在业务模块中,页面上可能会同时出现多个弹出框。为避免重复打开相同的弹出框,建议在显示弹出框前,先通过控制器检查其当前状态。如果弹出框已处于显示状态,则不应再次打开。" + }, + { + "name": "i_am_content", + "value": "我是内容" + }, + { + "name": "customDialogComponentWithTransition_title", + "value": "为弹出框内容和蒙层设置不同的动画效果" + }, + { + "name": "customDialogComponentWithTransition_desc", + "value": "当弹出框出现时,内容与蒙层显示动效一致。若开发者希望为弹出框内容及蒙层设定不同动画效果,从API version 19开始,可通过BaseDialogOptions中dialogTransition和maskTransition属性单独配置弹窗内容与蒙层的动画。具体的动画效果请参考组件内转场 (transition)。" + }, + { + "name": "customDialogWithKeyboardAvoidDistance_title", + "value": "设置弹出框避让软键盘的距离" + }, + { + "name": "customDialogWithKeyboardAvoidDistance_desc", + "value": "为显示弹出框的独立性,弹出框弹出时会与周边进行避让,包括状态栏、导航条以及键盘等留有间距。故当软键盘弹出时,默认情况下,弹出框会自动避开软键盘,并与之保持16vp的距离。从API version 15开始,开发者可以利用BaseDialogOptions中的keyboardAvoidMode和keyboardAvoidDistance这两个配置项,来设置弹出框在软键盘弹出时的行为,包括是否需要避开软键盘以及与软键盘之间的距离。" + }, + { + "name": "OpenDialogAndUpdate_title", + "value": "完整示例" + }, + { + "name": "OpenDialogAndUpdate_desc", + "value": "完整示例。" + }, + { + "name": "open_windows", + "value": "打开弹窗" + }, + { + "name": "the_second_page_is", + "value": "第二个页面的内容为" + }, + { + "name": "wether_to_get_the_second_page", + "value": "是否获取第二个页面的内容" + }, + { + "name": "click_and_return", + "value": "点击返回" + }, + { + "name": "this_is_a_window", + "value": "这是一个弹窗" + }, + { + "name": "Mask_CustomDialog_dialog", + "value": "弹出框蒙层控制" + }, + { + "name": "MaskDialog", + "value": "弹出框蒙层控制/MaskDialog" + }, + { + "name": "CustomDialogAnimation_title", + "value": "openAnimation和closeAnimation接口" + }, + { + "name": "CustomDialogAnimation_desc", + "value": "CustomDialog虽然不支持transition接口,但与之对应的openAnimation和closeAnimation接口在动画的打开和关闭时可进行定制。" + }, + { + "name": "CustomDialogControl_title", + "value": "弹出框蒙层显隐控制" + }, + { + "name": "CustomDialogControl_desc", + "value": "展示弹出框在蒙层显隐控制方面的能力。" + }, { "name": "DefaultAndTopToast_defaultToast", "value": "DEFAULT类型Toast" @@ -532,6 +712,90 @@ "name": "DefaultAndTopToast_topToastMessage", "value": "ok,我是TOP_MOST toast" }, + { + "name": "Scan_title", + "value": "扫一扫" + }, + { + "name": "Create_group_chat", + "value": "创建群聊" + }, + { + "name": "Electronic_work_card", + "value": "电子工卡" + }, + { + "name": "Selected", + "value": "选中了" + }, + { + "name": "Upper_half_screen", + "value": "上半屏" + }, + { + "name": "Middle_axle", + "value": "中轴" + }, + { + "name": "Lower_half_screen", + "value": "下半屏" + }, + { + "name": "Subwindow_display", + "value": "子窗显示" + }, + { + "name": "Subwindow", + "value": "子窗" + }, + { + "name": "Non_Subwindow", + "value": "非子窗" + }, + { + "name": "zone", + "value": "区域" + }, + { + "name": "hoverMode_start", + "value": "hoverMode开启" + }, + { + "name": "PopVibrateMenu_title", + "value": "菜单弹出时振动效果" + }, + { + "name": "PopVibrateMenu_des", + "value": "菜单弹出时,默认不振动。若希望菜单弹出时有振动效果,可以通过ContextMenuOptions的hapticFeedbackMode属性,设置菜单弹出时的振动模式。" + }, + { + "name": "Click_for_menu", + "value": "click for Menu" + }, + { + "name": "SupportAvoidCentralAxisMenu_title", + "value": "菜单支持避让中轴" + }, + { + "name": "SupportAvoidCentralAxisMenu_des", + "value": "从API version 18起,菜单支持中轴避让功能。从API version 20开始,在2in1设备上默认启用(仅在窗口处于瀑布模式时产生避让)。开发者可通过ContextMenuOptions中的enableHoverMode属性,控制菜单是否启用中轴避让。" + }, + { + "name": "EventTransSubWindowMenu_title", + "value": "控制子窗菜单的事件透传" + }, + { + "name": "EventTransSubWindowMenu_des", + "value": "当菜单在子窗口中弹出时,默认情况下,菜单周围的事件会传递至所在窗口。从API version 20开始,开发者可通过ContextMenuOptions的modalMode属性设置子菜单弹出时的模态模式,以控制菜单周围事件是否传递。将modalMode设置为ModalMode.TARGET_WINDOW时,菜单周围的事件将不再传递,菜单下方的控件也不会响应事件。" + }, + { + "name": "BindComponentMenu_title", + "value": "基于绑定组件指定位置弹出菜单" + }, + { + "name": "BindComponentMenu_des", + "value": "菜单从API version 20开始支持基于绑定组件在指定位置弹出。通过设置水平与垂直偏移量,控制菜单相对于绑定组件左上角的弹出位置。与单独使用offset接口不同,此方法可使菜单覆盖显示在绑定组件上。需要指定弹出位置时,可使用ContextMenuOptions的anchorPosition属性进行设置。" + }, { "name": "closeDialog_by_id", "value": "点击关闭弹窗:通过DialogID" @@ -559,6 +823,10 @@ { "name": "closeDialog_by_dialog_controller", "value": "点击关闭弹窗:通过外部传递的DialogController" + }, + { + "name": "close_widows", + "value": "点我关闭弹窗" } ] } \ No newline at end of file diff --git a/ArkUIKit/DialogProject/entry/src/main/syscap.json b/ArkUIKit/DialogProject/entry/src/main/syscap.json index 33b442171..2ecac78f6 100644 --- a/ArkUIKit/DialogProject/entry/src/main/syscap.json +++ b/ArkUIKit/DialogProject/entry/src/main/syscap.json @@ -3,29 +3,19 @@ "devices": { "general": [ "default" - ] - }, - "production": { - "removedSysCaps": [ - "SystemCapability.HiviewDFX.HiDumper", - "SystemCapability.Security.DeviceAuth", - "SystemCapability.Multimedia.Media.AVTranscoder", - "SystemCapability.Tee.TeeClient", - "SystemCapability.Communication.Bluetooth.Core", - "SystemCapability.ArkUi.Graphics3D", - "SystemCapability.DistributedHardware.DeviceManager", - "SystemCapability.Multimedia.Drm.Core", - "SystemCapability.Advertising.Ads", - "SystemCapability.Customization.EnterpriseDeviceManager", - "SystemCapability.Security.DeviceSecurityLevel", - "SystemCapability.UserIAM.UserAuth.PinAuth" - ] - }, - "custom": [ + ], + "custom": [ { "xts": [ - "SystemCapability.Graphic.Graphic2D.NativeDrawing" + "systemcapability.graphic.graphic2d.nativedrawing" ] } ] + }, + "production": { + "removedsyscaps": [ + "systemcapability.security.devicesecuritylevel", + "systemcapability.useriam.userauth.pinauth" + ] + } } diff --git a/ArkUIKit/DialogProject/entry/src/ohosTest/ets/test/Index.test.ets b/ArkUIKit/DialogProject/entry/src/ohosTest/ets/test/Index.test.ets index d5259895a..3e38b74f8 100644 --- a/ArkUIKit/DialogProject/entry/src/ohosTest/ets/test/Index.test.ets +++ b/ArkUIKit/DialogProject/entry/src/ohosTest/ets/test/Index.test.ets @@ -23,6 +23,8 @@ import resource from '../../../main/ets/common/resource'; const delegator: abilityDelegatorRegistry.AbilityDelegator = abilityDelegatorRegistry.getAbilityDelegator() const bundleName = abilityDelegatorRegistry.getArguments().bundleName; let want: Want; +const ONE_SECONDS_TIME = 1000; +const ONE_SECONDS_TIME2 = 10000; function sleep(time: number) { return new Promise((resolve: Function) => setTimeout(resolve, time)); @@ -39,7 +41,7 @@ export default function IndexTest() { abilityName: 'EntryAbility' }; await delegator.startAbility(want); - await sleep(1000); + await sleep(ONE_SECONDS_TIME); const ability: UIAbility = await delegator.getCurrentTopAbility(); console.info("get top ability"); expect(ability.context.abilityInfo.name).assertEqual('EntryAbility'); @@ -58,14 +60,71 @@ export default function IndexTest() { let button2 = await driver.findComponent(ON.text(resource.resourceToString($r('app.string.change_dialog')), MatchPattern.CONTAINS)); await button2.click(); + await sleep(ONE_SECONDS_TIME); + await driver.pressBack(); + await driver.pressBack(); + await driver.pressBack(); + done(); + }) + + it('testCustomDialogComponentWithTransition', 0, async (done: Function) => { + let driver = Driver.create(); + let button_list = await driver.findComponent(ON.text('openCustomDialog', MatchPattern.CONTAINS)); + expect(button_list === null).assertFalse(); + await button_list.click(); + let button_customDialogComponentWithTransition = await driver.findComponent(ON.text(resource.resourceToString($r('app.string.customDialogComponentWithTransition_title')), MatchPattern.CONTAINS)); + await button_customDialogComponentWithTransition.click(); + let text_open = await driver.findComponent(ON.text($r('app.string.CustomDialog_nest'), MatchPattern.CONTAINS)); + expect(text_open === null).assertFalse(); + await text_open.click(); + await sleep(5000); + await driver.pressBack(); + await sleep(5000); + await driver.pressBack(); + done(); + }) + + it('testcustomDialogWithKeyboardAvoidDistance', 0, async (done: Function) => { + let driver = Driver.create(); + let button_list = await driver.findComponent(ON.text('openCustomDialog', MatchPattern.CONTAINS)); + expect(button_list === null).assertFalse(); + await button_list.click(); + let button_customDialogWithKeyboardAvoidDistance = await driver.findComponent(ON.text(resource.resourceToString($r('app.string.customDialogWithKeyboardAvoidDistance_title')), MatchPattern.CONTAINS)); + await button_customDialogWithKeyboardAvoidDistance.click(); + let text_customDialogWithKeyboardAvoidDistance_open = await driver.findComponent(ON.text($r('app.string.CustomDialog_nest'), MatchPattern.CONTAINS)); + await text_customDialogWithKeyboardAvoidDistance_open.click(); + await sleep(1000); + let textinputComponent = await driver.findComponent(ON.type('TextInput')) + await textinputComponent.click(); await sleep(1000); await driver.pressBack(); + await sleep(1000); await driver.pressBack(); + await sleep(1000); await driver.pressBack(); done(); }) - it('testCustomDialog', 0, async (done: Function) => { + it('testOpenDialogAndUpdate', 0, async (done: Function) => { + let driver = Driver.create(); + let button_list = await driver.findComponent(ON.text('openCustomDialog', MatchPattern.CONTAINS)); + expect(button_list === null).assertFalse(); + await button_list.click(); + let button_customDialogWithKeyboardAvoidDistance = await driver.findComponent(ON.text(resource.resourceToString($r('app.string.OpenDialogAndUpdate_title')), MatchPattern.CONTAINS)); + await button_customDialogWithKeyboardAvoidDistance.click(); + let text_OpenDialogAndUpdate_update_options = await driver.findComponent(ON.text('open dialog and update options', MatchPattern.CONTAINS)); + await text_OpenDialogAndUpdate_update_options.click(); + await sleep(3000); + await driver.pressBack(); + let text_OpenDialogAndUpdate_update_content = await driver.findComponent(ON.text('open dialog and update content', MatchPattern.CONTAINS)); + await text_OpenDialogAndUpdate_update_content.click(); + await sleep(3000); + await driver.pressBack(); + await driver.pressBack(); + done(); + }) + + it('testCustomDialog', 60000, async (done: Function) => { console.info("uitest: testCustomDialog begin"); let driver = Driver.create(); let button_list = await driver.findComponent(ON.text(resource.resourceToString($r('app.string.CustomDialog1')), MatchPattern.CONTAINS)); @@ -82,7 +141,102 @@ export default function IndexTest() { await button_list4.click(); await driver.pressBack(); await driver.pressBack(); + + await sleep(1000); + + let button_createCustomDialog1 = await driver.findComponent(ON.text(resource.resourceToString($r('app.string.CreateCustomDialog1_title')), MatchPattern.CONTAINS)); + await button_createCustomDialog1.click(); + let button_createCustomDialog1_click = await driver.findComponent(ON.text('click me', MatchPattern.CONTAINS)); + await button_createCustomDialog1_click.click(); + await driver.pressBack(); + await driver.pressBack(); + + let button_dialogInteraction2 = await driver.findComponent(ON.text(resource.resourceToString($r('app.string.DialogInteraction2_title')), MatchPattern.CONTAINS)); + await button_dialogInteraction2.click(); + let button_dialogInteraction2_click = await driver.findComponent(ON.text('click me', MatchPattern.CONTAINS)); + await button_dialogInteraction2_click.click(); + let button_dialogInteraction2_confirm = await driver.findComponent(ON.text('confirm', MatchPattern.CONTAINS)); + await button_dialogInteraction2_confirm.click(); + await driver.pressBack(); + + let stackList = await driver.findComponent(ON.type('List')); + await stackList.scrollSearch(ON.text(resource.resourceToString($r('app.string.DialogInteraction3_title')))); + + let button_dialogInteraction3 = await driver.findComponent(ON.text(resource.resourceToString($r('app.string.DialogInteraction3_title')), MatchPattern.CONTAINS)); + await button_dialogInteraction3.click(); + let button_dialogInteraction3_click = await driver.findComponent(ON.text('click me', MatchPattern.CONTAINS)); + await button_dialogInteraction3_click.click(); + let button_dialogInteraction3_confirm = await driver.findComponent(ON.text('confirm', MatchPattern.CONTAINS)); + await button_dialogInteraction3_confirm.click(); + let button_dialogInteraction3_return = await driver.findComponent(ON.text($r('app.string.click_and_return'), MatchPattern.CONTAINS)); + await button_dialogInteraction3_return.click(); + await sleep(1000); + await driver.pressBack(); + await sleep(1000); + + await stackList.scrollToBottom() + + let button_dialogAnimation1 = await driver.findComponent(ON.text(resource.resourceToString($r('app.string.DialogAnimation1_title')), MatchPattern.CONTAINS)); + await button_dialogAnimation1.click(); + let button_dialogAnimation1_click = await driver.findComponent(ON.text('click me', MatchPattern.CONTAINS)); + await button_dialogAnimation1_click.click(); + await driver.pressBack(); + await driver.pressBack(); + + let button_dialogStyle1 = await driver.findComponent(ON.text(resource.resourceToString($r('app.string.DialogStyle1_title')), MatchPattern.CONTAINS)); + await button_dialogStyle1.click(); + let button_dialogStyle1_click = await driver.findComponent(ON.text('click me', MatchPattern.CONTAINS)); + await button_dialogStyle1_click.click(); + await driver.pressBack(); + await driver.pressBack(); + + let button_nestDialog1 = await driver.findComponent(ON.text(resource.resourceToString($r('app.string.NestDialog1_title')), MatchPattern.CONTAINS)); + await button_nestDialog1.click(); + let button_nestDialog1_click = await driver.findComponent(ON.text('Click Me', MatchPattern.CONTAINS)); + await button_nestDialog1_click.click(); + let button_nestDialog1_open = await driver.findComponent(ON.text('Open Second Dialog Box and close this box', MatchPattern.CONTAINS)); + await button_nestDialog1_open.click(); + let button_nestDialog1_create_text = await driver.findComponent(ON.text('Create Text', MatchPattern.CONTAINS)); + await button_nestDialog1_create_text.click(); + let button_nestDialog1_close = await driver.findComponent(ON.text('Close Second Dialog Box', MatchPattern.CONTAINS)); + await button_nestDialog1_close.click(); + await driver.pressBack(); + + let button_dialogWithPhysicalBack = await driver.findComponent(ON.text(resource.resourceToString($r('app.string.DialogWithPhysicalBack_title')), MatchPattern.CONTAINS)); + await button_dialogWithPhysicalBack.click(); + let button_dialogWithPhysicalBack_click = await driver.findComponent(ON.text('click me', MatchPattern.CONTAINS)); + await button_dialogWithPhysicalBack_click.click(); + let button_dialogWithPhysicalBack_confirm = await driver.findComponent(ON.text('confirm', MatchPattern.CONTAINS)); + await button_dialogWithPhysicalBack_confirm.click(); + await driver.pressBack(); + + let button_getDialogStatus = await driver.findComponent(ON.text(resource.resourceToString($r('app.string.GetDialogStatus_title')), MatchPattern.CONTAINS)); + await button_getDialogStatus.click(); + let button_button_getDialogStatus_click = await driver.findComponent(ON.text('click me', MatchPattern.CONTAINS)); + await button_button_getDialogStatus_click.click(); + let button_button_getDialogStatus_custom = await driver.findComponent(ON.text($r('app.string.closeDialog_by_dialog'), MatchPattern.CONTAINS)); + await button_button_getDialogStatus_custom.click(); + let button_button_getDialogStatus_custom_controller = await driver.findComponent(ON.text($r('app.string.closeDialog_by_dialog_controller'), MatchPattern.CONTAINS)); + await button_button_getDialogStatus_custom_controller.click(); + let button_button_getDialogStatus_close = await driver.findComponent(ON.text($r('app.string.close_widows'), MatchPattern.CONTAINS)); + await button_button_getDialogStatus_close.click(); + await driver.pressBack(); + + let button_dialogAvoidSoftKeyboard = await driver.findComponent(ON.text(resource.resourceToString($r('app.string.DialogAvoidSoftKeyboard_title')), MatchPattern.CONTAINS)); + await button_dialogAvoidSoftKeyboard.click(); + let text_dialogWithPhysicalBack_open = await driver.findComponent(ON.text($r('app.string.open_windows'), MatchPattern.CONTAINS)); + await text_dialogWithPhysicalBack_open.click(); + await sleep(1000); + let textinputComponent = await driver.findComponent(ON.type('TextInput')) + await textinputComponent.click(); + await sleep(1000); + await driver.pressBack(); + await sleep(1000); + await driver.pressBack(); await sleep(1000); + await driver.pressBack(); + + await sleep(ONE_SECONDS_TIME); done(); }) @@ -97,10 +251,10 @@ export default function IndexTest() { await driver.findComponent(ON.text(resource.resourceToString($r('app.string.CustomDialog_focus')), MatchPattern.CONTAINS)); await button_list1.click(); - await sleep(1000); + await sleep(ONE_SECONDS_TIME); await driver.pressBack(); await driver.pressBack(); - await sleep(1000); + await sleep(ONE_SECONDS_TIME); done(); }) @@ -111,23 +265,23 @@ export default function IndexTest() { MatchPattern.CONTAINS)); expect(button_list === null).assertFalse(); await button_list.click(); - await sleep(1000); + await sleep(ONE_SECONDS_TIME); let button_list1 = await driver.findComponent(ON.text(resource.resourceToString($r('app.string.StylePopup_global')), MatchPattern.CONTAINS)); await button_list1.click(); - await sleep(1000); + await sleep(ONE_SECONDS_TIME); let button_list2 = await driver.findComponent(ON.text('openPopup', MatchPattern.CONTAINS)); await button_list2.click(); - await sleep(1000); + await sleep(ONE_SECONDS_TIME); let button_list3 = await driver.findComponent(ON.text('Update', MatchPattern.CONTAINS)); await button_list3.click(); let button_list4 = await driver.findComponent(ON.text('Close', MatchPattern.CONTAINS)); await button_list4.click(); - await sleep(1000); + await sleep(ONE_SECONDS_TIME); await driver.pressBack(); await driver.pressBack(); - await sleep(1000); + await sleep(ONE_SECONDS_TIME); done(); }) @@ -138,15 +292,15 @@ export default function IndexTest() { MatchPattern.CONTAINS)); expect(button_list === null).assertFalse(); await button_list.click(); - await sleep(1000); + await sleep(ONE_SECONDS_TIME); let button_list1 = await driver.findComponent(ON.text(resource.resourceToString($r('app.string.CustomDialog_controller')), MatchPattern.CONTAINS)); await button_list1.click(); - await sleep(1000); + await sleep(ONE_SECONDS_TIME); await driver.pressBack(); await driver.pressBack(); - await sleep(1000); + await sleep(ONE_SECONDS_TIME); done(); }) @@ -157,16 +311,16 @@ export default function IndexTest() { MatchPattern.CONTAINS)); expect(button_list === null).assertFalse(); await button_list.click(); - await sleep(1000); - await driver.fling(UiDirection.DOWN, 10000); + await sleep(ONE_SECONDS_TIME); + await driver.fling(UiDirection.DOWN, ONE_SECONDS_TIME2); let button_list1 = await driver.findComponent(ON.text(resource.resourceToString($r('app.string.CustomDialog_page_level')), MatchPattern.CONTAINS)); await button_list1.click(); - await sleep(1000); + await sleep(ONE_SECONDS_TIME); await driver.pressBack(); await driver.pressBack(); - await sleep(1000); + await sleep(ONE_SECONDS_TIME); done(); }) @@ -177,15 +331,15 @@ export default function IndexTest() { MatchPattern.CONTAINS)); expect(button_list === null).assertFalse(); await button_list.click(); - await sleep(1000); + await sleep(ONE_SECONDS_TIME); let button_list1 = await driver.findComponent(ON.text(resource.resourceToString($r('app.string.OpenMenu_title')), MatchPattern.CONTAINS)); await button_list1.click(); - await sleep(1000); + await sleep(ONE_SECONDS_TIME); await driver.pressBack(); await driver.pressBack(); - await sleep(1000); + await sleep(ONE_SECONDS_TIME); done(); }) @@ -196,16 +350,139 @@ export default function IndexTest() { MatchPattern.CONTAINS)); expect(button_list === null).assertFalse(); await button_list.click(); - await sleep(1000); - await driver.fling(UiDirection.DOWN, 10000); + await sleep(ONE_SECONDS_TIME); + await driver.fling(UiDirection.DOWN, ONE_SECONDS_TIME2); let button_list1 = await driver.findComponent(ON.text(resource.resourceToString($r('app.string.CustomDialog_box_layer')), MatchPattern.CONTAINS)); await button_list1.click(); - await sleep(1000); + await sleep(ONE_SECONDS_TIME); await driver.pressBack(); await driver.pressBack(); - await sleep(1000); + await sleep(ONE_SECONDS_TIME); + done(); + }) + + it('testDialogFocusStrategy', 0, async (done: Function) => { + console.info("uitest: testDialogFocusStrategy begin"); + let driver = Driver.create(); + let button_list = await driver.findComponent(ON.text(resource.resourceToString($r('app.string.CustomDialog1')), + MatchPattern.CONTAINS)); + expect(button_list === null).assertFalse(); + await button_list.click(); + let button_list1 = + await driver.findComponent(ON.text(resource.resourceToString($r('app.string.CustomDialog_focus')), + MatchPattern.CONTAINS)); + await button_list1.click(); + await sleep(ONE_SECONDS_TIME); + await driver.pressBack(); + await driver.pressBack(); + await sleep(ONE_SECONDS_TIME); + done(); + }) + + it('testGlobalOpenPopup', 0, async (done: Function) => { + console.info("uitest: testGlobalOpenPopup begin"); + let driver = Driver.create(); + let button_list = await driver.findComponent(ON.text(resource.resourceToString($r('app.string.Popup1')), + MatchPattern.CONTAINS)); + expect(button_list === null).assertFalse(); + await button_list.click(); + await sleep(ONE_SECONDS_TIME); + let button_list1 = + await driver.findComponent(ON.text(resource.resourceToString($r('app.string.StylePopup_global')), + MatchPattern.CONTAINS)); + await button_list1.click(); + await sleep(ONE_SECONDS_TIME); + let button_list2 = await driver.findComponent(ON.text('openPopup', MatchPattern.CONTAINS)); + await button_list2.click(); + await sleep(ONE_SECONDS_TIME); + let button_list3 = await driver.findComponent(ON.text('Update', MatchPattern.CONTAINS)); + await button_list3.click(); + let button_list4 = await driver.findComponent(ON.text('Close', MatchPattern.CONTAINS)); + await button_list4.click(); + await sleep(ONE_SECONDS_TIME); + await driver.pressBack(); + await driver.pressBack(); + await sleep(ONE_SECONDS_TIME); + done(); + }) + + it('testDialogController', 0, async (done: Function) => { + console.info("uitest: testDialogController begin"); + let driver = Driver.create(); + let button_list = await driver.findComponent(ON.text(resource.resourceToString($r('app.string.CustomDialog1')), + MatchPattern.CONTAINS)); + expect(button_list === null).assertFalse(); + await button_list.click(); + await sleep(ONE_SECONDS_TIME); + let button_list1 = + await driver.findComponent(ON.text(resource.resourceToString($r('app.string.CustomDialog_controller')), + MatchPattern.CONTAINS)); + await button_list1.click(); + await sleep(ONE_SECONDS_TIME); + await driver.pressBack(); + await driver.pressBack(); + await sleep(ONE_SECONDS_TIME); + done(); + }) + + it('testPageLevelDialog', 0, async (done: Function) => { + console.info("uitest: testPageLevelDialog begin"); + let driver = Driver.create(); + let button_list = await driver.findComponent(ON.text(resource.resourceToString($r('app.string.CustomDialog1')), + MatchPattern.CONTAINS)); + expect(button_list === null).assertFalse(); + await button_list.click(); + await sleep(ONE_SECONDS_TIME); + await driver.fling(UiDirection.DOWN, ONE_SECONDS_TIME2); + let button_list1 = + await driver.findComponent(ON.text(resource.resourceToString($r('app.string.CustomDialog_page_level')), + MatchPattern.CONTAINS)); + await button_list1.click(); + await sleep(ONE_SECONDS_TIME); + await driver.pressBack(); + await driver.pressBack(); + await sleep(ONE_SECONDS_TIME); + done(); + }) + + it('testGlobalOpenMenu', 0, async (done: Function) => { + console.info("uitest: testGlobalOpenMenu begin"); + let driver = Driver.create(); + let button_list = await driver.findComponent(ON.text(resource.resourceToString($r('app.string.Menu1')), + MatchPattern.CONTAINS)); + expect(button_list === null).assertFalse(); + await button_list.click(); + await sleep(ONE_SECONDS_TIME); + let button_list1 = + await driver.findComponent(ON.text(resource.resourceToString($r('app.string.OpenMenu_title')), + MatchPattern.CONTAINS)); + await button_list1.click(); + await sleep(ONE_SECONDS_TIME); + await driver.pressBack(); + await driver.pressBack(); + await sleep(ONE_SECONDS_TIME); + done(); + }) + + it('testDialogBoxLayer', 0, async (done: Function) => { + console.info("uitest: testDialogBoxLayer begin"); + let driver = Driver.create(); + let button_list = await driver.findComponent(ON.text(resource.resourceToString($r('app.string.CustomDialog1')), + MatchPattern.CONTAINS)); + expect(button_list === null).assertFalse(); + await button_list.click(); + await sleep(ONE_SECONDS_TIME); + await driver.fling(UiDirection.DOWN, ONE_SECONDS_TIME2); + let button_list1 = + await driver.findComponent(ON.text(resource.resourceToString($r('app.string.CustomDialog_box_layer')), + MatchPattern.CONTAINS)); + await button_list1.click(); + await sleep(ONE_SECONDS_TIME); + await driver.pressBack(); + await driver.pressBack(); + await sleep(ONE_SECONDS_TIME); done(); }) @@ -218,13 +495,13 @@ export default function IndexTest() { let button_list1 = await driver.findComponent(ON.text(resource.resourceToString($r('app.string.DatePicker_title')), MatchPattern.CONTAINS)); await button_list1.click(); - let button_list2 = await driver.findComponent(ON.text('showDate', MatchPattern.CONTAINS)); + let button_list2 = await driver.findComponent(ON.text('showDatePickerDialog', MatchPattern.CONTAINS)); await button_list2.click(); - await sleep(1000); + await sleep(ONE_SECONDS_TIME); await driver.pressBack(); await driver.pressBack(); await driver.pressBack(); - await sleep(1000); + await sleep(ONE_SECONDS_TIME); done(); }) @@ -246,11 +523,37 @@ export default function IndexTest() { let button_list2 = await driver.findComponent(ON.text('ShowActionMenu', MatchPattern.CONTAINS)); await button_list2.click(); - await sleep(1000); + await sleep(ONE_SECONDS_TIME); await driver.pressBack(); await driver.pressBack(); await driver.pressBack(); - await sleep(1000); + await sleep(ONE_SECONDS_TIME); + done(); + }) + + /** + * @tc.number testFixedCustomDialog_002 + * @tc.name testFixedCustomDialog_002 + * @tc.desc Test Fixed-style pop-up box. + * @tc.size MEDIUM + * @tc.level Level 1 + * @tc.type Function + */ + it('testFixedCustomDialog_002', 0, async (done: Function) => { + let driver = Driver.create(); + let button_list = await driver.findComponent(ON.text(resource.resourceToString($r('app.string.FixedStyleDialog1')), MatchPattern.CONTAINS)); + expect(button_list === null).assertFalse(); + await button_list.click(); + await sleep(ONE_SECONDS_TIME); + let button_list1 = await driver.findComponent(ON.text(resource.resourceToString($r('app.string.DatePickerCustom_title')), MatchPattern.CONTAINS)); + await button_list1.click(); + await sleep(ONE_SECONDS_TIME); + let button_list2 = await driver.findComponent(ON.text('showDatePickerCustomDialog', MatchPattern.CONTAINS)); + await button_list2.click(); + await driver.pressBack(); + await driver.pressBack(); + await driver.pressBack(); + await sleep(ONE_SECONDS_TIME); done(); }) @@ -260,16 +563,68 @@ export default function IndexTest() { let button_list = await driver.findComponent(ON.text(resource.resourceToString($r('app.string.Menu1')), MatchPattern.CONTAINS)); expect(button_list === null).assertFalse(); await button_list.click(); - await sleep(1000); + await sleep(ONE_SECONDS_TIME); let button_list1 = await driver.findComponent(ON.text(resource.resourceToString($r('app.string.CreateMenu_title')), MatchPattern.CONTAINS)); await button_list1.click(); - await sleep(1000); + await sleep(ONE_SECONDS_TIME); let button_list2 = await driver.findComponent(ON.text(resource.resourceToString($r('app.string.menu_bind')), MatchPattern.CONTAINS)); await button_list2.click(); await driver.pressBack(); await driver.pressBack(); await driver.pressBack(); await driver.pressBack(); + await sleep(ONE_SECONDS_TIME); + done(); + }) + + it('testMaskDialog', 50, async (done: Function) => { + let driver = Driver.create(); + let button_list = await driver.findComponent(ON.text(resource.resourceToString($r('app.string.MaskDialog')), MatchPattern.CONTAINS)); + expect(button_list === null).assertFalse(); + await button_list.click(); + let button_list1 = await driver.findComponent(ON.text(resource.resourceToString($r('app.string.CustomDialogAnimation_title')), MatchPattern.CONTAINS)); + await button_list1.click(); + + let button_list2 = await driver.findComponent(ON.text('CustomDialogController animate', MatchPattern.CONTAINS)); + await button_list2.click(); + await sleep(2000) + await driver.pressBack(); + await sleep(2000) + await driver.pressBack(); + + let customDialogControl_list_item = await driver.findComponent(ON.text(resource.resourceToString($r('app.string.CustomDialogControl_title')), MatchPattern.CONTAINS)); + await customDialogControl_list_item.click(); + let button_autoCancel = await driver.findComponent(ON.text('openCustomDialog autoCancel:false', MatchPattern.CONTAINS)); + await button_autoCancel.click(); + await sleep(1000); + await driver.pressBack(); + + let button_isModal = await driver.findComponent(ON.text('openCustomDialog isModal:false', MatchPattern.CONTAINS)); + await button_isModal.click(); + await sleep(1000); + await driver.pressBack(); + + let button_maskOpt = await driver.findComponent(ON.text('openCustomDialog maskOpt', MatchPattern.CONTAINS)); + await button_maskOpt.click(); + await driver.pressBack(); + + let button_transition = await driver.findComponent(ON.text('openCustomDialog transition', MatchPattern.CONTAINS)); + await button_transition.click(); + await sleep(1000); + await driver.pressBack(); + await sleep(2000); + + let button_immersiveMode = await driver.findComponent(ON.text('openCustomDialog immersiveMode', MatchPattern.CONTAINS)); + await button_immersiveMode.click(); + await sleep(1000); + await driver.pressBack(); + + let button_maskTransition = await driver.findComponent(ON.text('openCustomDialog maskTransition', MatchPattern.CONTAINS)); + await sleep(1000); + await button_maskTransition.click(); + await sleep(2000); + await driver.pressBack(); + await sleep(1000); done(); }) @@ -289,8 +644,7 @@ export default function IndexTest() { await button2.click(); await driver.pressBack(); await driver.pressBack(); - await driver.pressBack(); - await sleep(1000); + await sleep(ONE_SECONDS_TIME); done(); }) @@ -299,16 +653,18 @@ export default function IndexTest() { let button_list = await driver.findComponent(ON.text(resource.resourceToString($r('app.string.OverlayManager1')), MatchPattern.CONTAINS)); expect(button_list === null).assertFalse(); await button_list.click(); + await sleep(ONE_SECONDS_TIME); let button_list1 = await driver.findComponent(ON.text(resource.resourceToString($r('app.string.OverlayManager_demo1_title')), MatchPattern.CONTAINS)); expect(button_list1 === null).assertFalse(); await button_list1.click(); + await sleep(ONE_SECONDS_TIME); let button1 = await driver.findComponent(ON.text('ComponentContent', MatchPattern.CONTAINS)); expect(button1 === null).assertFalse(); await button1.click(); await driver.pressBack(); await driver.pressBack(); await driver.pressBack(); - await sleep(1000); + await sleep(ONE_SECONDS_TIME); done(); }) }) diff --git a/ArkUIKit/DialogProject/entry/src/ohosTest/ets/test/List.test.ets b/ArkUIKit/DialogProject/entry/src/ohosTest/ets/test/List.test.ets index 3d739bce6..b93057ead 100644 --- a/ArkUIKit/DialogProject/entry/src/ohosTest/ets/test/List.test.ets +++ b/ArkUIKit/DialogProject/entry/src/ohosTest/ets/test/List.test.ets @@ -13,11 +13,14 @@ * limitations under the License. */ - import IndexTest from './Index.test' import abilityTest from './Ability.test'; +import PopupTest from './Popup.test'; +import MenuTest from './Menu.test' export default function testsuite() { abilityTest(); - IndexTest() + IndexTest(); + PopupTest(); + MenuTest(); } \ No newline at end of file diff --git a/ArkUIKit/DialogProject/entry/src/ohosTest/ets/test/Menu.test.ets b/ArkUIKit/DialogProject/entry/src/ohosTest/ets/test/Menu.test.ets new file mode 100644 index 000000000..59e2b4921 --- /dev/null +++ b/ArkUIKit/DialogProject/entry/src/ohosTest/ets/test/Menu.test.ets @@ -0,0 +1,181 @@ +/* + * 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 { describe, it, expect, beforeAll, Level } from '@ohos/hypium'; +// 导入测试依赖kit +import { abilityDelegatorRegistry, Driver, ON, MouseButton, Component, MatchPattern } from '@kit.TestKit'; +import { UIAbility, Want } from '@kit.AbilityKit'; +import resource from '../../../main/ets/common/resource'; + +const delegator: abilityDelegatorRegistry.AbilityDelegator = abilityDelegatorRegistry.getAbilityDelegator() +const bundleName = abilityDelegatorRegistry.getArguments().bundleName; +let want: Want; + +function sleep(time: number) { + return new Promise((resolve: Function) => setTimeout(resolve, time)); +} + +export default function MenuTest() { + + describe('MenuTest', () => { + + beforeAll(async () => { + want = { + bundleName: bundleName, + abilityName: 'EntryAbility' + }; + await delegator.startAbility(want); + await sleep(1000); + const ability: UIAbility = await delegator.getCurrentTopAbility(); + console.info("get top ability"); + expect(ability.context.abilityInfo.name).assertEqual('EntryAbility'); + }) + + /** + * @tc.number UiTest_001 + * @tc.name testPopVibrateMenu + * @tc.desc 测试菜单弹出时振动效果示例 + * @tc.level: Level 1 + */ + it('testPopVibrateMenu', Level.LEVEL1, async (done: Function) => { + console.info('uitest: testPopVibrateMenu begin'); + let driver = Driver.create(); + let button_list = + await driver.findComponent(ON.text(resource.resourceToString($r('app.string.Menu1')), MatchPattern.CONTAINS)); + expect(button_list === null).assertFalse(); + await button_list.click(); + await driver.delayMs(1000); + + let TextButton = + await driver.findComponent(ON.text(resource.resourceToString($r('app.string.PopVibrateMenu_title')), + MatchPattern.CONTAINS)); + expect(TextButton === null).assertFalse(); + await TextButton.click(); + await driver.delayMs(1000); + + let PopupOptionsButton = await driver.findComponent(ON.id('click for Menu', MatchPattern.CONTAINS)); + expect(PopupOptionsButton === null).assertFalse(); + await PopupOptionsButton.click(); + await driver.delayMs(1000); + + await driver.pressBack(); + await driver.delayMs(1000); + await driver.pressBack(); + await driver.delayMs(1000); + console.info('uitest: testPopVibrateMenu end'); + done(); + }) + + /** + * @tc.number UiTest_002 + * @tc.name testSupportAvoidCentralAxisMenu + * @tc.desc 测试菜单支持避让中轴示例 + * @tc.level: Level 1 + */ + it('testSupportAvoidCentralAxisMenu', Level.LEVEL1, async (done: Function) => { + console.info('uitest: testSupportAvoidCentralAxisMenu begin'); + let driver = Driver.create(); + let button_list = + await driver.findComponent(ON.text(resource.resourceToString($r('app.string.Menu1')), MatchPattern.CONTAINS)); + expect(button_list === null).assertFalse(); + await button_list.click(); + await driver.delayMs(1000); + + let TextButton = + await driver.findComponent(ON.text(resource.resourceToString($r('app.string.SupportAvoidCentralAxisMenu_title')), + MatchPattern.CONTAINS)); + expect(TextButton === null).assertFalse(); + await TextButton.click(); + await driver.delayMs(1000); + + let PopupOptionsButton = await driver.findComponent(ON.id('hoverMode_start', MatchPattern.CONTAINS)); + expect(PopupOptionsButton === null).assertFalse(); + await PopupOptionsButton.click(); + await driver.delayMs(1000); + + await driver.pressBack(); + await driver.delayMs(1000); + await driver.pressBack(); + await driver.delayMs(1000); + console.info('uitest: testSupportAvoidCentralAxisMenu end'); + done(); + }) + + /** + * @tc.number UiTest_003 + * @tc.name testEventTransSubWindowMenu + * @tc.desc 测试控制子窗菜单的事件透传示例 + * @tc.level: Level 1 + */ + it('testEventTransSubWindowMenu', Level.LEVEL1, async (done: Function) => { + console.info('uitest: testEventTransSubWindowMenu begin'); + let driver = Driver.create(); + let button_list = + await driver.findComponent(ON.text(resource.resourceToString($r('app.string.Menu1')), MatchPattern.CONTAINS)); + expect(button_list === null).assertFalse(); + await button_list.click(); + await driver.delayMs(1000); + + let TextButton = + await driver.findComponent(ON.text(resource.resourceToString($r('app.string.EventTransSubWindowMenu_title')), + MatchPattern.CONTAINS)); + expect(TextButton === null).assertFalse(); + await TextButton.click(); + await driver.delayMs(1000); + + let PopupOptionsButton = await driver.findComponent(ON.id('click', MatchPattern.CONTAINS)); + expect(PopupOptionsButton === null).assertFalse(); + await PopupOptionsButton.click(); + await driver.delayMs(1000); + + await driver.pressBack(); + await driver.delayMs(1000); + await driver.pressBack(); + await driver.delayMs(1000); + console.info('uitest: testEventTransSubWindowMenu end'); + done(); + }) + + /** + * @tc.number UiTest_004 + * @tc.name testBindComponentMenu + * @tc.desc 测试基于绑定组件指定位置弹出菜单示例 + * @tc.level: Level 1 + */ + it('testBindComponentMenu', Level.LEVEL1, async (done: Function) => { + console.info('uitest: testBindComponentMenu begin'); + let driver = Driver.create(); + let button_list = + await driver.findComponent(ON.text(resource.resourceToString($r('app.string.Menu1')), MatchPattern.CONTAINS)); + expect(button_list === null).assertFalse(); + await button_list.click(); + await driver.delayMs(1000); + + let TextButton = + await driver.findComponent(ON.text(resource.resourceToString($r('app.string.BindComponentMenu_title')), + MatchPattern.CONTAINS)); + expect(TextButton === null).assertFalse(); + await TextButton.click(); + await driver.delayMs(1000); + + await driver.pressBack(); + await driver.delayMs(1000); + await driver.pressBack(); + await driver.delayMs(1000); + console.info('uitest: testBindComponentMenu end'); + done(); + }) + }) +} \ No newline at end of file diff --git a/ArkUIKit/DialogProject/entry/src/ohosTest/ets/test/Popup.test.ets b/ArkUIKit/DialogProject/entry/src/ohosTest/ets/test/Popup.test.ets new file mode 100644 index 000000000..811c571c1 --- /dev/null +++ b/ArkUIKit/DialogProject/entry/src/ohosTest/ets/test/Popup.test.ets @@ -0,0 +1,375 @@ +/* + * 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 { describe, it, expect, beforeAll, Level } from '@ohos/hypium'; +// 导入测试依赖kit +import { abilityDelegatorRegistry, Driver, ON, MouseButton, Component, MatchPattern } from '@kit.TestKit'; +import { UIAbility, Want } from '@kit.AbilityKit'; +import resource from '../../../main/ets/common/resource'; + +const delegator: abilityDelegatorRegistry.AbilityDelegator = abilityDelegatorRegistry.getAbilityDelegator() +const bundleName = abilityDelegatorRegistry.getArguments().bundleName; +let want: Want; + +function sleep(time: number) { + return new Promise((resolve: Function) => setTimeout(resolve, time)); +} + +export default function PopupTest() { + + describe('PopupTest', () => { + + beforeAll(async () => { + want = { + bundleName: bundleName, + abilityName: 'EntryAbility' + }; + await delegator.startAbility(want); + await sleep(1000); + const ability: UIAbility = await delegator.getCurrentTopAbility(); + console.info("get top ability"); + expect(ability.context.abilityInfo.name).assertEqual('EntryAbility'); + }) + + /** + * @tc.number UiTest_001 + * @tc.name testTextPrompts + * @tc.desc 测试文本提示气泡示例 + * @tc.level: Level 1 + */ + it('testTextPrompts', Level.LEVEL1, async (done: Function) => { + console.info('uitest: testTextPrompts begin'); + let driver = Driver.create(); + let button_list = await driver.findComponent(ON.text('Popup', MatchPattern.CONTAINS)); + expect(button_list === null).assertFalse(); + await button_list.click(); + await driver.delayMs(1000); + + let TextButton = await driver.findComponent(ON.text(resource.resourceToString($r('app.string.TextPopup_title')), + MatchPattern.CONTAINS)); + expect(TextButton === null).assertFalse(); + await TextButton.click(); + // await driver.delayMs(1000); + + let PopupOptionsButton = await driver.findComponent(ON.id('PopupOptions', MatchPattern.CONTAINS)); + expect(PopupOptionsButton === null).assertFalse(); + await PopupOptionsButton.click(); + await driver.delayMs(1000); + + await driver.pressBack(); + await driver.delayMs(1000); + await driver.pressBack(); + await driver.delayMs(1000); + await driver.pressBack(); + await driver.delayMs(1000); + console.info('uitest: testTextPrompts end'); + done(); + }) + + /** + * @tc.number UiTest_002 + * @tc.name testPopupStateChange + * @tc.desc 测试添加气泡状态变化的事件示例 + * @tc.level: Level 1 + */ + it('testPopupStateChange', Level.LEVEL1, async (done: Function) => { + console.info('uitest: testPopupStateChange begin'); + let driver = Driver.create(); + let button_list = await driver.findComponent(ON.text('Popup', MatchPattern.CONTAINS)); + expect(button_list === null).assertFalse(); + await button_list.click(); + await driver.delayMs(1000); + + let TextButton = + await driver.findComponent(ON.text(resource.resourceToString($r('app.string.onStateChange_title')), + MatchPattern.CONTAINS)); + expect(TextButton === null).assertFalse(); + await TextButton.click(); + + let PopupOptionsButton = await driver.findComponent(ON.id('PopupOptions', MatchPattern.CONTAINS)); + expect(PopupOptionsButton === null).assertFalse(); + await PopupOptionsButton.click(); + await driver.delayMs(1000); + + await driver.pressBack(); + await driver.delayMs(1000); + await driver.pressBack(); + await driver.delayMs(1000); + await driver.pressBack(); + await driver.delayMs(1000); + console.info('uitest: testPopupStateChange end'); + done(); + }) + + /** + * @tc.number UiTest_003 + * @tc.name testButtonPopup + * @tc.desc 测试带按钮的提示气泡示例 + * @tc.level: Level 1 + */ + it('testButtonPopup', Level.LEVEL1, async (done: Function) => { + console.info('uitest: testButtonPopup begin'); + let driver = Driver.create(); + let button_list = await driver.findComponent(ON.text('Popup', MatchPattern.CONTAINS)); + expect(button_list === null).assertFalse(); + await button_list.click(); + await driver.delayMs(1000); + + let TextButton = await driver.findComponent(ON.text(resource.resourceToString($r('app.string.button_popup')), + MatchPattern.CONTAINS)); + expect(TextButton === null).assertFalse(); + await TextButton.click(); + + let PopupOptionsButton = await driver.findComponent(ON.id('PopupOptions', MatchPattern.CONTAINS)); + expect(PopupOptionsButton === null).assertFalse(); + await PopupOptionsButton.click(); + await driver.delayMs(1000); + + let buttonComponent = await driver.findComponent(ON.text('Confirm', MatchPattern.CONTAINS)); + expect(buttonComponent === null).assertFalse(); + await buttonComponent.click(); + await driver.delayMs(1000); + + await driver.pressBack(); + await driver.delayMs(1000); + await driver.pressBack(); + await driver.delayMs(1000); + console.info('uitest: testButtonPopup end'); + done(); + }) + + /** + * @tc.number UiTest_004 + * @tc.name testPopupAnimation + * @tc.desc 测试气泡的动画示例 + * @tc.level: Level 1 + */ + it('testPopupAnimation', Level.LEVEL1, async (done: Function) => { + console.info('uitest: testPopupAnimation begin'); + let driver = Driver.create(); + let button_list = await driver.findComponent(ON.text('Popup', MatchPattern.CONTAINS)); + expect(button_list === null).assertFalse(); + await button_list.click(); + await driver.delayMs(1000); + + let TextButton = + await driver.findComponent(ON.text(resource.resourceToString($r('app.string.AnimationPopup_title')), + MatchPattern.CONTAINS)); + expect(TextButton === null).assertFalse(); + await TextButton.click(); + + let PopupOptionsButton = await driver.findComponent(ON.id('PopupOptions', MatchPattern.CONTAINS)); + expect(PopupOptionsButton === null).assertFalse(); + await PopupOptionsButton.click(); + await driver.delayMs(1000); + await driver.pressBack(); + await driver.delayMs(1000); + + let buttonComponent = await driver.findComponent(ON.id('CustomPopupOptions', MatchPattern.CONTAINS)); + expect(buttonComponent === null).assertFalse(); + await buttonComponent.click(); + await driver.delayMs(1000); + + await driver.pressBack(); + await driver.delayMs(1000); + await driver.pressBack(); + await driver.delayMs(1000); + await driver.pressBack(); + await driver.delayMs(1000); + console.info('uitest: testPopupAnimation end'); + done(); + }) + + /** + * @tc.number UiTest_005 + * @tc.name testCustomPopup + * @tc.desc 测试自定义气泡示例 + * @tc.level: Level 1 + */ + it('testCustomPopup', Level.LEVEL1, async (done: Function) => { + console.info('uitest: testCustomPopup begin'); + let driver = Driver.create(); + let button_list = await driver.findComponent(ON.text('Popup', MatchPattern.CONTAINS)); + expect(button_list === null).assertFalse(); + await button_list.click(); + + let TextButton = + await driver.findComponent(ON.text(resource.resourceToString($r('app.string.custom_popup')), + MatchPattern.CONTAINS)); + expect(TextButton === null).assertFalse(); + await TextButton.click(); + + let PopupOptionsButton = await driver.findComponent(ON.id('CustomPopupOptions', MatchPattern.CONTAINS)); + expect(PopupOptionsButton === null).assertFalse(); + await PopupOptionsButton.click(); + + await driver.pressBack(); + await driver.delayMs(1000); + await driver.pressBack(); + await driver.delayMs(1000); + await driver.pressBack(); + await driver.delayMs(1000); + console.info('uitest: testCustomPopup end'); + done(); + }) + + /** + * @tc.number UiTest_006 + * @tc.name testPopupStyle + * @tc.desc 测试气泡样式示例 + * @tc.level: Level 1 + */ + it('testPopupStyle', Level.LEVEL1, async (done: Function) => { + console.info('uitest: testPopupStyle begin'); + let driver = Driver.create(); + let button_list = await driver.findComponent(ON.text('Popup', MatchPattern.CONTAINS)); + expect(button_list === null).assertFalse(); + await button_list.click(); + + let TextButton = + await driver.findComponent(ON.text(resource.resourceToString($r('app.string.StylePopup_title')), + MatchPattern.CONTAINS)); + expect(TextButton === null).assertFalse(); + await TextButton.click(); + + let PopupOptionsButton = await driver.findComponent(ON.id('PopupOptions', MatchPattern.CONTAINS)); + expect(PopupOptionsButton === null).assertFalse(); + await PopupOptionsButton.click(); + + await driver.pressBack(); + await driver.delayMs(1000); + await driver.pressBack(); + await driver.delayMs(1000); + await driver.pressBack(); + await driver.delayMs(1000); + console.info('uitest: testPopupStyle end'); + done(); + }) + + /** + * @tc.number UiTest_007 + * @tc.name testPopupAvoidSoftKeyboard + * @tc.desc 测试气泡避让软键盘示例 + * @tc.level: Level 1 + */ + it('testPopupAvoidSoftKeyboard', Level.LEVEL1, async (done: Function) => { + console.info('uitest: testPopupAvoidSoftKeyboard begin'); + let driver = Driver.create(); + let button_list = await driver.findComponent(ON.text('Popup', MatchPattern.CONTAINS)); + expect(button_list === null).assertFalse(); + await button_list.click(); + await driver.delayMs(1000); + + await driver.swipe(100, 800, 100, 300); + await driver.delayMs(1000); + + let TextButton = + await driver.findComponent(ON.text(resource.resourceToString($r('app.string.AvoidSoftKeyboardPopupExample_title')), + MatchPattern.CONTAINS)); + expect(TextButton === null).assertFalse(); + await TextButton.click(); + + let PopupOptionsButton = await driver.findComponent(ON.id('PopupOptions', MatchPattern.CONTAINS)); + expect(PopupOptionsButton === null).assertFalse(); + await PopupOptionsButton.click(); + await driver.delayMs(1000); + + await driver.pressBack(); + await driver.delayMs(1000); + await driver.pressBack(); + await driver.delayMs(1000); + await driver.pressBack(); + await driver.delayMs(1000); + console.info('uitest: testPopupAvoidSoftKeyboard end'); + done(); + }) + + /** + * @tc.number UiTest_008 + * @tc.name testPopupPolymorphicEffect + * @tc.desc 测试设置气泡内的多态效果示例 + * @tc.level: Level 1 + */ + it('testPopupPolymorphicEffect', Level.LEVEL1, async (done: Function) => { + console.info('uitest: testPopupPolymorphicEffect begin'); + let driver = Driver.create(); + let button_list = await driver.findComponent(ON.text('Popup', MatchPattern.CONTAINS)); + expect(button_list === null).assertFalse(); + await button_list.click(); + await driver.delayMs(1000); + + await driver.swipe(100, 800, 100, 100); + await driver.delayMs(1000); + + let TextButton = + await driver.findComponent(ON.text(resource.resourceToString($r('app.string.PolymorphicEffectPopupExample_title')), + MatchPattern.CONTAINS)); + expect(TextButton === null).assertFalse(); + await TextButton.click(); + + let PopupOptionsButton = await driver.findComponent(ON.id('click me', MatchPattern.CONTAINS)); + expect(PopupOptionsButton === null).assertFalse(); + await PopupOptionsButton.click(); + await driver.delayMs(1000); + + await driver.pressBack(); + await driver.delayMs(1000); + await driver.pressBack(); + await driver.delayMs(1000); + await driver.pressBack(); + await driver.delayMs(1000); + console.info('uitest: testPopupPolymorphicEffect end'); + done(); + }) + + /** + * @tc.number UiTest_009 + * @tc.name testPopupSupportedAvoidAxis + * @tc.desc 测试气泡支持避让中轴示例 + * @tc.level: Level 1 + */ + it('testPopupSupportedAvoidAxis', Level.LEVEL1, async (done: Function) => { + console.info('uitest: testPopupSupportedAvoidAxis begin'); + let driver = Driver.create(); + let button_list = await driver.findComponent(ON.text('Popup', MatchPattern.CONTAINS)); + expect(button_list === null).assertFalse(); + await button_list.click(); + await driver.delayMs(1000); + + await driver.swipe(100, 800, 100, 0); + await driver.delayMs(1000); + + let TextButton = + await driver.findComponent(ON.text(resource.resourceToString($r('app.string.SupportedAvoidAxisPopupExample_title')), + MatchPattern.CONTAINS)); + expect(TextButton === null).assertFalse(); + await TextButton.click(); + + let PopupOptionsButton = await driver.findComponent(ON.id('Popup', MatchPattern.CONTAINS)); + expect(PopupOptionsButton === null).assertFalse(); + await PopupOptionsButton.click(); + await driver.delayMs(1000); + + await driver.pressBack(); + await driver.delayMs(1000); + await driver.pressBack(); + await driver.delayMs(1000); + await driver.pressBack(); + await driver.delayMs(1000); + console.info('uitest: testPopupSupportedAvoidAxis end'); + done(); + }) + }) +} \ No newline at end of file diff --git a/ArkUIKit/DialogProject/ohosTest.md b/ArkUIKit/DialogProject/ohosTest.md index c76e7f37b..959af3943 100644 --- a/ArkUIKit/DialogProject/ohosTest.md +++ b/ArkUIKit/DialogProject/ohosTest.md @@ -1,9 +1,71 @@ -# dialog 测试用例归档 + +# 基础自定义弹出框 (CustomDialog) 用例表 + +| 测试功能 | 预置条件 | 输入 | 预期输出 | 是否自动 | 测试结果 | +|----------| -------------- |--------------------------------------------------------------------------------------------------------------------------|------------| :------- | -------- | +| 创建自定义弹出框 | 设备正常运行 | 进入示例页面,点击"click me"按钮,返回 | 弹出框显示正常 | 是 | Pass | +| 弹出框的交互 | 设备正常运行 | 进入示例页面,点击"click me"按钮,点击"confirm"按钮,返回 | 弹出框交互显示正常 | 是 | Pass | +| 弹出框的交互 | 设备正常运行 | 进入示例页面,点击"click me"按钮,点击"confirm"按钮,点击"点击返回"按钮,返回 | 弹出框交互显示正常 | 是 | Pass | +| 弹出框的动画 | 设备正常运行 | 进入示例页面,点击"click me"按钮,返回 | 弹出框,动画显示正常 | 是 | Pass | +| 弹出框的样式 | 设备正常运行 | 进入示例页面,点击"click me"按钮,返回 | 弹出框样式显示正常 | 是 | Pass | +| 嵌套自定义弹出框 | 设备正常运行 | 进入示例页面,点击"Click Me"按钮,点击"Open Second Dialog Box and close this box"按钮,点击"Create Text"按钮,点击"Close Second Dialog Box"按钮,返回 | 弹出框样式显示正常 | 是 | Pass | +| 实现弹出框的物理返回拦截 | 设备正常运行 | 进入示例页面,点击"click me"按钮,点击"confirm"按钮,返回 | 弹出框物理返回拦截正常 | 是 | Pass | +| 获取弹出框的状态 | 设备正常运行 | 进入示例页面,点击"click me"按钮,点击"查询弹窗状态:通过自定义组件自带controller"按钮,点击"查询弹窗状态:通过CustomDialogController"按钮,点击"关闭弹窗"按钮,返回 | 弹出框状态显示正常 | 是 | Pass | +| 设置弹出框避让软键盘的距离 | 设备正常运行 | 进入示例页面,点击"打开弹窗"按钮,等待1秒钟,光标选中输入框,等待1秒钟返回,再等待1秒钟返回,再等待1秒钟返回 | + + +# 不依赖UI组件的全局自定义弹出框 (openCustomDialog) 测试用例归档 + +## 用例表 + +| 测试功能 | 预置条件 | 输入 | 预期输出 | 是否自动 | 测试结果 | +|-------------------------| -------------- |---------------------------------------------------------------|-------------| :------- | -------- | +| 测试更新自定义弹出框的属性 | 设备正常运行 | 进入示例页面,点击"open dialog and update options"按钮,等待3秒,返回。再点击"open dialog and update content"按钮,等待3秒,返回 | 动画显示正常,消失正常 | 是 | Pass | +| 测试为弹出框内容和蒙层设置不同的动画效果 | 设备正常运行 | 进入示例页面,点击打开弹窗按钮,等待5秒动画显示,返回,再等待5秒动画消失 | 动画显示正常 | 是 | Pass | +| 测试设置弹出框避让软键盘的距离 | 设备正常运行 | 进入示例页面,点击打开弹窗按钮,等待一秒,返回,等待1秒,再返回,等待1秒 | 避让软键盘正常 | 是 | Pass | + + +# 弹出框蒙层控制 测试用例归档 ## 用例表 -| 测试功能 | 预置条件 | 输入 | 预期输出 | 是否自动 | 测试结果 | -|------| -------------- |----------------|---------------| :------- | -------- | +| 测试功能 | 预置条件 | 输入 | 预期输出 | 是否自动 | 测试结果 | +|-----------------------------------| -------------- |--------------------------------------|-------------| :------- | -------- | +| 测试使用CustomDialogController打开和关闭动画 | 设备正常运行 | 进入示例页面,点击按钮等待2秒动画显示,返回,再等待两秒动画消失 | 动画显示正常,消失正常 | 是 | Pass | +| 测试使用蒙层控制功能 | 设备正常运行 | 进入示例页面,分别点击所有按钮,有动画则等待一秒,返回,有动画则等待2秒 | 根据设置项显示正常 | 是 | Pass | | 设置浮层 | 设备正常运行 | 进入设置浮层页面 | 页面布局正常,浮层设置正确 | 是 | Pass | +| 固定样式弹出框首页加载测试 | 设备正常运行 | 验证基础元素展示 | 检查标题和列表组件 | 是 | Pass | +| 固定样式弹出框/操作菜单页面加载,页面按钮响应 | 设备正常运行 | 1. 点击"固定样式弹出框",会出现列表组件,包括“操作菜单”组件。
2. 点击“操作带单”组件按钮,出现操作菜单页面。
3. 点击该页面的ShowActionMenu菜单,会弹出菜单响应页面。 | 页面加载成功
菜单点击响应正常 | 是 | Pass | +| 固定样式弹出框/日期滑动选择器自定义弹窗页面加载,页面按钮响应 | 设备正常运行 | 进入日期滑动选择器自定义弹窗页面,点击按钮 | 页面布局正常,按钮点击响应正确 | 是 | Pass | + +# Navigation 测试用例归档 + +## 用例表 + +| 测试功能 | 预置条件 | 输入 | 预期输出 | 是否自动 | 测试结果 | +| ------------------- | -------------- |---------------|--------| :------- | -------- | +| 测试文本提示气泡示例 | 设备正常运行 | 进入各个示例页面,push页面,然后返回 | 页面跳转正常 | 是 | Pass | +| 测试添加气泡状态变化的事件示例 | 设备正常运行 | 进入各个示例页面,push页面,然后返回 | 页面跳转正常 | 是 | Pass | +| 测试带按钮的提示气泡示例 | 设备正常运行 | 进入各个示例页面,push页面,然后返回 | 页面跳转正常 | 是 | Pass | +| 测试气泡的动画示例 | 设备正常运行 | 进入各个示例页面,push页面,然后返回 | 页面跳转正常 | 是 | Pass | +| 测试自定义气泡示例 | 设备正常运行 | 进入各个示例页面,push页面,然后返回 | 页面跳转正常 | 是 | Pass | +| 测试气泡样式示例 | 设备正常运行 | 进入各个示例页面,push页面,然后返回 | 页面跳转正常 | 是 | Pass | +| 测试气泡避让软键盘示例 | 设备正常运行 | 进入各个示例页面,push页面,然后返回 | 页面跳转正常 | 是 | Pass | +| 测试设置气泡内的多态效果示例 | 设备正常运行 | 进入各个示例页面,push页面,然后返回 | 页面跳转正常 | 是 | Pass | +| 测试气泡支持避让中轴示例 | 设备正常运行 | 进入各个示例页面,push页面,然后返回 | 页面跳转正常 | 是 | Pass | +| 测试菜单弹出时振动效果示例 | 设备正常运行 | 进入各个示例页面,push页面,然后返回 | 页面跳转正常 | 是 | Pass | +| 测试菜单支持避让中轴示例 | 设备正常运行 | 进入各个示例页面,push页面,然后返回 | 页面跳转正常 | 是 | Pass | +| 测试控制子窗菜单的事件透传示例 | 设备正常运行 | 进入各个示例页面,push页面,然后返回 | 页面跳转正常 | 是 | Pass | +| 测试基于绑定组件指定位置弹出菜单示例 | 设备正常运行 | 进入各个示例页面,push页面,然后返回 | 页面跳转正常 | 是 | Pass | +| 设置浮层 | 设备正常运行 | 进入设置浮层页面 | 页面布局正常,浮层设置正确 | 是 | Pass | + +# Radio 测试用例归档 + +## 用例表 + | Radio | 首页加载测试 | 设备正常运行 | 验证基础元素展示 | 检查标题和列表组件 | Pass | -| 固定样式弹出框 | 固定样式弹出框页面加载,页面按钮响应 | 设备正常运行 | 1. 点击"固定样式弹出框",会出现列表组件,包括“操作菜单”组件。
2. 点击“操作带单”组件按钮,出现操作菜单页面。
3. 点击该页面的ShowActionMenu菜单,会弹出菜单响应页面。 | 页面加载成功
菜单点击响应正常 | Pass | \ No newline at end of file +| 固定样式弹出框 | 固定样式弹出框页面加载,页面按钮响应 | 设备正常运行 | 1. 点击"固定样式弹出框",会出现列表组件,包括“操作菜单”组件。
2. 点击“操作带单”组件按钮,出现操作菜单页面。
3. 点击该页面的ShowActionMenu菜单,会弹出菜单响应页面。 | 页面加载成功
菜单点击响应正常 | Pass | +| 固定样式弹出框首页加载测试 | 设备正常运行 | 验证基础元素展示 | 检查标题和列表组件 | 是 | Pass | +| 固定样式弹出框/操作菜单页面加载,页面按钮响应 | 设备正常运行 | 1. 点击"固定样式弹出框",会出现列表组件,包括“操作菜单”组件。
2. 点击“操作带单”组件按钮,出现操作菜单页面。
3. 点击该页面的ShowActionMenu菜单,会弹出菜单响应页面。 | 页面加载成功
菜单点击响应正常 | 是 | Pass | +| 固定样式弹出框/日期滑动选择器自定义弹窗页面加载,页面按钮响应 | 设备正常运行 | 进入日期滑动选择器自定义弹窗页面,点击按钮 | 页面布局正常,按钮点击响应正确 | 是 | Pass | + diff --git a/ArkUIKit/InterAction/.gitignore b/ArkUIKit/InterAction/.gitignore new file mode 100644 index 000000000..d2ff20141 --- /dev/null +++ b/ArkUIKit/InterAction/.gitignore @@ -0,0 +1,12 @@ +/node_modules +/oh_modules +/local.properties +/.idea +**/build +/.hvigor +.cxx +/.clangd +/.clang-format +/.clang-tidy +**/.test +/.appanalyzer \ No newline at end of file diff --git a/ArkUIKit/InterAction/AppScope/app.json5 b/ArkUIKit/InterAction/AppScope/app.json5 new file mode 100644 index 000000000..296d2b9a2 --- /dev/null +++ b/ArkUIKit/InterAction/AppScope/app.json5 @@ -0,0 +1,24 @@ +/* + * 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. + */ +{ + "app": { + "bundleName": "com.example.interaction", + "vendor": "example", + "versionCode": 1000000, + "versionName": "1.0.0", + "icon": "$media:layered_image", + "label": "$string:app_name" + } +} diff --git a/ArkUIKit/InterAction/AppScope/resources/base/element/string.json b/ArkUIKit/InterAction/AppScope/resources/base/element/string.json new file mode 100644 index 000000000..3b5759143 --- /dev/null +++ b/ArkUIKit/InterAction/AppScope/resources/base/element/string.json @@ -0,0 +1,8 @@ +{ + "string": [ + { + "name": "app_name", + "value": "ComponentExtension" + } + ] +} diff --git a/ArkUIKit/InterAction/AppScope/resources/base/media/background.png b/ArkUIKit/InterAction/AppScope/resources/base/media/background.png new file mode 100644 index 0000000000000000000000000000000000000000..923f2b3f27e915d6871871deea0420eb45ce102f GIT binary patch literal 91942 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 M;JyCV_snDe2la%mzyJUM literal 0 HcmV?d00001 diff --git a/ArkUIKit/InterAction/AppScope/resources/base/media/layered_image.json b/ArkUIKit/InterAction/AppScope/resources/base/media/layered_image.json new file mode 100644 index 000000000..fb4992044 --- /dev/null +++ b/ArkUIKit/InterAction/AppScope/resources/base/media/layered_image.json @@ -0,0 +1,7 @@ +{ + "layered-image": + { + "background" : "$media:background", + "foreground" : "$media:foreground" + } +} \ No newline at end of file diff --git a/ArkUIKit/InterAction/README_zh.md b/ArkUIKit/InterAction/README_zh.md new file mode 100644 index 000000000..149129fa1 --- /dev/null +++ b/ArkUIKit/InterAction/README_zh.md @@ -0,0 +1,97 @@ +# ArkUI使用支持交互事件指南文档示例 + +### 介绍 + +本示例通过使用[ArkUI指南文档](https://gitCode .com/openharmony/docs/tree/master/zh-cn/application-dev/ui) +中各场景的开发示例,展示在工程中,帮助开发者更好地理解ArkUI提供的组件及组件属性并合理使用。 + +### 效果预览 + +| 首页 | 交互类组件目录 | 单一手势示例 | +|------------------------------------|------------------------------------|------------------------------------| +| ![](screenshots/device/image1.png) | ![](screenshots/device/image2.png) | ![](screenshots/device/image3.png) | + +### 使用说明 + +1. 在主界面,可以点击对应目录,选择需要参考的组件示例。 + +2. 在组件目录选择详细的示例参考。 + +3. 进入示例界面,查看参考示例。 + +4. 通过自动测试框架可进行测试及维护。 + +### 工程目录 + +``` +entry/src/main/ets/ +|---entryability +|---pages +| |---FocusOnclickExample //热区事件 +| | |---FocusOnclickExample.ets +| |---MouseButton //鼠标按键事件 +| | |---MouseButton.ets +| |---mouseMove //鼠标移动事件 +| | |---mouseMove.ets +| |---MouseWheel //鼠标滚轮事件 +| | |---ListDataSource.ets +| | |---MouseWheel.ets +| |---MultipleFingerInformation //多指信息 +| | |---MultipleFingerInformation.ets +| |---onHover //鼠标移入移出事件 +| | |---OnHover.ets +| |---PreventBubbling //阻止冒泡事件 +| | |---PreventBubbling.ets +| |---sampling //采样和历史点 +| | |---Sampling.ets +| |---stopPropagation //阻止鼠标冒泡事件 +| | |---StopPropagation.ets +|---pages +| |---Index.ets // 应用主页面 +entry/src/ohosTest/ +|---ets +| |---index.test.ets // 示例代码测试代码 +``` + +### 具体实现 + +1、默认情况下,组件的响应热区即为组件自身的位置和大小,这与用户看到的范围相 +一致,从而最大程度地保证用户操作的手眼一致性。在极少数情况下,应用需调整热区 +大小以限制或扩大组件响应的操作范围,这一功能通过组件的responseRegion接口实现。 +响应热区影响指向性事件的派发,通过与组件自身区域的相对关系进行指定,可以指定一 +个或多个区域,将组件的响应热区分割为多个部分; +2、鼠标事件回调。每当鼠标指针在绑定该API的组件内产生行为(MouseAction)时,触 +发事件回调,参数为MouseEvent对象,表示触发此次的鼠标事件。该事件支持自定义冒泡 +设置,默认父子冒泡; +3、重采样会合并同一个触点在同一帧内多次上报的move事件,并通过算法尽可能计算出一 +个合适的坐标上报给应用; +4、在支持多指触控的触屏设备上,上报的事件中同时包含了窗口所有按压手指的信息,可 +以通过touches获取; + +### 相关权限 + +不涉及。 + +### 依赖 + +不涉及。 + +### 约束与限制 + +1.本示例仅支持标准系统上运行, 支持设备:RK3568。 + +2.本示例为Stage模型,支持API14版本SDK,版本号:5.0.2.57,镜像版本号:OpenHarmony_5.0.2.57。 + +3.本示例需要使用DevEco Studio NEXT Developer Preview2 (Build Version: 5.0.5.306, built on December 12, 2024)及以上版本才可编译运行。 + +### 下载 + +如需单独下载本工程,执行如下命令: + +```` +git init +git config core.sparsecheckout true +echo code/DocsSample/ArkUISample/EventProject > .git/info/sparse-checkout +git remote add origin https://gitCode .com/openharmony/applications_app_samples.git +git pull origin master +```` \ No newline at end of file diff --git a/ArkUIKit/InterAction/build-profile.json5 b/ArkUIKit/InterAction/build-profile.json5 new file mode 100644 index 000000000..be9d10f8e --- /dev/null +++ b/ArkUIKit/InterAction/build-profile.json5 @@ -0,0 +1,57 @@ +/* + * 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. + */ +{ + "app": { + "signingConfigs": [], + "products": [ + { + "name": "default", + "signingConfig": "default", + "compileSdkVersion": 20, + "compatibleSdkVersion": 20, + "targetSdkVersion": 20, + "runtimeOS": "OpenHarmony", + "buildOption": { + "strictMode": { + "caseSensitiveCheck": true, + "useNormalizedOHMUrl": true + } + } + } + ], + "buildModeSet": [ + { + "name": "debug", + }, + { + "name": "release" + } + ] + }, + "modules": [ + { + "name": "entry", + "srcPath": "./entry", + "targets": [ + { + "name": "default", + "applyToProducts": [ + "default" + ] + } + ] + } + ] +} \ No newline at end of file diff --git a/ArkUIKit/InterAction/code-linter.json5 b/ArkUIKit/InterAction/code-linter.json5 new file mode 100644 index 000000000..5c4682f81 --- /dev/null +++ b/ArkUIKit/InterAction/code-linter.json5 @@ -0,0 +1,46 @@ +/* + * 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. + */ +{ + "files": [ + "**/*.ets" + ], + "ignore": [ + "**/src/ohosTest/**/*", + "**/src/test/**/*", + "**/src/mock/**/*", + "**/node_modules/**/*", + "**/oh_modules/**/*", + "**/build/**/*", + "**/.preview/**/*" + ], + "ruleSet": [ + "plugin:@performance/recommended", + "plugin:@typescript-eslint/recommended" + ], + "rules": { + "@security/no-unsafe-aes": "error", + "@security/no-unsafe-hash": "error", + "@security/no-unsafe-mac": "warn", + "@security/no-unsafe-dh": "error", + "@security/no-unsafe-dsa": "error", + "@security/no-unsafe-ecdsa": "error", + "@security/no-unsafe-rsa-encrypt": "error", + "@security/no-unsafe-rsa-sign": "error", + "@security/no-unsafe-rsa-key": "error", + "@security/no-unsafe-dsa-key": "error", + "@security/no-unsafe-dh-key": "error", + "@security/no-unsafe-3des": "error" + } +} \ No newline at end of file diff --git a/ArkUIKit/InterAction/entry/.gitignore b/ArkUIKit/InterAction/entry/.gitignore new file mode 100644 index 000000000..e2713a277 --- /dev/null +++ b/ArkUIKit/InterAction/entry/.gitignore @@ -0,0 +1,6 @@ +/node_modules +/oh_modules +/.preview +/build +/.cxx +/.test \ No newline at end of file diff --git a/ArkUIKit/InterAction/entry/build-profile.json5 b/ArkUIKit/InterAction/entry/build-profile.json5 new file mode 100644 index 000000000..9016faf39 --- /dev/null +++ b/ArkUIKit/InterAction/entry/build-profile.json5 @@ -0,0 +1,47 @@ +/* + * 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. + */ +{ + "apiType": "stageMode", + "buildOption": { + "resOptions": { + "copyCodeResource": { + "enable": false + } + } + }, + "buildOptionSet": [ + { + "name": "release", + "arkOptions": { + "obfuscation": { + "ruleOptions": { + "enable": false, + "files": [ + "./obfuscation-rules.txt" + ] + } + } + } + }, + ], + "targets": [ + { + "name": "default" + }, + { + "name": "ohosTest", + } + ] +} \ No newline at end of file diff --git a/ArkUIKit/InterAction/entry/hvigorfile.ts b/ArkUIKit/InterAction/entry/hvigorfile.ts new file mode 100644 index 000000000..cfa8a00f7 --- /dev/null +++ b/ArkUIKit/InterAction/entry/hvigorfile.ts @@ -0,0 +1,21 @@ +/* + * 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 { hapTasks } from '@ohos/hvigor-ohos-plugin'; + +export default { + system: hapTasks, /* 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/ArkUIKit/InterAction/entry/obfuscation-rules.txt b/ArkUIKit/InterAction/entry/obfuscation-rules.txt new file mode 100644 index 000000000..272efb6ca --- /dev/null +++ b/ArkUIKit/InterAction/entry/obfuscation-rules.txt @@ -0,0 +1,23 @@ +# Define project specific obfuscation rules here. +# You can include the obfuscation configuration files in the current module's build-profile.json5. +# +# For more details, see +# https://developer.huawei.com/consumer/cn/doc/harmonyos-guides-V5/source-obfuscation-V5 + +# Obfuscation options: +# -disable-obfuscation: disable all obfuscations +# -enable-property-obfuscation: obfuscate the property names +# -enable-toplevel-obfuscation: obfuscate the names in the global scope +# -compact: remove unnecessary blank spaces and all line feeds +# -remove-log: remove all console.* statements +# -print-namecache: print the name cache that contains the mapping from the old names to new names +# -apply-namecache: reuse the given cache file + +# Keep options: +# -keep-property-name: specifies property names that you want to keep +# -keep-global-name: specifies names that you want to keep in the global scope + +-enable-property-obfuscation +-enable-toplevel-obfuscation +-enable-filename-obfuscation +-enable-export-obfuscation \ No newline at end of file diff --git a/ArkUIKit/InterAction/entry/oh-package.json5 b/ArkUIKit/InterAction/entry/oh-package.json5 new file mode 100644 index 000000000..10cda399b --- /dev/null +++ b/ArkUIKit/InterAction/entry/oh-package.json5 @@ -0,0 +1,24 @@ +/* + * 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. + */ +{ + "name": "entry", + "version": "1.0.0", + "description": "Please describe the basic information.", + "main": "", + "author": "", + "license": "", + "dependencies": {} +} + diff --git a/ArkUIKit/InterAction/entry/src/main/ets/common/resource.ets b/ArkUIKit/InterAction/entry/src/main/ets/common/resource.ets new file mode 100644 index 000000000..723a39426 --- /dev/null +++ b/ArkUIKit/InterAction/entry/src/main/ets/common/resource.ets @@ -0,0 +1,25 @@ +/* + * 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. + */ + +export class P2PManager { + public resourceToString(resource: Resource): string { + return getContext(this).resourceManager.getStringSync(resource); + } +} + +// 默认导出let +let p2pManager = new P2PManager(); + +export default p2pManager as P2PManager; \ No newline at end of file diff --git a/ArkUIKit/InterAction/entry/src/main/ets/entryability/EntryAbility.ets b/ArkUIKit/InterAction/entry/src/main/ets/entryability/EntryAbility.ets new file mode 100644 index 000000000..081b700ca --- /dev/null +++ b/ArkUIKit/InterAction/entry/src/main/ets/entryability/EntryAbility.ets @@ -0,0 +1,95 @@ +/* + * 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 { AbilityConstant, ConfigurationConstant, UIAbility, Want } from '@kit.AbilityKit'; +import { hilog } from '@kit.PerformanceAnalysisKit'; +import { display, uiObserver, window } from '@kit.ArkUI'; + +const DOMAIN = 0x0000; + +function callBackFunc(info: uiObserver.NavDestinationSwitchInfo) { + console.info(`testTag navDestinationSwitch from: ${JSON.stringify(info.from)} to: ${JSON.stringify(info.to)}`) +} + +function callBackFunc2(info: uiObserver.NavDestinationSwitchInfo) { + console.info(`testTag2 navDestinationSwitch from: ${JSON.stringify(info.from)} to: ${JSON.stringify(info.to)}`) +} + +export default class EntryAbility extends UIAbility { + onCreate(want: Want, launchParam: AbilityConstant.LaunchParam): void { + this.context.getApplicationContext().setColorMode(ConfigurationConstant.ColorMode.COLOR_MODE_NOT_SET); + hilog.info(DOMAIN, 'testTag', '%{public}s', 'Ability onCreate'); + uiObserver.on('navDestinationSwitch', this.context, callBackFunc); + uiObserver.on('navDestinationSwitch', this.context, { + navigationId: 'myNavId' + }, callBackFunc2); + } + + onDestroy(): void { + hilog.info(DOMAIN, 'testTag', '%{public}s', 'Ability onDestroy'); + uiObserver.off('navDestinationSwitch', this.context, callBackFunc); + uiObserver.off('navDestinationSwitch', this.context, { + navigationId: 'myNavId' + }, callBackFunc); + } + + onWindowStageCreate(windowStage: window.WindowStage): void { + // Main window is created, set main page for this ability + hilog.info(DOMAIN, 'testTag', '%{public}s', 'Ability onWindowStageCreate'); + let mainWindow: window.Window; + try { + mainWindow = windowStage.getMainWindowSync(); + let displayClass: display.Display = display.getDefaultDisplaySync(); + AppStorage.setOrCreate('orientation', displayClass.orientation); + // 监听窗口的windowsSizeChange事件,旋转屏时会触发该事件 + mainWindow.on('windowSizeChange', (data) => { + console.info('Succeeded in enabling the listener for window size changes. Data: ' + JSON.stringify(data)); + let displayClass: display.Display | null = null; + try { + displayClass = display.getDefaultDisplaySync(); + console.info('display orientation is ' + JSON.stringify(displayClass.orientation)); + // 获取屏幕的显示方向 + AppStorage.set('orientation', displayClass.orientation); + } catch { + return; + } + }) + } catch { + hilog.info(0x0000, 'testTag', '%{public}s', 'error'); + return; + } + 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.'); + }); + } + + onWindowStageDestroy(): void { + // Main window is destroyed, release UI related resources + hilog.info(DOMAIN, 'testTag', '%{public}s', 'Ability onWindowStageDestroy'); + } + + onForeground(): void { + // Ability has brought to foreground + hilog.info(DOMAIN, 'testTag', '%{public}s', 'Ability onForeground'); + } + + onBackground(): void { + // Ability has back to background + hilog.info(DOMAIN, 'testTag', '%{public}s', 'Ability onBackground'); + } +} \ No newline at end of file diff --git a/ArkUIKit/InterAction/entry/src/main/ets/entrybackupability/EntryBackupAbility.ets b/ArkUIKit/InterAction/entry/src/main/ets/entrybackupability/EntryBackupAbility.ets new file mode 100644 index 000000000..4ce6449f0 --- /dev/null +++ b/ArkUIKit/InterAction/entry/src/main/ets/entrybackupability/EntryBackupAbility.ets @@ -0,0 +1,30 @@ +/* + * 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 { hilog } from '@kit.PerformanceAnalysisKit'; +import { BackupExtensionAbility, BundleVersion } from '@kit.CoreFileKit'; + +const DOMAIN = 0x0000; + +export default class EntryBackupAbility extends BackupExtensionAbility { + async onBackup() { + hilog.info(DOMAIN, 'testTag', 'onBackup ok'); + await Promise.resolve(); + } + + async onRestore(bundleVersion: BundleVersion) { + hilog.info(DOMAIN, 'testTag', 'onRestore ok %{public}s', JSON.stringify(bundleVersion)); + await Promise.resolve(); + } +} \ No newline at end of file diff --git a/ArkUIKit/InterAction/entry/src/main/ets/pages/FocusOnclickExample/FocusOnclickExample.ets b/ArkUIKit/InterAction/entry/src/main/ets/pages/FocusOnclickExample/FocusOnclickExample.ets new file mode 100644 index 000000000..19519ba17 --- /dev/null +++ b/ArkUIKit/InterAction/entry/src/main/ets/pages/FocusOnclickExample/FocusOnclickExample.ets @@ -0,0 +1,50 @@ +/* + * 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. + */ + +// [Start focus_onclick] +@Entry +@Component +struct FocusOnclickExample { + @State text: string = '' + @State number:number = 0 + + build() { + Column() { + Text(this.text) + .margin({bottom:20}) + Button($r('app.string.button')) + .responseRegion([ + { + x: 0, + y: 0, + width: '30%', + height: '100%' + }, // 第一个热区为按钮的左侧1/3区域 + { + x: '70%', + y: 0, + width: '30%', + height: '100%' + },// 第二个热区为按钮的右侧1/3区域 + ]) + .onClick(() => { + this.number++; + this.text = 'button' + this.number + 'clicked' + }) + .width(200) + }.width('100%').justifyContent(FlexAlign.Center) + } +} +// [End focus_onclick] diff --git a/ArkUIKit/InterAction/entry/src/main/ets/pages/Index.ets b/ArkUIKit/InterAction/entry/src/main/ets/pages/Index.ets new file mode 100644 index 000000000..4f1690610 --- /dev/null +++ b/ArkUIKit/InterAction/entry/src/main/ets/pages/Index.ets @@ -0,0 +1,208 @@ +/* + * 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 curves from '@ohos.curves'; +import { Route, RouteGroup } from './common/Index'; +import { KeyboardAvoidMode } from '@kit.ArkUI'; +import router from '@ohos.router'; + +@Styles +function cardPressedStyle() { + .backgroundColor('rgba(0,0,0,0.1)') + .opacity(1) + .animation({ curve: curves.cubicBezierCurve(0.33, 0, 0.67, 1), duration: 100 }) +} + +@Styles +function cardNormalStyle() { + .backgroundColor('rgba(0,0,0,0)') + .opacity(1) + .animation({ curve: curves.cubicBezierCurve(0.33, 0, 0.67, 1), duration: 100 }) +} + +@Styles +function cardDisabledStyle() { + .backgroundColor('rgba(0,0,0,0)') + .opacity(0.5) + .animation({ curve: curves.cubicBezierCurve(0.33, 0, 0.67, 1), duration: 100 }) +} + + +@Entry +@Component +struct ComponentExtension { + @Provide('router') router: NavPathStack = new NavPathStack(); + //$r('app.string.xxx')需要替换为开发者所需的资源文件 + @State routes: RouteGroup[] = [ + { + name: 'FocusOnclickExample', + label: $r('app.string.FocusOnclick'), + children: [ + { name: 'FocusOnclickExample', label: $r('app.string.FocusOnclickExample') }, + ] + }, + { + name: 'PreventBubbling', + label: $r('app.string.PreventBubbling'), + children: [ + { name: 'PreventBubbling', label: $r('app.string.PreventBubblingExample') }, + ] + }, + { + name: 'sampling', + label: $r('app.string.sampling'), + children: [ + { name: 'Sampling', label: $r('app.string.samplingExample') }, + ] + }, + { + name: 'MultipleFingerInformation', + label: $r('app.string.MultipleFingerInformation'), + children: [ + { name: 'MultipleFingerInformation', label: $r('app.string.MultipleFingerInformationExample') }, + ] + }, + { + name: 'mouseMove', + label: $r('app.string.mouseMove'), + children: [ + { name: 'MouseMove', label: $r('app.string.mouseMoveExample') }, + ] + }, + { + name: 'stopPropagation', + label: $r('app.string.stopPropagation'), + children: [ + { name: 'StopPropagation', label: $r('app.string.stopPropagationExample') }, + ] + }, + { + name: 'onHover', + label: $r('app.string.onHover'), + children: [ + { name: 'OnHover', label: $r('app.string.onHoverExample') }, + ] + }, + { + name: 'MouseButton', + label: $r('app.string.MouseButton'), + children: [ + { name: 'MouseButton', label: $r('app.string.MouseButtonExample') }, + ] + }, + { + name: 'MouseWheel', + label: $r('app.string.MouseWheel'), + children: [ + { name: 'MouseWheel', label: $r('app.string.MouseWheelExample') }, + ] + } + ]; + @State selection: string | null = null; + + @Builder + ListItemGroupHeader(route: RouteGroup) { + Row() { + Text(route.label) + .fontColor($r('sys.color.ohos_id_color_text_primary')) + .fontWeight(FontWeight.Medium) + + Blank() + + Text(`${route.children.length}`) + .fontColor($r('sys.color.ohos_id_color_text_secondary')) + .opacity(this.selection === route.name ? 0 : 1) + + Image($r('sys.media.ohos_ic_public_arrow_right')) + .fillColor($r('sys.color.ohos_id_color_fourth')) + .height(24) + .width(24) + .rotate({ angle: this.selection === route.name ? 90 : 0 }) + .animation({ curve: curves.interpolatingSpring(0, 1, 228, 30) }) + } + .borderRadius(20) + .width('100%') + .padding(8) + .enabled(!!route.children.length) + .stateStyles({ + pressed: cardPressedStyle, + normal: cardNormalStyle, + disabled: cardDisabledStyle, + }) + .onClick(() => { + animateTo( + { curve: curves.interpolatingSpring(0, 1, 228, 25) }, + () => { + if (this.selection === route.name) { + this.selection = null; + } else { + this.selection = route.name; + } + }); + }) + } + + aboutToAppear(): void { + this.getUIContext().setKeyboardAvoidMode(KeyboardAvoidMode.RESIZE); + } + + build() { + Column() { + Text('ComponentExtension') + List() { + ForEach(this.routes, (routeGroup: RouteGroup) => { + ListItemGroup({ + header: this.ListItemGroupHeader(routeGroup), + style: ListItemGroupStyle.CARD, + }) { + if (routeGroup.name === this.selection) { + ForEach(routeGroup.children, (route: Route) => { + ListItem() { + Row() { + Text(route.label).fontSize(16) + Blank() + Image($r('sys.media.ohos_ic_public_arrow_right')) + .fillColor($r('sys.color.ohos_id_color_fourth')) + .height(24) + .width(24) + } + .stateStyles({ + pressed: cardPressedStyle, + normal: cardNormalStyle, + disabled: cardDisabledStyle, + }) + .borderRadius(20) + .padding(8) + .transition( + TransitionEffect.OPACITY.animation({ + curve: curves.interpolatingSpring(0, 1, 228, 30) + }) + ) + .width('100%') + .onClick(() => { + const name = `pages/${routeGroup.name}/${route.name}`; + router.pushUrl({ url: name }) + }) + } + .width('100%') + }) + } + } + .padding(2) + .divider({ strokeWidth: 0.5 }) + }) + }.padding({ bottom: 10 }) + } + } +} \ No newline at end of file diff --git a/ArkUIKit/InterAction/entry/src/main/ets/pages/MouseButton/MouseButton.ets b/ArkUIKit/InterAction/entry/src/main/ets/pages/MouseButton/MouseButton.ets new file mode 100644 index 000000000..7a14b92c1 --- /dev/null +++ b/ArkUIKit/InterAction/entry/src/main/ets/pages/MouseButton/MouseButton.ets @@ -0,0 +1,141 @@ +/* + * 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. + */ + +// [Start mouse_button] +class ListDataSource implements IDataSource { + private list: number[] = []; + private listeners: DataChangeListener[] = []; + + constructor(list: number[]) { + this.list = list; + } + + totalCount(): number { + return this.list.length; + } + + getData(index: number): number { + return this.list[index]; + } + + registerDataChangeListener(listener: DataChangeListener): void { + if (this.listeners.indexOf(listener) < 0) { + this.listeners.push(listener); + } + } + + unregisterDataChangeListener(listener: DataChangeListener): void { + const pos = this.listeners.indexOf(listener); + if (pos >= 0) { + this.listeners.splice(pos, 1); + } + } + + // 通知控制器数据删除 + notifyDataDelete(index: number): void { + this.listeners.forEach(listener => { + listener.onDataDelete(index); + }); + } + + // 在指定索引位置删除一个元素 + public deleteItem(index: number): void { + this.list.splice(index, 1); + this.notifyDataDelete(index); + } +} + +@Entry +@Component +struct ListExample { + private arr: ListDataSource = new ListDataSource([0, 1, 2, 3, 4, 5, 6, 7, 8, 9]); + private allSelectedItems: Array = [] + @State isSelected: boolean[] = [] + + @Styles + selectedStyle(): void { + .backgroundColor(Color.Green) + } + + isItemSelected(item: number): boolean { + for (let i = 0; i < this.allSelectedItems.length; i++) { + if (this.allSelectedItems[i] === item) { + this.isSelected[item] = true; + return true; + } + } + this.isSelected[item] = false; + return false; + } + + build() { + Column() { + List({ space: 10, initialIndex: 0 }) { + LazyForEach(this.arr, (index: number) => { + ListItem() { + Text('' + index) + .width('100%') + .height(100) + .fontSize(16) + .fontColor(this.isSelected[index] ? Color.White : Color.Black) + .textAlign(TextAlign.Center) + } + .backgroundColor(Color.White) + .selectable(true) + .selected(this.isSelected[index]) + .stateStyles({ + selected: this.selectedStyle + }) + .onMouse((event: MouseEvent) => { + // 判断是否按下鼠标左键 + if (event.button === MouseButton.Left && event.action === MouseAction.Press) { + // 判断之前是否已经时选中状态 + let isSelected: boolean = this.isItemSelected(index) + // 判断修饰键状态 + let isCtrlPressing: boolean = false + if (event.getModifierKeyState) { + isCtrlPressing = event.getModifierKeyState(['Ctrl']) + } + // 如果没有按着ctrl键点鼠标,则强制清理掉其他选中的条目并只让当前条目选中 + if (!isCtrlPressing) { + this.allSelectedItems = [] + for (let i = 0; i < this.isSelected.length; i++) { + this.isSelected[i] = false + } + } + if (isSelected) { + this.allSelectedItems.filter(item => item !== index) + this.isSelected[index] = false + } else { + this.allSelectedItems.push(index) + this.isSelected[index] = true + } + } + }) + }, (item: string) => item) + } + .listDirection(Axis.Vertical) + .scrollBar(BarState.Off) + .friction(0.6) + .edgeEffect(EdgeEffect.Spring) + .width('90%') + } + .width('100%') + .height('100%') + .backgroundColor(0xDCDCDC) + .padding({ top: 5 }) + } +} +// [End mouse_button] \ No newline at end of file diff --git a/ArkUIKit/InterAction/entry/src/main/ets/pages/MouseWheel/ListDataSource.ets b/ArkUIKit/InterAction/entry/src/main/ets/pages/MouseWheel/ListDataSource.ets new file mode 100644 index 000000000..f84f0676c --- /dev/null +++ b/ArkUIKit/InterAction/entry/src/main/ets/pages/MouseWheel/ListDataSource.ets @@ -0,0 +1,72 @@ +/* + * 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. + */ + +// [Start list_data_source] +export class ListDataSource implements IDataSource { + private list: number[] = []; + private listeners: DataChangeListener[] = []; + + constructor(list: number[]) { + this.list = list; + } + + totalCount(): number { + return this.list.length; + } + + getData(index: number): number { + return this.list[index]; + } + + registerDataChangeListener(listener: DataChangeListener): void { + if (this.listeners.indexOf(listener) < 0) { + this.listeners.push(listener); + } + } + + unregisterDataChangeListener(listener: DataChangeListener): void { + const pos = this.listeners.indexOf(listener); + if (pos >= 0) { + this.listeners.splice(pos, 1); + } + } + + // 通知控制器数据删除 + notifyDataDelete(index: number): void { + this.listeners.forEach(listener => { + listener.onDataDelete(index); + }); + } + + // 通知控制器添加数据 + notifyDataAdd(index: number): void { + this.listeners.forEach(listener => { + listener.onDataAdd(index); + }); + } + + // 在指定索引位置删除一个元素 + public deleteItem(index: number): void { + this.list.splice(index, 1); + this.notifyDataDelete(index); + } + + // 在指定索引位置插入一个元素 + public insertItem(index: number, data: number): void { + this.list.splice(index, 0, data); + this.notifyDataAdd(index); + } +} +// [End list_data_source] \ No newline at end of file diff --git a/ArkUIKit/InterAction/entry/src/main/ets/pages/MouseWheel/MouseWheel.ets b/ArkUIKit/InterAction/entry/src/main/ets/pages/MouseWheel/MouseWheel.ets new file mode 100644 index 000000000..91d358f36 --- /dev/null +++ b/ArkUIKit/InterAction/entry/src/main/ets/pages/MouseWheel/MouseWheel.ets @@ -0,0 +1,75 @@ +/* + * 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. + */ + +// [Start mouse_wheel] +import { ListDataSource } from './ListDataSource'; + +@Entry +@Component +struct MouseWheel { + private arr: ListDataSource = new ListDataSource([0, 1, 2, 3, 4, 5, 6, 7, 8, 9]); + @State dir1: Axis = Axis.Vertical; + + build() { + Column() { + Button('Click to Change ListDirection') + .margin(20) + .onClick(() => { + if (this.dir1 === Axis.Vertical) { + this.dir1 = Axis.Horizontal + } else { + this.dir1 = Axis.Vertical + } + }) + List({ space: 20, initialIndex: 0 }) { + LazyForEach(this.arr, (item: number) => { + ListItem() { + Text('' + item) + .width('100%') + .height(100) + .fontSize(16) + .textAlign(TextAlign.Center) + .borderRadius(10) + .backgroundColor(0xFFFFFF) + } + .margin(20) + // 为ListItem绑定滑动手势,当在ListItem上滚动鼠标滚轮时,会优先触发ListItem的滑动手势 + .gesture(PanGesture({ direction: PanDirection.Vertical }) + .onActionStart(() => { + }) + .onActionUpdate(() => { + })) + }, (item: number) => item.toString()) + } + .borderWidth(1) + .listDirection(this.dir1) // 排列方向 + .scrollBar(BarState.Off) + .friction(0.6) + .divider({ + strokeWidth: 2, + color: 0xFFFFFF, + startMargin: 20, + endMargin: 20 + }) // 每行之间的分界线 + .edgeEffect(EdgeEffect.Spring) // 边缘效果设置为Spring + .width('90%') + } + .width('100%') + .height('100%') + .backgroundColor(0xDCDCDC) + .padding(20) + } +} +// [End mouse_wheel] \ No newline at end of file diff --git a/ArkUIKit/InterAction/entry/src/main/ets/pages/MultipleFingerInformation/MultipleFingerInformation.ets b/ArkUIKit/InterAction/entry/src/main/ets/pages/MultipleFingerInformation/MultipleFingerInformation.ets new file mode 100644 index 000000000..bc898e381 --- /dev/null +++ b/ArkUIKit/InterAction/entry/src/main/ets/pages/MultipleFingerInformation/MultipleFingerInformation.ets @@ -0,0 +1,56 @@ +/* + * 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. + */ + +// [Start multiple_finger_information] +@Entry +@ComponentV2 +struct MultipleFingerInformation { + private currentFingerCount: number = 0 + private allFingerIds: number[] = [] + + build() { + RelativeContainer() { + Column() + .backgroundColor(Color.Green) + .height('100%') + .width('100%') + .onTouch((event: TouchEvent) => { + if (event.source !== SourceType.TouchScreen) { + return; + } + // clear数组 + this.allFingerIds.splice(0, this.allFingerIds.length) + // 从event中获取所有触点信息 + let allFingers = event.touches; + if (allFingers.length > 0 && this.currentFingerCount === 0) { + // 第1根手指按下 + this.currentFingerCount = allFingers.length + } + if (allFingers.length !== 0) { + for (const finger of allFingers) { + this.allFingerIds.push(finger.id) + } + } + if (event.type === TouchType.Up && event.touches.length === 1) { + // 所有手指都已抬起 + this.currentFingerCount = 0 + } + }) + } + .height('100%') + .width('100%') + } +} +// [End multiple_finger_information] \ No newline at end of file diff --git a/ArkUIKit/InterAction/entry/src/main/ets/pages/PreventBubbling/PreventBubbling.ets b/ArkUIKit/InterAction/entry/src/main/ets/pages/PreventBubbling/PreventBubbling.ets new file mode 100644 index 000000000..8323e35a0 --- /dev/null +++ b/ArkUIKit/InterAction/entry/src/main/ets/pages/PreventBubbling/PreventBubbling.ets @@ -0,0 +1,47 @@ +/* + * 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. + */ + +// [Start prevent_bubbling] +@Entry +@ComponentV2 +struct PreventBubbling { + + build() { + RelativeContainer() { + Column() { // 父组件 + Text($r('app.string.preventEvent')) + .fontColor(Color.White) + .height('40%') + .width('80%') + .backgroundColor(Color.Brown) + .alignSelf(ItemAlign.Center) + .padding(10) + .margin(20) + .onTouch((event:TouchEvent)=>{ + event.stopPropagation() // 子组件优先接收到触摸事件后,阻止父组件接收事件 + }) + } + .justifyContent(FlexAlign.End) + .backgroundColor(Color.Green) + .height('100%') + .width('100%') + .onTouch((event:TouchEvent)=>{ + }) + } + .height('100%') + .width('100%') + } +} +// [End prevent_bubbling] \ No newline at end of file diff --git a/ArkUIKit/InterAction/entry/src/main/ets/pages/common/Index.ets b/ArkUIKit/InterAction/entry/src/main/ets/pages/common/Index.ets new file mode 100644 index 000000000..02c5c6b98 --- /dev/null +++ b/ArkUIKit/InterAction/entry/src/main/ets/pages/common/Index.ets @@ -0,0 +1,23 @@ +/* + * 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. + */ + +export interface Route { + name: string; + label: ResourceStr; +} + +export interface RouteGroup extends Route { + children: Route[]; +} \ No newline at end of file diff --git a/ArkUIKit/InterAction/entry/src/main/ets/pages/mouseMove/MouseMove.ets b/ArkUIKit/InterAction/entry/src/main/ets/pages/mouseMove/MouseMove.ets new file mode 100644 index 000000000..8decf179f --- /dev/null +++ b/ArkUIKit/InterAction/entry/src/main/ets/pages/mouseMove/MouseMove.ets @@ -0,0 +1,61 @@ +/* + * 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. + */ + +// [Start mouse_move] +@Entry +@Component +struct MouseMove { + @State buttonText: string = ''; + @State columnText: string = ''; + @State text: string = 'OnMouse Sample Button'; + @State color: Color = Color.Gray; + + build() { + Column() { + Button(this.text, { type: ButtonType.Capsule }) + .width(200) + .height(100) + .backgroundColor(this.color) + .onMouse((event?: MouseEvent) => { // 设置Button的onMouse回调 + if (event) { + this.buttonText = 'Button onMouse:\n' + '' + + 'button = ' + event.button + '\n' + + 'action = ' + event.action + '\n' + + 'x,y = (' + event.x + ',' + event.y + ')' + '\n' + + 'windowXY=(' + event.windowX + ',' + event.windowY + ')'; + } + }) + Divider() + Text(this.buttonText).fontColor(Color.Green) + Divider() + Text(this.columnText).fontColor(Color.Red) + } + .width('100%') + .height('100%') + .justifyContent(FlexAlign.Center) + .borderWidth(2) + .borderColor(Color.Red) + .onMouse((event?: MouseEvent) => { // Set the onMouse callback for the column. + if (event) { + this.columnText = 'Column onMouse:\n' + '' + + 'button = ' + event.button + '\n' + + 'action = ' + event.action + '\n' + + 'x,y = (' + event.x + ',' + event.y + ')' + '\n' + + 'windowXY=(' + event.windowX + ',' + event.windowY + ')'; + } + }) + } +} +// [End mouse_move] \ No newline at end of file diff --git a/ArkUIKit/InterAction/entry/src/main/ets/pages/onHover/OnHover.ets b/ArkUIKit/InterAction/entry/src/main/ets/pages/onHover/OnHover.ets new file mode 100644 index 000000000..afc7d6c79 --- /dev/null +++ b/ArkUIKit/InterAction/entry/src/main/ets/pages/onHover/OnHover.ets @@ -0,0 +1,40 @@ +/* + * 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. + */ + +// [Start on_hover] +@Entry +@Component +struct OnHover { + @State hoverText: string = 'Not Hover'; + @State color: Color = Color.Gray; + + build() { + Column() { + Button(this.hoverText) + .width(200).height(100) + .backgroundColor(this.color) + .onHover((isHover?: boolean) => { // 使用onHover接口监听鼠标是否悬浮在Button组件上 + if (isHover) { + this.hoverText = 'Hovered!'; + this.color = Color.Green; + } else { + this.hoverText = 'Not Hover'; + this.color = Color.Gray; + } + }) + }.width('100%').height('100%').justifyContent(FlexAlign.Center) + } +} +// [End on_hover] \ No newline at end of file diff --git a/ArkUIKit/InterAction/entry/src/main/ets/pages/sampling/Sampling.ets b/ArkUIKit/InterAction/entry/src/main/ets/pages/sampling/Sampling.ets new file mode 100644 index 000000000..148bda7b1 --- /dev/null +++ b/ArkUIKit/InterAction/entry/src/main/ets/pages/sampling/Sampling.ets @@ -0,0 +1,39 @@ +/* + * 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. + */ + +// [Start samp_ling] +@Entry +@ComponentV2 +struct Sampling { + build() { + RelativeContainer() { + Column() + .backgroundColor(Color.Green) + .height('100%') + .width('100%') + .onTouch((event: TouchEvent) => { + // 从event中获取历史点 + let allHistoricalPoints = event.getHistoricalPoints(); + if (allHistoricalPoints.length !== 0) { + for (const point of allHistoricalPoints) { + } + } + }) + } + .height('100%') + .width('100%') + } +} +// [End samp_ling] \ No newline at end of file diff --git a/ArkUIKit/InterAction/entry/src/main/ets/pages/stopPropagation/StopPropagation.ets b/ArkUIKit/InterAction/entry/src/main/ets/pages/stopPropagation/StopPropagation.ets new file mode 100644 index 000000000..a7d85c001 --- /dev/null +++ b/ArkUIKit/InterAction/entry/src/main/ets/pages/stopPropagation/StopPropagation.ets @@ -0,0 +1,62 @@ +/* + * 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. + */ + +// [Start stop_propagation] +@Entry +@Component +struct StopPropagation { + @State buttonText: string = ''; + @State columnText: string = ''; + @State text: string = 'OnMouse Sample Button'; + @State color: Color = Color.Gray; + + build() { + Column() { + Button(this.text, { type: ButtonType.Capsule }) + .width(200) + .height(100) + .backgroundColor(this.color) + .onMouse((event?: MouseEvent) => { // 设置Button的onMouse回调 + if (event) { + event.stopPropagation(); // 在Button的onMouse事件中设置阻止冒泡 + this.buttonText = 'Button onMouse:\n' + '' + + 'button = ' + event.button + '\n' + + 'action = ' + event.action + '\n' + + 'x,y = ' + '\n' + '(' + event.x + ',' + event.y + ')' + '\n' + + 'windowXY=' + '\n' + '(' + event.windowX + ',' + event.windowY + ')'; + } + }) + Divider() + Text(this.buttonText).fontColor(Color.Green) + Divider() + Text(this.columnText).fontColor(Color.Red) + } + .width('100%') + .height('100%') + .justifyContent(FlexAlign.Center) + .borderWidth(2) + .borderColor(Color.Red) + .onMouse((event?: MouseEvent) => { // 设置Column的onMouse回调 + if (event) { + this.columnText = 'Column onMouse:\n' + '' + + 'button = ' + event.button + '\n' + + 'action = ' + event.action + '\n' + + 'x,y = ' + '\n' + '(' + event.x + ',' + event.y + ')' + '\n' + + 'windowXY=' + '\n' + '(' + event.windowX + ',' + event.windowY + ')'; + } + }) + } +} +// [End stop_propagation] \ No newline at end of file diff --git a/ArkUIKit/InterAction/entry/src/main/module.json5 b/ArkUIKit/InterAction/entry/src/main/module.json5 new file mode 100644 index 000000000..44e30abf3 --- /dev/null +++ b/ArkUIKit/InterAction/entry/src/main/module.json5 @@ -0,0 +1,65 @@ +/* + * 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. + */ + +{ + "module": { + "name": "entry", + "type": "entry", + "description": "$string:module_desc", + "mainElement": "EntryAbility", + "deviceTypes": [ + "default" + ], + "deliveryWithInstall": true, + "installationFree": false, + "pages": "$profile:main_pages", + "abilities": [ + { + "name": "EntryAbility", + "srcEntry": "./ets/entryability/EntryAbility.ets", + "description": "$string:EntryAbility_desc", + "icon": "$media:layered_image", + "label": "$string:EntryAbility_label", + "startWindowIcon": "$media:startIcon", + "startWindowBackground": "$color:start_window_background", + "exported": true, + "skills": [ + { + "entities": [ + "entity.system.home" + ], + "actions": [ + "ohos.want.action.home" + ] + } + ] + } + ], + "extensionAbilities": [ + { + "name": "EntryBackupAbility", + "srcEntry": "./ets/entrybackupability/EntryBackupAbility.ets", + "type": "backup", + "exported": false, + "metadata": [ + { + "name": "ohos.extension.backup", + "resource": "$profile:backup_config" + } + ], + } + ] + } +} \ No newline at end of file diff --git a/ArkUIKit/InterAction/entry/src/main/resources/base/element/color.json b/ArkUIKit/InterAction/entry/src/main/resources/base/element/color.json new file mode 100644 index 000000000..3c712962d --- /dev/null +++ b/ArkUIKit/InterAction/entry/src/main/resources/base/element/color.json @@ -0,0 +1,8 @@ +{ + "color": [ + { + "name": "start_window_background", + "value": "#FFFFFF" + } + ] +} \ No newline at end of file diff --git a/ArkUIKit/InterAction/entry/src/main/resources/base/element/float.json b/ArkUIKit/InterAction/entry/src/main/resources/base/element/float.json new file mode 100644 index 000000000..33ea22304 --- /dev/null +++ b/ArkUIKit/InterAction/entry/src/main/resources/base/element/float.json @@ -0,0 +1,8 @@ +{ + "float": [ + { + "name": "page_text_font_size", + "value": "50fp" + } + ] +} diff --git a/ArkUIKit/InterAction/entry/src/main/resources/base/element/string.json b/ArkUIKit/InterAction/entry/src/main/resources/base/element/string.json new file mode 100644 index 000000000..4953ba3fa --- /dev/null +++ b/ArkUIKit/InterAction/entry/src/main/resources/base/element/string.json @@ -0,0 +1,112 @@ +{ + "string": [ + { + "name": "module_desc", + "value": "module description" + }, + { + "name": "EntryAbility_desc", + "value": "description" + }, + { + "name": "EntryAbility_label", + "value": "label" + }, + { + "name": "FocusOnclick", + "value": "热区" + }, + { + "name": "FocusOnclickExample", + "value": "热区范围" + }, + { + "name": "PreventBubbling", + "value": "阻止冒泡" + }, + { + "name": "PreventBubblingExample", + "value": "阻止冒泡事件" + }, + { + "name": "sampling", + "value": "采样和历史点" + }, + { + "name": "samplingExample", + "value": "采样和历史点事件" + }, + { + "name": "MultipleFingerInformation", + "value": "多指信息" + }, + { + "name": "MultipleFingerInformationExample", + "value": "多指信息事件" + }, + { + "name": "mouseMove", + "value": "鼠标移动" + }, + { + "name": "mouseMoveExample", + "value": "鼠标移动事件" + }, + { + "name": "stopPropagation", + "value": "阻止鼠标冒泡" + }, + { + "name": "stopPropagationExample", + "value": "阻止鼠标冒泡事件" + }, + { + "name": "onHover", + "value": "鼠标移入移出" + }, + { + "name": "onHoverExample", + "value": "鼠标移入移出事件" + }, + { + "name": "MouseButton", + "value": "鼠标按键" + }, + { + "name": "MouseButtonExample", + "value": "鼠标按键事件" + }, + { + "name": "MouseWheel", + "value": "鼠标滚轮" + }, + { + "name": "MouseWheelExample", + "value": "鼠标滚轮事件" + }, + { + "name": "AnimatablePropertyText", + "value": "动画装饰器2" + }, + { + "name": "StylesDecorator", + "value": "Style装饰器" + }, + { + "name": "fancyAndglobalFancy", + "value": "Style装饰器1" + }, + { + "name": "FancyUse", + "value": "Style装饰器2" + }, + { + "name": "button", + "value": "按钮" + }, + { + "name": "preventEvent", + "value": "如果点中了我,就阻止父组件收到触摸事件" + } + ] +} \ No newline at end of file diff --git a/ArkUIKit/InterAction/entry/src/main/resources/base/media/background.png b/ArkUIKit/InterAction/entry/src/main/resources/base/media/background.png new file mode 100644 index 0000000000000000000000000000000000000000..923f2b3f27e915d6871871deea0420eb45ce102f GIT binary patch literal 91942 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

c)ijgxDm}8EsRXFt3h@+Ufr7@DN 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 literal 0 HcmV?d00001 diff --git a/ArkUIKit/InterAction/entry/src/main/resources/base/profile/backup_config.json b/ArkUIKit/InterAction/entry/src/main/resources/base/profile/backup_config.json new file mode 100644 index 000000000..78f40ae7c --- /dev/null +++ b/ArkUIKit/InterAction/entry/src/main/resources/base/profile/backup_config.json @@ -0,0 +1,3 @@ +{ + "allowToBackupRestore": true +} \ No newline at end of file diff --git a/ArkUIKit/InterAction/entry/src/main/resources/base/profile/main_pages.json b/ArkUIKit/InterAction/entry/src/main/resources/base/profile/main_pages.json new file mode 100644 index 000000000..9ebaca780 --- /dev/null +++ b/ArkUIKit/InterAction/entry/src/main/resources/base/profile/main_pages.json @@ -0,0 +1,14 @@ +{ + "src": [ + "pages/Index", + "pages/FocusOnclickExample/FocusOnclickExample", + "pages/PreventBubbling/PreventBubbling", + "pages/sampling/Sampling", + "pages/MultipleFingerInformation/MultipleFingerInformation", + "pages/mouseMove/MouseMove", + "pages/onHover/OnHover", + "pages/stopPropagation/StopPropagation", + "pages/MouseButton/MouseButton", + "pages/MouseWheel/MouseWheel" + ] +} diff --git a/ArkUIKit/InterAction/entry/src/main/resources/dark/element/color.json b/ArkUIKit/InterAction/entry/src/main/resources/dark/element/color.json new file mode 100644 index 000000000..79b11c274 --- /dev/null +++ b/ArkUIKit/InterAction/entry/src/main/resources/dark/element/color.json @@ -0,0 +1,8 @@ +{ + "color": [ + { + "name": "start_window_background", + "value": "#000000" + } + ] +} \ No newline at end of file diff --git a/ArkUIKit/InterAction/entry/src/main/syscap.json b/ArkUIKit/InterAction/entry/src/main/syscap.json new file mode 100644 index 000000000..d14edde42 --- /dev/null +++ b/ArkUIKit/InterAction/entry/src/main/syscap.json @@ -0,0 +1,20 @@ +{ + "devices": { + "general": [ + "default" + ], + "custom": [ + { + "xts": [ + "SystemCapability.ArkUI.ArkUI.Full", + "SystemCapability.ArkUI.ArkUI.Circle", + "SystemCapability.Test.UiTest", + "SystemCapability.Ability.AbilityRuntime.Core", + "SystemCapability.Notification.Emitter", + "SystemCapability.MiscServices.Time", + "SystemCapability.FileManagement.File.FileIO" + ] + } + ] + } +} \ No newline at end of file diff --git a/ArkUIKit/InterAction/entry/src/mock/mock-config.json5 b/ArkUIKit/InterAction/entry/src/mock/mock-config.json5 new file mode 100644 index 000000000..323d1d611 --- /dev/null +++ b/ArkUIKit/InterAction/entry/src/mock/mock-config.json5 @@ -0,0 +1,16 @@ +/* + * 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. + */ +{ +} \ No newline at end of file diff --git a/ArkUIKit/InterAction/entry/src/ohosTest/ets/test/Ability.test.ets b/ArkUIKit/InterAction/entry/src/ohosTest/ets/test/Ability.test.ets new file mode 100644 index 000000000..0f8ce9a2c --- /dev/null +++ b/ArkUIKit/InterAction/entry/src/ohosTest/ets/test/Ability.test.ets @@ -0,0 +1,50 @@ +/* + * 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 { hilog } from '@kit.PerformanceAnalysisKit'; +import { describe, beforeAll, beforeEach, afterEach, afterAll, it, expect } from '@ohos/hypium'; + +export default function abilityTest() { + describe('ActsAbilityTest', () => { + // Defines a test suite. Two parameters are supported: test suite name and test suite function. + beforeAll(() => { + // Presets an action, which is performed only once before all test cases of the test suite start. + // This API supports only one parameter: preset action function. + }) + beforeEach(() => { + // Presets an action, which is performed before each unit test case starts. + // The number of execution times is the same as the number of test cases defined by **it**. + // This API supports only one parameter: preset action function. + }) + afterEach(() => { + // Presets a clear action, which is performed after each unit test case ends. + // The number of execution times is the same as the number of test cases defined by **it**. + // This API supports only one parameter: clear action function. + }) + afterAll(() => { + // Presets a clear action, which is performed after all test cases of the test suite end. + // This API supports only one parameter: clear action function. + }) + it('assertContain', 0, () => { + // Defines a test case. This API supports three parameters: test case name, filter parameter, and test case function. + hilog.info(0x0000, 'testTag', '%{public}s', 'it begin'); + let a = 'abc'; + let b = 'b'; + // Defines a variety of assertion methods, which are used to declare expected boolean conditions. + expect(a).assertContain(b); + expect(a).assertEqual(a); + }) + }) +} \ No newline at end of file diff --git a/ArkUIKit/InterAction/entry/src/ohosTest/ets/test/Index.test.ets b/ArkUIKit/InterAction/entry/src/ohosTest/ets/test/Index.test.ets new file mode 100644 index 000000000..91eb14499 --- /dev/null +++ b/ArkUIKit/InterAction/entry/src/ohosTest/ets/test/Index.test.ets @@ -0,0 +1,189 @@ +/* + * 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 { describe, it, expect, beforeAll } from '@ohos/hypium'; +// 导入测试依赖kit +import { abilityDelegatorRegistry, Driver, ON, MatchPattern } from '@kit.TestKit'; +import { UIAbility, Want } from '@kit.AbilityKit'; + + +const delegator: abilityDelegatorRegistry.AbilityDelegator = abilityDelegatorRegistry.getAbilityDelegator(); +const bundleName = abilityDelegatorRegistry.getArguments().bundleName; +let want: Want; + +export default function ParentTest() { + describe('IndextTest', () => { + beforeAll(async () => { + want = { + bundleName: bundleName, + abilityName: 'EntryAbility' + }; + await delegator.startAbility(want); + let driver = Driver.create(); + await driver.delayMs(1000); + const ability: UIAbility = await delegator.getCurrentTopAbility(); + console.info('get top ability'); + expect(ability.context.abilityInfo.name).assertEqual('EntryAbility'); + }) + + /** + * @tc.number Interaction_0100 + * @tc.name testInteraction + * @tc.desc 热区验证 + */ + it('Interaction_0100', 0, async (done: Function) => { + let driver = Driver.create(); + let button = await driver.findComponent(ON.text($r('app.string.FocusOnclick'), MatchPattern.CONTAINS)); + await button.click(); + let button1 = await driver.findComponent(ON.text($r('app.string.FocusOnclickExample'), MatchPattern.CONTAINS)); + await button1.click(); + let button2 = await driver.findComponent(ON.text('按钮', MatchPattern.CONTAINS)); + await button2.click(); + await driver.delayMs(2000); + await driver.pressBack(); + done(); + }) + + /** + * @tc.number AnimatableExtendTest_001 + * @tc.name testAnimatableExtend + * @tc.desc 测试AnimatableExtend装饰器是否显示正常 + */ + it('Interaction_0200', 0, async (done: Function) => { + let driver = Driver.create(); + let button = await driver.findComponent(ON.text('阻止冒泡', MatchPattern.CONTAINS)); + await button.click(); + let button1 = await driver.findComponent(ON.text('阻止冒泡事件', MatchPattern.CONTAINS)); + await button1.click(); + let button2 = await driver.findComponent(ON.text('如果点中了我,就阻止父组件收到触摸事件', MatchPattern.CONTAINS)); + await button2.click(); + await driver.delayMs(2000); + await driver.pressBack(); + done(); + }) + + /** + * @tc.number Interaction_0300 + * @tc.name testInteraction + * @tc.desc 测试AnimatableExtend装饰器是否显示正常 + */ + it('Interaction_0300', 0, async (done: Function) => { + let driver = Driver.create(); + let button = await driver.findComponent(ON.text('采样和历史点', MatchPattern.CONTAINS)); + await button.click(); + let button1 = await driver.findComponent(ON.text('采样和历史点事件', MatchPattern.CONTAINS)); + await button1.click(); + await driver.delayMs(2000); + await driver.pressBack(); + done(); + }) + + /** + * @tc.number Interaction_0400 + * @tc.name testInteraction + * @tc.desc 测试AnimatableExtend装饰器是否显示正常 + */ + it('Interaction_0400', 0, async (done: Function) => { + let driver = Driver.create(); + let button = await driver.findComponent(ON.text('多指信息', MatchPattern.CONTAINS)); + await button.click(); + let button1 = await driver.findComponent(ON.text('多指信息事件', MatchPattern.CONTAINS)); + await button1.click(); + await driver.delayMs(2000); + await driver.pressBack(); + done(); + }) + + /** + * @tc.number Interaction_0500 + * @tc.name testInteraction + * @tc.desc 测试AnimatableExtend装饰器是否显示正常 + */ + it('Interaction_0500', 0, async (done: Function) => { + let driver = Driver.create(); + let button = await driver.findComponent(ON.text('鼠标移动', MatchPattern.CONTAINS)); + await button.click(); + let button1 = await driver.findComponent(ON.text('鼠标移动事件', MatchPattern.CONTAINS)); + await button1.click(); + await driver.delayMs(2000); + await driver.pressBack(); + done(); + }) + + /** + * @tc.number Interaction_0600 + * @tc.name testInteraction + * @tc.desc 测试AnimatableExtend装饰器是否显示正常 + */ + it('Interaction_0600', 0, async (done: Function) => { + let driver = Driver.create(); + let button = await driver.findComponent(ON.text('阻止鼠标冒泡', MatchPattern.CONTAINS)); + await button.click(); + let button1 = await driver.findComponent(ON.text('阻止鼠标冒泡事件', MatchPattern.CONTAINS)); + await button1.click(); + await driver.delayMs(2000); + await driver.pressBack(); + done(); + }) + + /** + * @tc.number Interaction_0700 + * @tc.name testInteraction + * @tc.desc 测试AnimatableExtend装饰器是否显示正常 + */ + it('Interaction_0700', 0, async (done: Function) => { + let driver = Driver.create(); + let button = await driver.findComponent(ON.text('鼠标移入移出', MatchPattern.CONTAINS)); + await button.click(); + let button1 = await driver.findComponent(ON.text('鼠标移入移出事件', MatchPattern.CONTAINS)); + await button1.click(); + await driver.delayMs(2000); + await driver.pressBack(); + done(); + }) + + /** + * @tc.number Interaction_0800 + * @tc.name testInteraction + * @tc.desc 测试AnimatableExtend装饰器是否显示正常 + */ + it('Interaction_0800', 0, async (done: Function) => { + let driver = Driver.create(); + let button = await driver.findComponent(ON.text('鼠标按键', MatchPattern.CONTAINS)); + await button.click(); + let button1 = await driver.findComponent(ON.text('鼠标按键事件', MatchPattern.CONTAINS)); + await button1.click(); + await driver.delayMs(2000); + await driver.pressBack(); + done(); + }) + + /** + * @tc.number Interaction_0900 + * @tc.name testInteraction + * @tc.desc 测试AnimatableExtend装饰器是否显示正常 + */ + it('Interaction_0900', 0, async (done: Function) => { + let driver = Driver.create(); + let button = await driver.findComponent(ON.text('鼠标滚轮', MatchPattern.CONTAINS)); + await button.click(); + let button1 = await driver.findComponent(ON.text('鼠标滚轮事件', MatchPattern.CONTAINS)); + await button1.click(); + await driver.delayMs(2000); + await driver.pressBack(); + done(); + }) + }) +} \ No newline at end of file diff --git a/ArkUIKit/InterAction/entry/src/ohosTest/ets/test/List.test.ets b/ArkUIKit/InterAction/entry/src/ohosTest/ets/test/List.test.ets new file mode 100644 index 000000000..559689169 --- /dev/null +++ b/ArkUIKit/InterAction/entry/src/ohosTest/ets/test/List.test.ets @@ -0,0 +1,20 @@ +/* + * 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 ParentTest from './Index.test' + +export default function testsuite() { + ParentTest(); +} \ No newline at end of file diff --git a/ArkUIKit/InterAction/entry/src/ohosTest/module.json5 b/ArkUIKit/InterAction/entry/src/ohosTest/module.json5 new file mode 100644 index 000000000..0c08292a5 --- /dev/null +++ b/ArkUIKit/InterAction/entry/src/ohosTest/module.json5 @@ -0,0 +1,26 @@ +/* + * 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. + */ + +{ + "module": { + "name": "entry_test", + "type": "feature", + "deviceTypes": [ + "default" + ], + "deliveryWithInstall": true, + "installationFree": false + } +} diff --git a/ArkUIKit/InterAction/entry/src/test/List.test.ets b/ArkUIKit/InterAction/entry/src/test/List.test.ets new file mode 100644 index 000000000..f1186b1f5 --- /dev/null +++ b/ArkUIKit/InterAction/entry/src/test/List.test.ets @@ -0,0 +1,20 @@ +/* + * 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 localUnitTest from './LocalUnit.test'; + +export default function testsuite() { + localUnitTest(); +} \ No newline at end of file diff --git a/ArkUIKit/InterAction/entry/src/test/LocalUnit.test.ets b/ArkUIKit/InterAction/entry/src/test/LocalUnit.test.ets new file mode 100644 index 000000000..7fc57c77d --- /dev/null +++ b/ArkUIKit/InterAction/entry/src/test/LocalUnit.test.ets @@ -0,0 +1,48 @@ +/* + * 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 { describe, beforeAll, beforeEach, afterEach, afterAll, it, expect } from '@ohos/hypium'; + +export default function localUnitTest() { + describe('localUnitTest', () => { + // Defines a test suite. Two parameters are supported: test suite name and test suite function. + beforeAll(() => { + // Presets an action, which is performed only once before all test cases of the test suite start. + // This API supports only one parameter: preset action function. + }); + beforeEach(() => { + // Presets an action, which is performed before each unit test case starts. + // The number of execution times is the same as the number of test cases defined by **it**. + // This API supports only one parameter: preset action function. + }); + afterEach(() => { + // Presets a clear action, which is performed after each unit test case ends. + // The number of execution times is the same as the number of test cases defined by **it**. + // This API supports only one parameter: clear action function. + }); + afterAll(() => { + // Presets a clear action, which is performed after all test cases of the test suite end. + // This API supports only one parameter: clear action function. + }); + it('assertContain', 0, () => { + // Defines a test case. This API supports three parameters: test case name, filter parameter, and test case function. + let a = 'abc'; + let b = 'b'; + // Defines a variety of assertion methods, which are used to declare expected boolean conditions. + expect(a).assertContain(b); + expect(a).assertEqual(a); + }); + }); +} \ No newline at end of file diff --git a/ArkUIKit/InterAction/hvigor/hvigor-config.json5 b/ArkUIKit/InterAction/hvigor/hvigor-config.json5 new file mode 100644 index 000000000..3b057578a --- /dev/null +++ b/ArkUIKit/InterAction/hvigor/hvigor-config.json5 @@ -0,0 +1,37 @@ +/* + * 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. + */ +{ + "modelVersion": "6.0.0", + "dependencies": { + }, + "execution": { + // "analyze": "normal", /* Define the build analyze mode. Value: [ "normal" | "advanced" | "ultrafine" | false ]. Default: "normal" */ + // "daemon": true, /* Enable daemon compilation. Value: [ true | false ]. Default: true */ + // "incremental": true, /* Enable incremental compilation. Value: [ true | false ]. Default: true */ + // "parallel": true, /* Enable parallel compilation. Value: [ true | false ]. Default: true */ + // "typeCheck": false, /* Enable typeCheck. Value: [ true | false ]. Default: false */ + // "optimizationStrategy": "memory" /* Define the optimization strategy. Value: [ "memory" | "performance" ]. Default: "memory" */ + }, + "logging": { + // "level": "info" /* Define the log level. Value: [ "debug" | "info" | "warn" | "error" ]. Default: "info" */ + }, + "debugging": { + // "stacktrace": false /* Disable stacktrace compilation. Value: [ true | false ]. Default: false */ + }, + "nodeOptions": { + // "maxOldSpaceSize": 8192 /* Enable nodeOptions maxOldSpaceSize compilation. Unit M. Used for the daemon process. Default: 8192*/ + // "exposeGC": true /* Enable to trigger garbage collection explicitly. Default: true*/ + } +} diff --git a/ArkUIKit/InterAction/hvigorfile.ts b/ArkUIKit/InterAction/hvigorfile.ts new file mode 100644 index 000000000..e3340f07e --- /dev/null +++ b/ArkUIKit/InterAction/hvigorfile.ts @@ -0,0 +1,21 @@ +/* + * 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 { appTasks } from '@ohos/hvigor-ohos-plugin'; + +export default { + system: appTasks, /* 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/ArkUIKit/InterAction/oh-package.json5 b/ArkUIKit/InterAction/oh-package.json5 new file mode 100644 index 000000000..69cb43cba --- /dev/null +++ b/ArkUIKit/InterAction/oh-package.json5 @@ -0,0 +1,25 @@ +/* + * 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. + */ + +{ + "modelVersion": "6.0.0", + "description": "Please describe the basic information.", + "dependencies": { + }, + "devDependencies": { + "@ohos/hypium": "1.0.24", + "@ohos/hamock": "1.0.0" + } +} diff --git a/ArkUIKit/InterAction/ohosTest.md b/ArkUIKit/InterAction/ohosTest.md new file mode 100644 index 000000000..9311d7b4f --- /dev/null +++ b/ArkUIKit/InterAction/ohosTest.md @@ -0,0 +1,8 @@ +| 测试功能 | 预置条件 | 输入 | 预期输出 | 测试结果 | +| | ------------ | ---------------------- | --------------------------- | -------- | +| 首页加载测试 | 设备正常运行 | 验证基础元素渲染 | 检查标题和列表组件 | Pass | +| 鼠标按键测试 | 设备正常运行 | 同时按着ctrl和鼠标左键选中多个 | 可以选中多个 | Pass | +| 鼠标滚轮测试 | 设备正常运行 | 点击'Click to Change ListDirection'切换滚动方向 | 切换滚动方向成功 | Pass | +| 鼠标移入测试 | 设备正常运行 | 鼠标移入方框 | 方框背景色跟文字变化 | Pass | +| 鼠标移动测试 | 设备正常运行 | 移动鼠标 | 页面文本随之变化 | Pass | + diff --git a/ArkUIKit/InterAction/screenshots/device/image1.png b/ArkUIKit/InterAction/screenshots/device/image1.png new file mode 100644 index 0000000000000000000000000000000000000000..25b17b90926d156e097dfabe84bd386cd5d86a52 GIT binary patch literal 23450 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 literal 0 HcmV?d00001 diff --git a/ArkUIKit/InterAction/screenshots/device/image2.png b/ArkUIKit/InterAction/screenshots/device/image2.png new file mode 100644 index 0000000000000000000000000000000000000000..4c42d8b52e98583e4fbdb3e154111b64c9e64a35 GIT binary patch literal 15616 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�XE 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%0AXbDmtI+0POeSvp+~#V8yQ4-ke*K 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 T#lR^u(8*(#W(7x`{`kKDY}s;X literal 0 HcmV?d00001 diff --git a/ArkUIKit/StyledStringNDK/README.md b/ArkUIKit/StyledStringNDK/README.md index 041551c62..a6b659e65 100644 --- a/ArkUIKit/StyledStringNDK/README.md +++ b/ArkUIKit/StyledStringNDK/README.md @@ -52,13 +52,11 @@ entry/src/main/ ## 约束和限制 -1. 本示例支持仅标准系统上运行,支持设备:华为手机、华为平板。 +1. 本示例支持标准系统上运行,支持设备:RK3568; -2. HarmonyOS系统:HarmonyOS 6.0.0 Beta3版本及以上。 +2. 本示例支持API20版本SDK,版本号:6.0.0.36; -3. DevEco Studio版本:DevEco Studio 6.0.0 Beta3版本及以上。 - -4. HarmonyOS SDK版本:HarmonyOS 6.0.0 Beta3 SDK版本及以上。 +3. 本示例已支持使DevEco Studio 5.0.5 Release (构建版本:5.0.13.100,构建 2025年4月25日)编译运行 ## 下载 @@ -67,7 +65,7 @@ entry/src/main/ ``` git init git config core.sparsecheckout true -echo ArkUIKit/StyledStringNDK > .git/info/sparse-checkout -git remote add origin https://gitee.com/harmonyos_samples/guide-snippets.git +echo code/DocsSample/ArkUISample/StyledStringNDK > .git/info/sparse-checkout +git remote add origin https://gitee.com/openharmony/applications_app_samples.git git pull origin master ``` \ No newline at end of file diff --git a/ArkUIKit/StyledStringNDK/build-profile.json5 b/ArkUIKit/StyledStringNDK/build-profile.json5 index d4774ea1b..fd3e8fb5f 100644 --- a/ArkUIKit/StyledStringNDK/build-profile.json5 +++ b/ArkUIKit/StyledStringNDK/build-profile.json5 @@ -18,7 +18,9 @@ { "name": "default", "signingConfig": "default", + "compileSdkVersion": "6.0.0(20)", "compatibleSdkVersion": "6.0.0(20)", + "targetSdkVersion": "6.0.0(20)", "runtimeOS": "HarmonyOS", "buildOption": { "strictMode": { diff --git a/ArkUIKit/StyledStringNDK/entry/build-profile.json5 b/ArkUIKit/StyledStringNDK/entry/build-profile.json5 index 9b5904523..a20094043 100644 --- a/ArkUIKit/StyledStringNDK/entry/build-profile.json5 +++ b/ArkUIKit/StyledStringNDK/entry/build-profile.json5 @@ -1,3 +1,17 @@ +/* + * 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. + */ { "apiType": "stageMode", "buildOption": { @@ -5,7 +19,10 @@ "path": "./src/main/cpp/CMakeLists.txt", "arguments": "", "cppFlags": "", - "abiFilters": ["arm64-v8a", "x86_64"] + "abiFilters": [ + "arm64-v8a", + "x86_64" + ] } }, "buildOptionSet": [ diff --git a/ArkUIKit/StyledStringNDK/entry/src/main/cpp/manager.cpp b/ArkUIKit/StyledStringNDK/entry/src/main/cpp/manager.cpp index e281e0537..16e42cb8d 100644 --- a/ArkUIKit/StyledStringNDK/entry/src/main/cpp/manager.cpp +++ b/ArkUIKit/StyledStringNDK/entry/src/main/cpp/manager.cpp @@ -12,9 +12,14 @@ * See the License for the specific language governing permissions and * limitations under the License. */ +// [Start obtain_create_text_all] #include "manager.h" +#include #include #include +// [StartExclude obtain_create_text_all] +#include +// [EndExclude obtain_create_text_all] #include #include @@ -22,29 +27,36 @@ namespace NativeNode::Manager { constexpr int32_t NUM_10 = 10; constexpr int32_t NUM_28 = 28; constexpr int32_t NUM_400 = 400; +// [StartExclude obtain_create_text_all] NodeManager &NodeManager::GetInstance() { static NodeManager instance; return instance; } -void NodeManager::SetContentHandle(ArkUI_NodeContentHandle contentHandle) { contentHandle_ = contentHandle; } +void NodeManager::SetXComponent(OH_NativeXComponent *xComponent) { xComponent_ = xComponent; } +// [EndExclude obtain_create_text_all] void NodeManager::CreateNativeNode() { - if (!contentHandle_) { + // [StartExclude obtain_create_text_all] + if (!xComponent_) { return; } + // [EndExclude obtain_create_text_all] + // [Start obtain_create_text] ArkUI_NativeNodeAPI_1 *nodeApi = reinterpret_cast( OH_ArkUI_QueryModuleInterfaceByName(ARKUI_NATIVE_NODE, "ArkUI_NativeNodeAPI_1")); if (nodeApi == nullptr) { return; } + // [StartExclude obtain_create_text] // 创建一个Column容器组件 ArkUI_NodeHandle column = nodeApi->createNode(ARKUI_NODE_COLUMN); ArkUI_NumberValue colWidth[] = {{.f32 = 300}}; ArkUI_AttributeItem widthItem = {.value = colWidth, .size = 1}; nodeApi->setAttribute(column, NODE_WIDTH, &widthItem); + // [EndExclude obtain_create_text] // 创建Text组件 ArkUI_NodeHandle text = nodeApi->createNode(ARKUI_NODE_TEXT); ArkUI_NumberValue textWidth[] = {{.f32 = 300}}; @@ -53,17 +65,22 @@ void NodeManager::CreateNativeNode() ArkUI_NumberValue textHeight[] = {{.f32 = 100}}; ArkUI_AttributeItem textHeightItem = {.value = textHeight, .size = 1}; nodeApi->setAttribute(text, NODE_HEIGHT, &textHeightItem); + // [End obtain_create_text] ArkUI_NumberValue borderWidth[] = {{.f32 = 1}}; ArkUI_AttributeItem borderWidthItem = {.value = borderWidth, .size = 1}; nodeApi->setAttribute(text, NODE_BORDER_WIDTH, &borderWidthItem); // OH_Drawing_开头的API是字体引擎提供的,typographyStyle表示段落样式。 + // [Start obtain_create_text_typographyStyle] OH_Drawing_TypographyStyle *typographyStyle = OH_Drawing_CreateTypographyStyle(); OH_Drawing_SetTypographyTextAlign(typographyStyle, OH_Drawing_TextAlign::TEXT_ALIGN_CENTER); OH_Drawing_SetTypographyTextMaxLines(typographyStyle, NUM_10); + // [End obtain_create_text_typographyStyle] // 创建 ArkUI_StyledString。 + // [Start obtain_create_text_styledString] ArkUI_StyledString *styledString = OH_ArkUI_StyledString_Create(typographyStyle, OH_Drawing_CreateFontCollection()); // 创建文本样式,设置字体和颜色。 + // [Start obtain_create_text_placeholder] OH_Drawing_TextStyle *textStyle = OH_Drawing_CreateTextStyle(); OH_Drawing_SetTextStyleFontSize(textStyle, NUM_28); OH_Drawing_SetTextStyleColor(textStyle, OH_Drawing_ColorSetArgb(0xFF, 0x70, 0x70, 0x70)); @@ -71,9 +88,11 @@ void NodeManager::CreateNativeNode() OH_ArkUI_StyledString_PushTextStyle(styledString, textStyle); OH_ArkUI_StyledString_AddText(styledString, "Hello"); OH_ArkUI_StyledString_PopTextStyle(styledString); + // [StartExclude obtain_create_text_styledString] // 添加占位,此区域内不会绘制文字,可以在此位置挂载Image组件实现图文混排。 OH_Drawing_PlaceholderSpan placeHolder{.width = 100, .height = 100}; OH_ArkUI_StyledString_AddPlaceholder(styledString, &placeHolder); + // [EndExclude obtain_create_text_styledString] // 设置不同样式的文字 OH_Drawing_TextStyle *worldTextStyle = OH_Drawing_CreateTextStyle(); OH_Drawing_SetTextStyleFontSize(worldTextStyle, NUM_28); @@ -81,20 +100,27 @@ void NodeManager::CreateNativeNode() OH_ArkUI_StyledString_PushTextStyle(styledString, worldTextStyle); OH_ArkUI_StyledString_AddText(styledString, "World!"); OH_ArkUI_StyledString_PopTextStyle(styledString); + // [End obtain_create_text_placeholder] + // [End obtain_create_text_styledString] // 依赖StyledString对象创建字体引擎的Typography,此时它已经包含了设置的文本及其样式。 + // [Start obtain_create_text_typography] OH_Drawing_Typography *typography = OH_ArkUI_StyledString_CreateTypography(styledString); // 字体引擎布局方法,需传入一个宽度,此宽度需与Text组件宽度匹配。 // 布局宽度 = Text组件宽度 - (左padding + 右padding) OH_Drawing_TypographyLayout(typography, NUM_400); + // [End obtain_create_text_typography] + // [Start obtain_create_text_attributeItem] ArkUI_AttributeItem styledStringItem = {.object = styledString}; // 布局完成后,通过NODE_TEXT_CONTENT_WITH_STYLED_STRING设置给Text组件。 nodeApi->setAttribute(text, NODE_TEXT_CONTENT_WITH_STYLED_STRING, &styledStringItem); + // [End obtain_create_text_attributeItem] // 资源释放,应用侧可以自由决定何时释放。 OH_ArkUI_StyledString_Destroy(styledString); // Text作为Column子组件 nodeApi->addChild(column, text); - // Column作为ContentSlot子组件 - OH_ArkUI_NodeContent_AddNode(contentHandle_, column); + // Column作为XComponent子组件 + OH_NativeXComponent_AttachNativeRootNode(xComponent_, column); } } // namespace NativeNode::Manager +// [End obtain_create_text_all] diff --git a/ArkUIKit/StyledStringNDK/entry/src/main/cpp/manager.h b/ArkUIKit/StyledStringNDK/entry/src/main/cpp/manager.h index 40d7565e5..55b98a698 100644 --- a/ArkUIKit/StyledStringNDK/entry/src/main/cpp/manager.h +++ b/ArkUIKit/StyledStringNDK/entry/src/main/cpp/manager.h @@ -28,11 +28,11 @@ class NodeManager { public: ~NodeManager() = default; static NodeManager& GetInstance(); - void SetContentHandle(ArkUI_NodeContentHandle contentHandle); + void SetXComponent(OH_NativeXComponent* xComponent); void CreateNativeNode(); private: NodeManager() = default; - ArkUI_NodeContentHandle contentHandle_; + OH_NativeXComponent* xComponent_; std::unordered_map callbackMap_; }; } diff --git a/ArkUIKit/StyledStringNDK/entry/src/main/cpp/napi_init.cpp b/ArkUIKit/StyledStringNDK/entry/src/main/cpp/napi_init.cpp index 8de3f3d6c..0ef82312d 100644 --- a/ArkUIKit/StyledStringNDK/entry/src/main/cpp/napi_init.cpp +++ b/ArkUIKit/StyledStringNDK/entry/src/main/cpp/napi_init.cpp @@ -13,23 +13,27 @@ * limitations under the License. */ #include "manager.h" -#include #include -#include #include -static napi_value createNativeNode(napi_env env, napi_callback_info info) +static OH_NativeXComponent* GetXComponent(napi_env env, napi_value exports) { - size_t argc = 1; - napi_value args[1] = { nullptr }; - if (napi_get_cb_info(env, info, &argc, args, nullptr, nullptr) != napi_ok) { - OH_LOG_Print(LOG_APP, LOG_ERROR, 0xFF00, "StyledStringNDK", "CreateNativeNode napi_get_cb_info failed"); + if ((env == nullptr) || (exports == nullptr)) { + return nullptr; + } + napi_value exportInstance = nullptr; + if (napi_get_named_property(env, exports, OH_NATIVE_XCOMPONENT_OBJ, &exportInstance) != napi_ok) { + return nullptr; + } + OH_NativeXComponent* xComp = nullptr; + if (napi_unwrap(env, exportInstance, reinterpret_cast(&xComp)) != napi_ok) { return nullptr; } - // 获取NodeContent - ArkUI_NodeContentHandle contentHandle; - OH_ArkUI_GetNodeContentFromNapiValue(env, args[0], &contentHandle); - NativeNode::Manager::NodeManager::GetInstance().SetContentHandle(contentHandle); + return xComp; +} + +static napi_value createNativeNode(napi_env env, napi_callback_info info) +{ NativeNode::Manager::NodeManager::GetInstance().CreateNativeNode(); return nullptr; } @@ -41,6 +45,10 @@ static napi_value Init(napi_env env, napi_value exports) { "createNativeNode", nullptr, createNativeNode, nullptr, nullptr, nullptr, napi_default, nullptr } }; napi_define_properties(env, exports, sizeof(desc) / sizeof(desc[0]), desc); + auto xComponent = GetXComponent(env, exports); + if (xComponent) { + NativeNode::Manager::NodeManager::GetInstance().SetXComponent(xComponent); + } return exports; } EXTERN_C_END diff --git a/ArkUIKit/StyledStringNDK/entry/src/main/cpp/types/libentry/Index.d.ts b/ArkUIKit/StyledStringNDK/entry/src/main/cpp/types/libentry/Index.d.ts index da6cd3291..c09127fac 100644 --- a/ArkUIKit/StyledStringNDK/entry/src/main/cpp/types/libentry/Index.d.ts +++ b/ArkUIKit/StyledStringNDK/entry/src/main/cpp/types/libentry/Index.d.ts @@ -12,5 +12,4 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - -export const createNativeNode: (content: object) => void; \ No newline at end of file +export const createNativeNode: () => void; \ No newline at end of file diff --git a/ArkUIKit/StyledStringNDK/entry/src/main/ets/pages/Index.ets b/ArkUIKit/StyledStringNDK/entry/src/main/ets/pages/Index.ets index 4193211d1..073f244e8 100644 --- a/ArkUIKit/StyledStringNDK/entry/src/main/ets/pages/Index.ets +++ b/ArkUIKit/StyledStringNDK/entry/src/main/ets/pages/Index.ets @@ -13,24 +13,24 @@ * limitations under the License. */ import testNapi from 'libentry.so'; -import { NodeContent } from '@kit.ArkUI'; @Entry @Component struct Index { - private nodeContent: Content = new NodeContent(); build() { Row() { Column() { - ContentSlot(this.nodeContent) + XComponent({ + id: "xComponent", + type: XComponentType.NODE, + libraryname: "entry" + }).onAppear(()=> { + testNapi.createNativeNode() + }) } .width('100%') } .height('100%') } - - aboutToAppear(): void { - testNapi.createNativeNode(this.nodeContent); - } } diff --git a/ArkUIKit/StyledStringNDK/entry/src/main/module.json5 b/ArkUIKit/StyledStringNDK/entry/src/main/module.json5 index 8b215df6b..e816d2f02 100644 --- a/ArkUIKit/StyledStringNDK/entry/src/main/module.json5 +++ b/ArkUIKit/StyledStringNDK/entry/src/main/module.json5 @@ -19,8 +19,7 @@ "description": "$string:module_desc", "mainElement": "EntryAbility", "deviceTypes": [ - "phone", - "tablet" + "default" ], "deliveryWithInstall": true, "installationFree": false, diff --git a/ArkUIKit/StyledStringNDK/entry/src/main/syscap.json b/ArkUIKit/StyledStringNDK/entry/src/main/syscap.json new file mode 100644 index 000000000..19b9dd01e --- /dev/null +++ b/ArkUIKit/StyledStringNDK/entry/src/main/syscap.json @@ -0,0 +1,12 @@ +{ + "devices": { + "general": ["default"], + "custom": [ + { + "xts": [ + "SystemCapability.Graphic.Graphic2D.NativeDrawing" + ] + } + ] + } +} \ No newline at end of file diff --git a/ArkUIKit/StyledStringNDK/entry/src/ohosTest/ets/test/Ability.test.ets b/ArkUIKit/StyledStringNDK/entry/src/ohosTest/ets/test/Ability.test.ets index 7f30942b8..153a6b2f7 100644 --- a/ArkUIKit/StyledStringNDK/entry/src/ohosTest/ets/test/Ability.test.ets +++ b/ArkUIKit/StyledStringNDK/entry/src/ohosTest/ets/test/Ability.test.ets @@ -13,7 +13,8 @@ * limitations under the License. */ import { hilog } from '@kit.PerformanceAnalysisKit'; -import { describe, beforeAll, beforeEach, afterEach, afterAll, it, expect } from '@ohos/hypium'; +import testNapi from 'libentry.so'; +import { describe, beforeAll, beforeEach, afterEach, afterAll, it, expect, Level } from '@ohos/hypium'; export default function abilityTest() { describe('ActsAbilityTest', () => { @@ -36,14 +37,19 @@ export default function abilityTest() { // Presets a clear action, which is performed after all test cases of the test suite end. // This API supports only one parameter: clear action function. }) - it('assertContain', 0, () => { + + /** + * @tc.number testStyledStringNDK_001 + * @tc.name testStyledStringNDK_001 + * @tc.desc test testStyledStringNDK + * @tc.level: Level 1 + */ + it('testStyledStringNDK_001', Level.LEVEL1, async (done: Function) => { // Defines a test case. This API supports three parameters: test case name, filter parameter, and test case function. - hilog.info(0x0000, 'testTag', '%{public}s', 'it begin'); - let a = 'abc'; - let b = 'b'; - // Defines a variety of assertion methods, which are used to declare expected boolean conditions. - expect(a).assertContain(b); - expect(a).assertEqual(a); + hilog.info(0x0000, 'testTag', 'testStyledStringNDK_001 begin'); + testNapi.createNativeNode(); + hilog.info(0x0000, 'testTag', 'testStyledStringNDK_001 end'); + done(); }) }) } \ No newline at end of file diff --git a/ArkUIKit/StyledStringNDK/entry/src/ohosTest/ets/testability/TestAbility.ets b/ArkUIKit/StyledStringNDK/entry/src/ohosTest/ets/testability/TestAbility.ets new file mode 100644 index 000000000..66d72d2a3 --- /dev/null +++ b/ArkUIKit/StyledStringNDK/entry/src/ohosTest/ets/testability/TestAbility.ets @@ -0,0 +1,66 @@ +/* + * 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 UIAbility from '@ohos.app.ability.UIAbility'; +import AbilityDelegatorRegistry from '@ohos.app.ability.abilityDelegatorRegistry'; +import hilog from '@ohos.hilog'; +import { Hypium } from '@ohos/hypium'; +import testsuite from '../test/List.test'; +import window from '@ohos.window'; +import Want from '@ohos.app.ability.Want'; +import AbilityConstant from '@ohos.app.ability.AbilityConstant'; + +export default class TestAbility extends UIAbility { + onCreate(want: Want, launchParam: AbilityConstant.LaunchParam) { + hilog.info(0x0000, 'testTag', '%{public}s', 'TestAbility onCreate'); + hilog.info(0x0000, 'testTag', '%{public}s', 'want param:' + JSON.stringify(want) ?? ''); + hilog.info(0x0000, 'testTag', '%{public}s', 'launchParam:'+ JSON.stringify(launchParam) ?? ''); + let abilityDelegator: AbilityDelegatorRegistry.AbilityDelegator; + abilityDelegator = AbilityDelegatorRegistry.getAbilityDelegator(); + let abilityDelegatorArguments: AbilityDelegatorRegistry.AbilityDelegatorArgs; + abilityDelegatorArguments = AbilityDelegatorRegistry.getArguments(); + hilog.info(0x0000, 'testTag', '%{public}s', 'start run testcase!!!'); + Hypium.hypiumTest(abilityDelegator, abilityDelegatorArguments, testsuite); + } + + onDestroy() { + hilog.info(0x0000, 'testTag', '%{public}s', 'TestAbility onDestroy'); + } + + onWindowStageCreate(windowStage: window.WindowStage) { + hilog.info(0x0000, 'testTag', '%{public}s', 'TestAbility onWindowStageCreate'); + windowStage.loadContent('testability/pages/Index', (err, data) => { + if (err.code) { + hilog.error(0x0000, 'testTag', 'Failed to load the content. Cause: %{public}s', + JSON.stringify(err) ?? ''); + return; + } + hilog.info(0x0000, 'testTag', 'Succeeded in loading the content. Data: %{public}s', + JSON.stringify(data) ?? ''); + }); + } + + onWindowStageDestroy() { + hilog.info(0x0000, 'testTag', '%{public}s', 'TestAbility onWindowStageDestroy'); + } + + onForeground() { + hilog.info(0x0000, 'testTag', '%{public}s', 'TestAbility onForeground'); + } + + onBackground() { + hilog.info(0x0000, 'testTag', '%{public}s', 'TestAbility onBackground'); + } +} \ No newline at end of file diff --git a/ArkUIKit/StyledStringNDK/entry/src/ohosTest/ets/testability/pages/Index.ets b/ArkUIKit/StyledStringNDK/entry/src/ohosTest/ets/testability/pages/Index.ets new file mode 100644 index 000000000..073f244e8 --- /dev/null +++ b/ArkUIKit/StyledStringNDK/entry/src/ohosTest/ets/testability/pages/Index.ets @@ -0,0 +1,36 @@ +/* + * 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 testNapi from 'libentry.so'; + +@Entry +@Component +struct Index { + + build() { + Row() { + Column() { + XComponent({ + id: "xComponent", + type: XComponentType.NODE, + libraryname: "entry" + }).onAppear(()=> { + testNapi.createNativeNode() + }) + } + .width('100%') + } + .height('100%') + } +} diff --git a/ArkUIKit/StyledStringNDK/entry/src/ohosTest/ets/testrunner/OpenHarmonyTestRunner.ts b/ArkUIKit/StyledStringNDK/entry/src/ohosTest/ets/testrunner/OpenHarmonyTestRunner.ts new file mode 100644 index 000000000..1493be8f3 --- /dev/null +++ b/ArkUIKit/StyledStringNDK/entry/src/ohosTest/ets/testrunner/OpenHarmonyTestRunner.ts @@ -0,0 +1,64 @@ +/* + * 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 hilog from '@ohos.hilog'; +import TestRunner from '@ohos.application.testRunner'; +import AbilityDelegatorRegistry from '@ohos.app.ability.abilityDelegatorRegistry'; + +var abilityDelegator = undefined; +var abilityDelegatorArguments = undefined; + +async function onAbilityCreateCallback() { + hilog.info(0x0000, 'testTag', '%{public}s', 'onAbilityCreateCallback'); +} + +async function addAbilityMonitorCallback(err: any) { + hilog.info(0x0000, 'testTag', 'addAbilityMonitorCallback : %{public}s', JSON.stringify(err) ?? ''); +} + +export default class OpenHarmonyTestRunner implements TestRunner { + constructor() { + } + + onPrepare() { + hilog.info(0x0000, 'testTag', '%{public}s', 'OpenHarmonyTestRunner OnPrepare '); + } + + async onRun() { + hilog.info(0x0000, 'testTag', '%{public}s', 'OpenHarmonyTestRunner onRun run'); + abilityDelegatorArguments = AbilityDelegatorRegistry.getArguments(); + abilityDelegator = AbilityDelegatorRegistry.getAbilityDelegator(); + var testAbilityName = abilityDelegatorArguments.bundleName + '.TestAbility'; + let lMonitor = { + abilityName: testAbilityName, + onAbilityCreate: onAbilityCreateCallback, + }; + abilityDelegator.addAbilityMonitor(lMonitor, addAbilityMonitorCallback); + var cmd = 'aa start -d 0 -a TestAbility' + ' -b ' + abilityDelegatorArguments.bundleName; + var debug = abilityDelegatorArguments.parameters['-D']; + if (debug == 'true') + { + cmd += ' -D' + } + hilog.info(0x0000, 'testTag', 'cmd : %{public}s', cmd); + abilityDelegator.executeShellCommand(cmd, + (err: any, d: any) => { + hilog.info(0x0000, 'testTag', 'executeShellCommand : err : %{public}s', JSON.stringify(err) ?? ''); + hilog.info(0x0000, 'testTag', 'executeShellCommand : data : %{public}s', d.stdResult ?? ''); + hilog.info(0x0000, 'testTag', 'executeShellCommand : data : %{public}s', d.exitCode ?? ''); + }); + hilog.info(0x0000, 'testTag', '%{public}s', 'OpenHarmonyTestRunner onRun end'); + } +} \ No newline at end of file diff --git a/ArkUIKit/StyledStringNDK/entry/src/ohosTest/module.json5 b/ArkUIKit/StyledStringNDK/entry/src/ohosTest/module.json5 index f6bdce994..24ed42cb9 100644 --- a/ArkUIKit/StyledStringNDK/entry/src/ohosTest/module.json5 +++ b/ArkUIKit/StyledStringNDK/entry/src/ohosTest/module.json5 @@ -17,8 +17,29 @@ "name": "entry_test", "type": "feature", "deviceTypes": [ - "default", - "tablet" + "default" + ], + "abilities": [ + { + "name": "TestAbility", + "srcEntry": "./ets/testability/TestAbility.ets", + "description": "$string:TestAbility_desc", + "icon": "$media:icon", + "label": "$string:TestAbility_label", + "exported": true, + "startWindowIcon": "$media:icon", + "startWindowBackground": "$color:start_window_background", + "skills": [ + { + "actions": [ + "action.system.home" + ], + "entities": [ + "entity.system.home" + ] + } + ] + } ], "deliveryWithInstall": true, "installationFree": false diff --git a/ArkUIKit/StyledStringNDK/entry/src/ohosTest/resources/base/element/color.json b/ArkUIKit/StyledStringNDK/entry/src/ohosTest/resources/base/element/color.json new file mode 100644 index 000000000..3c712962d --- /dev/null +++ b/ArkUIKit/StyledStringNDK/entry/src/ohosTest/resources/base/element/color.json @@ -0,0 +1,8 @@ +{ + "color": [ + { + "name": "start_window_background", + "value": "#FFFFFF" + } + ] +} \ No newline at end of file diff --git a/ArkUIKit/StyledStringNDK/entry/src/ohosTest/resources/base/element/string.json b/ArkUIKit/StyledStringNDK/entry/src/ohosTest/resources/base/element/string.json new file mode 100644 index 000000000..65d8fa5a7 --- /dev/null +++ b/ArkUIKit/StyledStringNDK/entry/src/ohosTest/resources/base/element/string.json @@ -0,0 +1,16 @@ +{ + "string": [ + { + "name": "module_test_desc", + "value": "test ability description" + }, + { + "name": "TestAbility_desc", + "value": "the test ability" + }, + { + "name": "TestAbility_label", + "value": "test label" + } + ] +} \ No newline at end of file diff --git a/ArkUIKit/StyledStringNDK/entry/src/ohosTest/resources/base/media/icon.png b/ArkUIKit/StyledStringNDK/entry/src/ohosTest/resources/base/media/icon.png new file mode 100644 index 0000000000000000000000000000000000000000..d1fc6539ef4b1dbea75ac9230a47c0b97757079f GIT binary patch literal 7536 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 .git/info/sparse-checkout -git remote add origin https://gitee.com/harmonyos_samples/guide-snippets.git +echo code/DocsSample/ArkUISample/TextAreaEventNDK > .git/info/sparse-checkout +git remote add origin https://gitee.com/openharmony/applications_app_samples.git git pull origin master ``` \ No newline at end of file diff --git a/ArkUIKit/TextAreaEventNDK/build-profile.json5 b/ArkUIKit/TextAreaEventNDK/build-profile.json5 index d4774ea1b..fd3e8fb5f 100644 --- a/ArkUIKit/TextAreaEventNDK/build-profile.json5 +++ b/ArkUIKit/TextAreaEventNDK/build-profile.json5 @@ -18,7 +18,9 @@ { "name": "default", "signingConfig": "default", + "compileSdkVersion": "6.0.0(20)", "compatibleSdkVersion": "6.0.0(20)", + "targetSdkVersion": "6.0.0(20)", "runtimeOS": "HarmonyOS", "buildOption": { "strictMode": { diff --git a/ArkUIKit/TextAreaEventNDK/entry/build-profile.json5 b/ArkUIKit/TextAreaEventNDK/entry/build-profile.json5 index cff3c16ef..a20094043 100644 --- a/ArkUIKit/TextAreaEventNDK/entry/build-profile.json5 +++ b/ArkUIKit/TextAreaEventNDK/entry/build-profile.json5 @@ -19,7 +19,10 @@ "path": "./src/main/cpp/CMakeLists.txt", "arguments": "", "cppFlags": "", - "abiFilters": ["arm64-v8a", "x86_64"] + "abiFilters": [ + "arm64-v8a", + "x86_64" + ] } }, "buildOptionSet": [ diff --git a/ArkUIKit/TextAreaEventNDK/entry/src/main/cpp/manager.cpp b/ArkUIKit/TextAreaEventNDK/entry/src/main/cpp/manager.cpp index d704d7769..4594bfd36 100644 --- a/ArkUIKit/TextAreaEventNDK/entry/src/main/cpp/manager.cpp +++ b/ArkUIKit/TextAreaEventNDK/entry/src/main/cpp/manager.cpp @@ -12,6 +12,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ +// [Start obtain_textarea_all] #include "manager.h" #include #include @@ -27,11 +28,11 @@ NodeManager &NodeManager::GetInstance() return instance; } -void NodeManager::SetContentHandle(ArkUI_NodeContentHandle contentHandle) { contentHandle_ = contentHandle; } +void NodeManager::SetXComponent(OH_NativeXComponent *xComponent) { xComponent_ = xComponent; } void NodeManager::CreateTextAreaNode() { - if (!contentHandle_) { + if (!xComponent_) { return; } ArkUI_NativeNodeAPI_1 *nodeApi = reinterpret_cast( @@ -44,20 +45,24 @@ void NodeManager::CreateTextAreaNode() ArkUI_AttributeItem widthItem = {.value = colWidth, .size = 1}; nodeApi->setAttribute(column, NODE_WIDTH, &widthItem); + // [Start obtain_create_textarea] ArkUI_NodeHandle text = nodeApi->createNode(ARKUI_NODE_TEXT); ArkUI_NumberValue textWidth[] = {{.f32 = 300}}; ArkUI_AttributeItem textWidthItem = {.value = textWidth, .size = 1}; nodeApi->setAttribute(text, NODE_WIDTH, &textWidthItem); + // [StartExclude obtain_create_textarea] ArkUI_NumberValue textHeight[] = {{.f32 = 100}}; ArkUI_AttributeItem textHeightItem = {.value = textHeight, .size = 1}; nodeApi->setAttribute(text, NODE_HEIGHT, &textHeightItem); nodeApi->addChild(column, text); + // [EndExclude obtain_create_textarea] ArkUI_NodeHandle selectionText = nodeApi->createNode(ARKUI_NODE_TEXT); ArkUI_NumberValue selectionTextWidth[] = {{.f32 = 300}}; ArkUI_AttributeItem selectionTextWidthItem = {.value = selectionTextWidth, .size = 1}; nodeApi->setAttribute(selectionText, NODE_WIDTH, &selectionTextWidthItem); + // [StartExclude obtain_create_textarea] nodeApi->addChild(column, selectionText); ArkUI_NodeHandle textArea = nodeApi->createNode(ARKUI_NODE_TEXT_AREA); ArkUI_NumberValue textAreaWidth[] = {{.f32 = 300}}; @@ -68,18 +73,21 @@ void NodeManager::CreateTextAreaNode() ArkUI_AttributeItem borderWidthItem = {.value = borderWidth, .size = 1}; nodeApi->setAttribute(textArea, NODE_BORDER_WIDTH, &borderWidthItem); + // [EndExclude obtain_create_textarea] const ArkUI_AttributeItem *attributeItem = nodeApi->getAttribute(textArea, NODE_UNIQUE_ID); auto id = attributeItem->value[0].i32; nodeApi->registerNodeEvent(textArea, NODE_TEXT_AREA_ON_CHANGE, id, text); nodeApi->registerNodeEvent(textArea, NODE_TEXT_AREA_ON_PASTE, id, text); nodeApi->registerNodeEvent(textArea, NODE_TEXT_AREA_ON_TEXT_SELECTION_CHANGE, id, selectionText); + // [End obtain_create_textarea] TextAreaNodeEventReceiver(nodeApi); nodeApi->addChild(column, textArea); - OH_ArkUI_NodeContent_AddNode(contentHandle_, column); + OH_NativeXComponent_AttachNativeRootNode(xComponent_, column); } void NodeManager::TextAreaNodeEventReceiver(ArkUI_NativeNodeAPI_1* nodeApi) { + // [Start obtain_textarea_NodeEventReceiver] nodeApi->registerNodeEventReceiver([](ArkUI_NodeEvent *event) { ArkUI_NodeEventType eventType = OH_ArkUI_NodeEvent_GetEventType(event); ArkUI_AttributeItem content; @@ -101,5 +109,7 @@ void NodeManager::TextAreaNodeEventReceiver(ArkUI_NativeNodeAPI_1* nodeApi) nodeApi->setAttribute(textNode, NODE_TEXT_CONTENT, &content); } }); + // [End obtain_textarea_NodeEventReceiver] } } // namespace NativeNode::Manager +// [End obtain_textarea_all] diff --git a/ArkUIKit/TextAreaEventNDK/entry/src/main/cpp/manager.h b/ArkUIKit/TextAreaEventNDK/entry/src/main/cpp/manager.h index d6c3b8258..1af1f0cb8 100644 --- a/ArkUIKit/TextAreaEventNDK/entry/src/main/cpp/manager.h +++ b/ArkUIKit/TextAreaEventNDK/entry/src/main/cpp/manager.h @@ -29,13 +29,15 @@ class NodeManager { public: ~NodeManager() = default; static NodeManager& GetInstance(); - void SetContentHandle(ArkUI_NodeContentHandle contentHandle); + void SetXComponent(OH_NativeXComponent* xComponent); + void CreateNativeNode(); void CreateTextAreaNode(); - + const EventCallback& GetCallback(int32_t id); private: NodeManager() = default; + void AddNodeEventCallback(int32_t id, EventCallback&& callback); void TextAreaNodeEventReceiver(ArkUI_NativeNodeAPI_1* nodeApi); - ArkUI_NodeContentHandle contentHandle_; + OH_NativeXComponent* xComponent_; std::unordered_map callbackMap_; }; } diff --git a/ArkUIKit/TextAreaEventNDK/entry/src/main/cpp/napi_init.cpp b/ArkUIKit/TextAreaEventNDK/entry/src/main/cpp/napi_init.cpp index 97b997cfa..2bbb60b80 100644 --- a/ArkUIKit/TextAreaEventNDK/entry/src/main/cpp/napi_init.cpp +++ b/ArkUIKit/TextAreaEventNDK/entry/src/main/cpp/napi_init.cpp @@ -13,24 +13,27 @@ * limitations under the License. */ #include "manager.h" -#include #include -#include #include - -static napi_value createNativeNode(napi_env env, napi_callback_info info) +static OH_NativeXComponent* GetXComponent(napi_env env, napi_value exports) { - size_t argc = 1; - napi_value args[1] = { nullptr }; - if (napi_get_cb_info(env, info, &argc, args, nullptr, nullptr) != napi_ok) { - OH_LOG_Print(LOG_APP, LOG_ERROR, 0xFF00, "TextAreaEventNDK", "CreateNativeNode napi_get_cb_info failed"); + if ((env == nullptr) || (exports == nullptr)) { + return nullptr; + } + napi_value exportInstance = nullptr; + if (napi_get_named_property(env, exports, OH_NATIVE_XCOMPONENT_OBJ, &exportInstance) != napi_ok) { + return nullptr; + } + OH_NativeXComponent* xComp = nullptr; + if (napi_unwrap(env, exportInstance, reinterpret_cast(&xComp)) != napi_ok) { return nullptr; } - // 获取NodeContent - ArkUI_NodeContentHandle contentHandle; - OH_ArkUI_GetNodeContentFromNapiValue(env, args[0], &contentHandle); - NativeNode::Manager::NodeManager::GetInstance().SetContentHandle(contentHandle); + return xComp; +} + +static napi_value createNativeNode(napi_env env, napi_callback_info info) +{ NativeNode::Manager::NodeManager::GetInstance().CreateTextAreaNode(); return nullptr; } @@ -42,6 +45,10 @@ static napi_value Init(napi_env env, napi_value exports) { "createNativeNode", nullptr, createNativeNode, nullptr, nullptr, nullptr, napi_default, nullptr } }; napi_define_properties(env, exports, sizeof(desc) / sizeof(desc[0]), desc); + auto xComponent = GetXComponent(env, exports); + if (xComponent) { + NativeNode::Manager::NodeManager::GetInstance().SetXComponent(xComponent); + } return exports; } EXTERN_C_END diff --git a/ArkUIKit/TextAreaEventNDK/entry/src/main/cpp/types/libentry/Index.d.ts b/ArkUIKit/TextAreaEventNDK/entry/src/main/cpp/types/libentry/Index.d.ts index da6cd3291..c09127fac 100644 --- a/ArkUIKit/TextAreaEventNDK/entry/src/main/cpp/types/libentry/Index.d.ts +++ b/ArkUIKit/TextAreaEventNDK/entry/src/main/cpp/types/libentry/Index.d.ts @@ -12,5 +12,4 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - -export const createNativeNode: (content: object) => void; \ No newline at end of file +export const createNativeNode: () => void; \ No newline at end of file diff --git a/ArkUIKit/TextAreaEventNDK/entry/src/main/ets/pages/Index.ets b/ArkUIKit/TextAreaEventNDK/entry/src/main/ets/pages/Index.ets index 9c6014f98..0893689d5 100644 --- a/ArkUIKit/TextAreaEventNDK/entry/src/main/ets/pages/Index.ets +++ b/ArkUIKit/TextAreaEventNDK/entry/src/main/ets/pages/Index.ets @@ -12,26 +12,25 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - import testNapi from 'libentry.so'; -import { NodeContent } from '@kit.ArkUI'; @Entry @Component struct Index { - private nodeContent: Content = new NodeContent(); build() { Row() { Column() { - ContentSlot(this.nodeContent) + XComponent({ + id: "xComponent", + type: XComponentType.NODE, + libraryname: "entry" + }).onAppear(()=> { + testNapi.createNativeNode(); + }) } .width('100%') } .height('100%') } - - aboutToAppear(): void { - testNapi.createNativeNode(this.nodeContent); - } } diff --git a/ArkUIKit/TextAreaEventNDK/entry/src/main/module.json5 b/ArkUIKit/TextAreaEventNDK/entry/src/main/module.json5 index 8b215df6b..e816d2f02 100644 --- a/ArkUIKit/TextAreaEventNDK/entry/src/main/module.json5 +++ b/ArkUIKit/TextAreaEventNDK/entry/src/main/module.json5 @@ -19,8 +19,7 @@ "description": "$string:module_desc", "mainElement": "EntryAbility", "deviceTypes": [ - "phone", - "tablet" + "default" ], "deliveryWithInstall": true, "installationFree": false, diff --git a/ArkUIKit/TextAreaEventNDK/entry/src/main/syscap.json b/ArkUIKit/TextAreaEventNDK/entry/src/main/syscap.json new file mode 100644 index 000000000..19b9dd01e --- /dev/null +++ b/ArkUIKit/TextAreaEventNDK/entry/src/main/syscap.json @@ -0,0 +1,12 @@ +{ + "devices": { + "general": ["default"], + "custom": [ + { + "xts": [ + "SystemCapability.Graphic.Graphic2D.NativeDrawing" + ] + } + ] + } +} \ No newline at end of file diff --git a/ArkUIKit/TextAreaEventNDK/entry/src/ohosTest/ets/test/Ability.test.ets b/ArkUIKit/TextAreaEventNDK/entry/src/ohosTest/ets/test/Ability.test.ets index 7f30942b8..b2da585ec 100644 --- a/ArkUIKit/TextAreaEventNDK/entry/src/ohosTest/ets/test/Ability.test.ets +++ b/ArkUIKit/TextAreaEventNDK/entry/src/ohosTest/ets/test/Ability.test.ets @@ -13,7 +13,8 @@ * limitations under the License. */ import { hilog } from '@kit.PerformanceAnalysisKit'; -import { describe, beforeAll, beforeEach, afterEach, afterAll, it, expect } from '@ohos/hypium'; +import testNapi from 'libentry.so'; +import { describe, beforeAll, beforeEach, afterEach, afterAll, it, expect, Level } from '@ohos/hypium'; export default function abilityTest() { describe('ActsAbilityTest', () => { @@ -36,14 +37,19 @@ export default function abilityTest() { // Presets a clear action, which is performed after all test cases of the test suite end. // This API supports only one parameter: clear action function. }) - it('assertContain', 0, () => { + + /** + * @tc.number testTextAreaEventNDK_001 + * @tc.name testTextAreaEventNDK_001 + * @tc.desc test testTextAreaEventNDK + * @tc.level: Level 1 + */ + it('testTextAreaEventNDK_001', Level.LEVEL1, async (done: Function) => { // Defines a test case. This API supports three parameters: test case name, filter parameter, and test case function. - hilog.info(0x0000, 'testTag', '%{public}s', 'it begin'); - let a = 'abc'; - let b = 'b'; - // Defines a variety of assertion methods, which are used to declare expected boolean conditions. - expect(a).assertContain(b); - expect(a).assertEqual(a); + hilog.info(0x0000, 'testTag', 'testTextAreaEventNDK_001 begin'); + testNapi.createNativeNode(); + hilog.info(0x0000, 'testTag', 'testTextAreaEventNDK_001 end'); + done(); }) }) } \ No newline at end of file diff --git a/ArkUIKit/TextAreaEventNDK/entry/src/ohosTest/ets/testability/TestAbility.ets b/ArkUIKit/TextAreaEventNDK/entry/src/ohosTest/ets/testability/TestAbility.ets new file mode 100644 index 000000000..6d510ed63 --- /dev/null +++ b/ArkUIKit/TextAreaEventNDK/entry/src/ohosTest/ets/testability/TestAbility.ets @@ -0,0 +1,66 @@ +/* + * 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 UIAbility from '@ohos.app.ability.UIAbility'; +import AbilityDelegatorRegistry from '@ohos.app.ability.abilityDelegatorRegistry'; +import hilog from '@ohos.hilog'; +import { Hypium } from '@ohos/hypium'; +import testsuite from '../test/List.test'; +import window from '@ohos.window'; +import Want from '@ohos.app.ability.Want' +import AbilityConstant from '@ohos.app.ability.AbilityConstant'; + +export default class TestAbility extends UIAbility { + onCreate(want: Want, launchParam: AbilityConstant.LaunchParam) { + hilog.info(0x0000, 'testTag', '%{public}s', 'TestAbility onCreate'); + hilog.info(0x0000, 'testTag', '%{public}s', 'want param:' + JSON.stringify(want) ?? ''); + hilog.info(0x0000, 'testTag', '%{public}s', 'launchParam:'+ JSON.stringify(launchParam) ?? ''); + let abilityDelegator: AbilityDelegatorRegistry.AbilityDelegator; + abilityDelegator = AbilityDelegatorRegistry.getAbilityDelegator(); + let abilityDelegatorArguments: AbilityDelegatorRegistry.AbilityDelegatorArgs; + abilityDelegatorArguments = AbilityDelegatorRegistry.getArguments(); + hilog.info(0x0000, 'testTag', '%{public}s', 'start run testcase!!!'); + Hypium.hypiumTest(abilityDelegator, abilityDelegatorArguments, testsuite); + } + + onDestroy() { + hilog.info(0x0000, 'testTag', '%{public}s', 'TestAbility onDestroy'); + } + + onWindowStageCreate(windowStage: window.WindowStage) { + hilog.info(0x0000, 'testTag', '%{public}s', 'TestAbility onWindowStageCreate'); + windowStage.loadContent('testability/pages/Index', (err, data) => { + if (err.code) { + hilog.error(0x0000, 'testTag', 'Failed to load the content. Cause: %{public}s', + JSON.stringify(err) ?? ''); + return; + } + hilog.info(0x0000, 'testTag', 'Succeeded in loading the content. Data: %{public}s', + JSON.stringify(data) ?? ''); + }); + } + + onWindowStageDestroy() { + hilog.info(0x0000, 'testTag', '%{public}s', 'TestAbility onWindowStageDestroy'); + } + + onForeground() { + hilog.info(0x0000, 'testTag', '%{public}s', 'TestAbility onForeground'); + } + + onBackground() { + hilog.info(0x0000, 'testTag', '%{public}s', 'TestAbility onBackground'); + } +} \ No newline at end of file diff --git a/ArkUIKit/TextAreaEventNDK/entry/src/ohosTest/ets/testability/pages/Index.ets b/ArkUIKit/TextAreaEventNDK/entry/src/ohosTest/ets/testability/pages/Index.ets new file mode 100644 index 000000000..d61532abc --- /dev/null +++ b/ArkUIKit/TextAreaEventNDK/entry/src/ohosTest/ets/testability/pages/Index.ets @@ -0,0 +1,48 @@ +/* + * 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 hilog from '@ohos.hilog'; + +@Entry +@Component +struct Index { + aboutToAppear() { + hilog.info(0x0000, 'testTag', '%{public}s', 'TestAbility index aboutToAppear'); + } + @State message: string = 'Hello World' + build() { + Row() { + Column() { + Text(this.message) + .fontSize(50) + .fontWeight(FontWeight.Bold); + Button() { + Text('next page') + .fontSize(20) + .fontWeight(FontWeight.Bold); + }.type(ButtonType.Capsule) + .margin({ + top: 20 + }) + .backgroundColor('#0D9FFB') + .width('35%') + .height('5%') + .onClick(()=>{ + }) + } + .width('100%'); + } + .height('100%'); + } + } \ No newline at end of file diff --git a/ArkUIKit/TextAreaEventNDK/entry/src/ohosTest/ets/testrunner/OpenHarmonyTestRunner.ts b/ArkUIKit/TextAreaEventNDK/entry/src/ohosTest/ets/testrunner/OpenHarmonyTestRunner.ts new file mode 100644 index 000000000..1493be8f3 --- /dev/null +++ b/ArkUIKit/TextAreaEventNDK/entry/src/ohosTest/ets/testrunner/OpenHarmonyTestRunner.ts @@ -0,0 +1,64 @@ +/* + * 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 hilog from '@ohos.hilog'; +import TestRunner from '@ohos.application.testRunner'; +import AbilityDelegatorRegistry from '@ohos.app.ability.abilityDelegatorRegistry'; + +var abilityDelegator = undefined; +var abilityDelegatorArguments = undefined; + +async function onAbilityCreateCallback() { + hilog.info(0x0000, 'testTag', '%{public}s', 'onAbilityCreateCallback'); +} + +async function addAbilityMonitorCallback(err: any) { + hilog.info(0x0000, 'testTag', 'addAbilityMonitorCallback : %{public}s', JSON.stringify(err) ?? ''); +} + +export default class OpenHarmonyTestRunner implements TestRunner { + constructor() { + } + + onPrepare() { + hilog.info(0x0000, 'testTag', '%{public}s', 'OpenHarmonyTestRunner OnPrepare '); + } + + async onRun() { + hilog.info(0x0000, 'testTag', '%{public}s', 'OpenHarmonyTestRunner onRun run'); + abilityDelegatorArguments = AbilityDelegatorRegistry.getArguments(); + abilityDelegator = AbilityDelegatorRegistry.getAbilityDelegator(); + var testAbilityName = abilityDelegatorArguments.bundleName + '.TestAbility'; + let lMonitor = { + abilityName: testAbilityName, + onAbilityCreate: onAbilityCreateCallback, + }; + abilityDelegator.addAbilityMonitor(lMonitor, addAbilityMonitorCallback); + var cmd = 'aa start -d 0 -a TestAbility' + ' -b ' + abilityDelegatorArguments.bundleName; + var debug = abilityDelegatorArguments.parameters['-D']; + if (debug == 'true') + { + cmd += ' -D' + } + hilog.info(0x0000, 'testTag', 'cmd : %{public}s', cmd); + abilityDelegator.executeShellCommand(cmd, + (err: any, d: any) => { + hilog.info(0x0000, 'testTag', 'executeShellCommand : err : %{public}s', JSON.stringify(err) ?? ''); + hilog.info(0x0000, 'testTag', 'executeShellCommand : data : %{public}s', d.stdResult ?? ''); + hilog.info(0x0000, 'testTag', 'executeShellCommand : data : %{public}s', d.exitCode ?? ''); + }); + hilog.info(0x0000, 'testTag', '%{public}s', 'OpenHarmonyTestRunner onRun end'); + } +} \ No newline at end of file diff --git a/ArkUIKit/TextAreaEventNDK/entry/src/ohosTest/module.json5 b/ArkUIKit/TextAreaEventNDK/entry/src/ohosTest/module.json5 index f6bdce994..24ed42cb9 100644 --- a/ArkUIKit/TextAreaEventNDK/entry/src/ohosTest/module.json5 +++ b/ArkUIKit/TextAreaEventNDK/entry/src/ohosTest/module.json5 @@ -17,8 +17,29 @@ "name": "entry_test", "type": "feature", "deviceTypes": [ - "default", - "tablet" + "default" + ], + "abilities": [ + { + "name": "TestAbility", + "srcEntry": "./ets/testability/TestAbility.ets", + "description": "$string:TestAbility_desc", + "icon": "$media:icon", + "label": "$string:TestAbility_label", + "exported": true, + "startWindowIcon": "$media:icon", + "startWindowBackground": "$color:start_window_background", + "skills": [ + { + "actions": [ + "action.system.home" + ], + "entities": [ + "entity.system.home" + ] + } + ] + } ], "deliveryWithInstall": true, "installationFree": false diff --git a/ArkUIKit/TextAreaEventNDK/entry/src/ohosTest/resources/base/element/color.json b/ArkUIKit/TextAreaEventNDK/entry/src/ohosTest/resources/base/element/color.json new file mode 100644 index 000000000..3c712962d --- /dev/null +++ b/ArkUIKit/TextAreaEventNDK/entry/src/ohosTest/resources/base/element/color.json @@ -0,0 +1,8 @@ +{ + "color": [ + { + "name": "start_window_background", + "value": "#FFFFFF" + } + ] +} \ No newline at end of file diff --git a/ArkUIKit/TextAreaEventNDK/entry/src/ohosTest/resources/base/element/string.json b/ArkUIKit/TextAreaEventNDK/entry/src/ohosTest/resources/base/element/string.json new file mode 100644 index 000000000..65d8fa5a7 --- /dev/null +++ b/ArkUIKit/TextAreaEventNDK/entry/src/ohosTest/resources/base/element/string.json @@ -0,0 +1,16 @@ +{ + "string": [ + { + "name": "module_test_desc", + "value": "test ability description" + }, + { + "name": "TestAbility_desc", + "value": "the test ability" + }, + { + "name": "TestAbility_label", + "value": "test label" + } + ] +} \ No newline at end of file diff --git a/ArkUIKit/TextAreaEventNDK/entry/src/ohosTest/resources/base/media/icon.png b/ArkUIKit/TextAreaEventNDK/entry/src/ohosTest/resources/base/media/icon.png new file mode 100644 index 0000000000000000000000000000000000000000..d1fc6539ef4b1dbea75ac9230a47c0b97757079f GIT binary patch literal 7536 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