diff --git a/ArkUIKit/ChooseComponent/README_zh.md b/ArkUIKit/ChooseComponent/README_zh.md index e1a335f5c5cadf23acc0c926cf8d572fac691729..07f29630f3545baf30ef571a8e81f36ef3edf5b6 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 0000000000000000000000000000000000000000..565f6bd333648a7c7a25089127ddb5fc99c9f9df --- /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 0000000000000000000000000000000000000000..cedb508b6cf54e0d1b50a5a498fdd3c8027a8bbd --- /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 dfbc79820732da7a70944289750bfd113e8b5222..da855939af7092be52ba2bdb3ac6572bf5dbd14a 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 d903c8599d0ab0c0d8e93fa44da34b2411ddc72d..c35769b9bebf59c5a92a8938f5f86ebb472c1734 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 0000000000000000000000000000000000000000..927e3ce4e171ada83773701b1e1b8f10ff54e288 --- /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 f37f6f3bd71096b1f6fd86e9612037192180f1cb..a51d7b9318a1831d2713e19059b254b21b8523da 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 489944cc97e22d3f1d81c1e1ce544bc4c10e186c..7d397b7d7d9600767ecf3853e197d6d7a0beac17 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 7de4f7438880b75133e55ce1f1e5bf6ce26bfe0a..682837839545949e75eec483fc82e8df5bbfb32c 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 40ebdd1f0002615313b7731118edeec704329eb4..05d6f070eebf1d9d0d068a09cab8e4514e622cb7 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 95d1ceb49b3fcfc428d43e99852853768433ed2e..ac419f406dae2d55a44017a4f27189100db230a2 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 0000000000000000000000000000000000000000..d2ff20141ceed86d87c0ea5d99481973005bab2b --- /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 fe49c9e7249fb1354c5d050d61cad272ccf3e855..71f6b5827b5a76539f52cafdee63c5df2ce243f9 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 0000000000000000000000000000000000000000..904a0d4000a9f083b1f5ef713dcf951dc3f527e2 --- /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 25b5083933446b390161842431f415919eb1ec32..70d3ac1125d3b5f67ccd474f32bd517c0133b56c 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 0000000000000000000000000000000000000000..02ba747a251ee8c94e2c7a25d3966cc72f81a2a0 --- /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 0000000000000000000000000000000000000000..6d6ff0907e1c992b9fe5ba98169af96b5bb177e5 --- /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 60c4eca1dd3914a578dcbbb9ec9768bae8f57fa4..66401c68f56c1a86447a1c8fe05a8a8ce30503ff 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 0000000000000000000000000000000000000000..46894959596f8dc521269fec535d1c47efd9f42f --- /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 0000000000000000000000000000000000000000..427885ab22a2574f6e665df6b8fd82ddf4b807af --- /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 0000000000000000000000000000000000000000..75495218cd52b4c656ffae57612ce8650dca23b1 --- /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 0000000000000000000000000000000000000000..fc7be7346cbe10dd60be980f6595e297ba3d73d4 --- /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 0000000000000000000000000000000000000000..1854516cd309eac978a4ab09ed131dc7e6f5a66e --- /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 f2d21b0f986528004cdc7809ffab842e841df639..47ad82e052f05716f7dfc924f7c99379e2b67ce0 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 0000000000000000000000000000000000000000..62bc6d2c2f1f3d33015d6af125536466e7f54e49 --- /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 0000000000000000000000000000000000000000..deefe611f5a6a70c2a51c65c9267100b7fece383 --- /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 0000000000000000000000000000000000000000..c9e5db160842b3726243f55f360651551aff6e44 --- /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 0000000000000000000000000000000000000000..1a647eca3e88d622dd86bd722235af2146f31126 --- /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 0000000000000000000000000000000000000000..be6df1a70d507f9ac3f95ecfb457aac9ec071f22 --- /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 8f2f6a43aeaa63e32dffd26f8b1b59d2f102cf5d..2c81a26d7b271366701bad1d7256808d0a9a52c6 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 0000000000000000000000000000000000000000..6b4b3d039d6f0522a8f8bd572acbae2a7df1a062 --- /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 0000000000000000000000000000000000000000..88201726d58fb7b01ea96d9f41203dfaee7e62c2 --- /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 edc3baea8251f17286cc909df2d52b26188d1a94..536beb3dc71bfe0342b51f19b560780940c19b54 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 825c1f7ed93b7d661c5f189dd8687986f9fd4156..248287b2c5457cac77993ffb9928bfa33a74c518 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 c12418f2f7f837b719ee5397d8abf7f582edab93..3d935d6bd651f80b444b9cb7f2a7322615a24ab0 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 0000000000000000000000000000000000000000..e1ecc228cd6d41f7b1348e8c741e7d114fff975a --- /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 28caa25d66d07d063b681ea5dffbd8df5398b73b..38ba9a08915f19750119dd65660bead279745978 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 b8e1c07033025062a98b9ea0be8bee1349e05688..a87d0fbfb7227198a4e614b6f63f03c31cc3dfc4 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 73da39ba000a77326b1c0093dbd8493e1755f7d8..b341e0fecfa90b92d003b57566b5af05f5996d38 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 165285fbc1f7f2aba0988c88d2e2f3362c770aa0..7443d8602e498f5d03d4268230572481201b7f1d 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 7f0393367b4ae9594a1ea01c6ad12f8a11ff8c59..f7c732c4fb95c350295032e39a257cc9dd76fe6e 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 0000000000000000000000000000000000000000..cf4965e4e6587a574b9ca6e3c82bfbd863f21420 --- /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 0000000000000000000000000000000000000000..3cea4486ab5f17e7705ff3569e71a8fa9266c151 --- /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 0000000000000000000000000000000000000000..da7d036d99b18d4515d1dcb257ec19624c9c640d --- /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 3d1b31b014ae9c8d588d06fd8b0f51aa5491e64b..b1e70b807d6226f8f17fb38297a4dcf560a4debb 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 0000000000000000000000000000000000000000..02e7e7828dc21b6a11952426332176bc7fa3cd15 --- /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 0000000000000000000000000000000000000000..274209275e03304ea803fb74ce98dba05659ecc7 --- /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 0000000000000000000000000000000000000000..001eccb027094bcef8529abc43ab6a99aaba4144 --- /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 114fc049e35955c71c3d11ac88db751f19cf9efb..c27b08aa9b9c6e70519ea802d0041ddd8dd59371 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 c533a4f49056d7da52b8086304a12e3c1a6a0f5c..b2ac7eccce33ea284fcc977516ea6802c66f1fc5 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 6d9896b990e8c83e24a9eeb00451ef53155588d4..e375ceebb6e29afe6ee3176bfd0d68956aed28af 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 2ef0e99f872fd0f9298ce1a88b6978aeff8f87a7..6335db86d90a5af770ae4f4823b62ee66c95a1bf 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 0000000000000000000000000000000000000000..c8bcd9c495cfcc7831ee784ac42278e720c6ace0 --- /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 0000000000000000000000000000000000000000..b1c1679d0d50e54122bd748964caa6e17a2a9836 --- /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 a9fc84f9844ebac1f5f2c79e7ef5b8336be22a42..d8a8da864f4ea7b6f0fd2d6c8897d102b4ee25d2 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 32426e33258fcf5b3976588d19b7bd58eaac91de..da2b18db1684ba13deb8793ecea238f1899e531d 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 0000000000000000000000000000000000000000..a354498679397932526a6c3bc36b8e36a7b77e57 --- /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 4ff872db5c2306411b3e34fabc9154d8771fc316..df50c95e2765adbff7a935798637b0e688eb9f30 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 f09d09a7bc661e848418aaf40ba4506a86649bb1..21cf7f8339830f58301037e174b15016ca6fe076 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 c3c2d7c5c81bf829354a2e82032e905c51304d9a..b145c062a5f67d03098410f8764eb3bcb37aba62 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 33b442171611eb7176abfd9ac7a69795f606b15f..2ecac78f66d4db74139182ee99887488338204e4 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 d5259895a9141461ee24365cd0cb1b2ed184862e..3e38b74f8d3cb2d8fe1da56df6764cb700b9234a 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 3d739bce6f4114150b415adb0cef32e93643f243..b93057ead6dd7b4e64fcfe52a6bc0ab00f5e77af 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 0000000000000000000000000000000000000000..59e2b4921cf40f7659d9ced2bd346d29458c3bdc --- /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 0000000000000000000000000000000000000000..811c571c1dae73bfc6ba3970eae25102a889c7ab --- /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 c76e7f37b12809475751a4d1b5de91b5208bc5fb..959af3943b32453e6ca59b0898ddaaf9742fd82d 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 0000000000000000000000000000000000000000..d2ff20141ceed86d87c0ea5d99481973005bab2b --- /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 0000000000000000000000000000000000000000..296d2b9a29a6cd7ce2ef35fdf102627e096e7f34 --- /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 0000000000000000000000000000000000000000..3b57591431fa00901f16b8fd617cbdbe3b7ca535 --- /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 Binary files /dev/null and b/ArkUIKit/InterAction/AppScope/resources/base/media/background.png differ diff --git a/ArkUIKit/InterAction/AppScope/resources/base/media/foreground.png b/ArkUIKit/InterAction/AppScope/resources/base/media/foreground.png new file mode 100644 index 0000000000000000000000000000000000000000..eb9427585b36d14b12477435b6419d1f07b3e0bb Binary files /dev/null and b/ArkUIKit/InterAction/AppScope/resources/base/media/foreground.png differ 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 0000000000000000000000000000000000000000..fb49920440fb4d246c82f9ada275e26123a2136a --- /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 0000000000000000000000000000000000000000..149129fa1bcab5e3d6d40d30e8fb8404bebb48e1 --- /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 0000000000000000000000000000000000000000..be9d10f8e052670ae3c81423b85d6874fab214f8 --- /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 0000000000000000000000000000000000000000..5c4682f8164874ec7e9cb8f99ff8b3228ffbc126 --- /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 0000000000000000000000000000000000000000..e2713a2779c5a3e0eb879efe6115455592caeea5 --- /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 0000000000000000000000000000000000000000..9016faf39f8a65cf648bae246a53575510fe8b9f --- /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 0000000000000000000000000000000000000000..cfa8a00f74f409d9647f55cdf270ab6aec69fe41 --- /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 0000000000000000000000000000000000000000..272efb6ca3f240859091bbbfc7c5802d52793b0b --- /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 0000000000000000000000000000000000000000..10cda399b0aec3099b257299a57d284393e4e55a --- /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 0000000000000000000000000000000000000000..723a394265ee2e6bf6d895e9503c4b2d8e49207a --- /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 0000000000000000000000000000000000000000..081b700cacec6def24d204fbc37ab93985f7b4ec --- /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 0000000000000000000000000000000000000000..4ce6449f0e91914e73d4502c9f2e8e9a395ea4b1 --- /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 0000000000000000000000000000000000000000..19519ba179e820e3a2ae17e1f3b5458d4411354b --- /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 0000000000000000000000000000000000000000..4f169061084db608fc655c5abd74977e3dbb204b --- /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 0000000000000000000000000000000000000000..7a14b92c1636aa4dcd7571dfe4d6abd7938afa0d --- /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 0000000000000000000000000000000000000000..f84f0676c116eaee7032a5fae7d877a6beac4880 --- /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 0000000000000000000000000000000000000000..91d358f36761f2c4ad78dc249d11ec0dffa2454e --- /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 0000000000000000000000000000000000000000..bc898e3814bfd5daa92d4c7e2a3711402675d04b --- /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 0000000000000000000000000000000000000000..8323e35a09da3ce2d71b619c8e703d0e32cbe784 --- /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 0000000000000000000000000000000000000000..02c5c6b987280c6731d3e40af7c56c416176a3af --- /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 0000000000000000000000000000000000000000..8decf179fc93770b9ac021d6fdad6c554b48ee03 --- /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 0000000000000000000000000000000000000000..afc7d6c79c740d36b99ac4ea79f92494d9d172f1 --- /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 0000000000000000000000000000000000000000..148bda7b177e62a943518017318a44defe75a117 --- /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 0000000000000000000000000000000000000000..a7d85c001dd9b0615e3773ddd58896e3142052df --- /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 0000000000000000000000000000000000000000..44e30abf324bffa0b0c832125d835c1de2cf9bc9 --- /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 0000000000000000000000000000000000000000..3c712962da3c2751c2b9ddb53559afcbd2b54a02 --- /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 0000000000000000000000000000000000000000..33ea22304f9b1485b5f22d811023701b5d4e35b6 --- /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 0000000000000000000000000000000000000000..4953ba3fa63e63daf1880b72eeaf634e2224afdd --- /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 Binary files /dev/null and b/ArkUIKit/InterAction/entry/src/main/resources/base/media/background.png differ diff --git a/ArkUIKit/InterAction/entry/src/main/resources/base/media/foreground.png b/ArkUIKit/InterAction/entry/src/main/resources/base/media/foreground.png new file mode 100644 index 0000000000000000000000000000000000000000..97014d3e10e5ff511409c378cd4255713aecd85f Binary files /dev/null and b/ArkUIKit/InterAction/entry/src/main/resources/base/media/foreground.png differ diff --git a/ArkUIKit/InterAction/entry/src/main/resources/base/media/layered_image.json b/ArkUIKit/InterAction/entry/src/main/resources/base/media/layered_image.json new file mode 100644 index 0000000000000000000000000000000000000000..fb49920440fb4d246c82f9ada275e26123a2136a --- /dev/null +++ b/ArkUIKit/InterAction/entry/src/main/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/entry/src/main/resources/base/media/startIcon.png b/ArkUIKit/InterAction/entry/src/main/resources/base/media/startIcon.png new file mode 100644 index 0000000000000000000000000000000000000000..205ad8b5a8a42e8762fbe4899b8e5e31ce822b8b Binary files /dev/null and b/ArkUIKit/InterAction/entry/src/main/resources/base/media/startIcon.png differ 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 0000000000000000000000000000000000000000..78f40ae7c494d71e2482278f359ec790ca73471a --- /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 0000000000000000000000000000000000000000..9ebaca780ffbedd74adc283daa2f1a9966aa3130 --- /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 0000000000000000000000000000000000000000..79b11c2747aec33e710fd3a7b2b3c94dd9965499 --- /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 0000000000000000000000000000000000000000..d14edde4277db282075a6639d65e40ddbbf0f2a2 --- /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 0000000000000000000000000000000000000000..323d1d611fecf4ecb751976e3a71500b3712a445 --- /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 0000000000000000000000000000000000000000..0f8ce9a2c012f8fe36114cef65216ef0b6254f41 --- /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 0000000000000000000000000000000000000000..91eb144991b86ce9b4c0f3057cd539857453f893 --- /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 0000000000000000000000000000000000000000..559689169845e1d4510330d1b3316bd4443f9129 --- /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 0000000000000000000000000000000000000000..0c08292a56e2a5c90c7188b7319fe974c04ebb0a --- /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 0000000000000000000000000000000000000000..f1186b1f53c3a70930921c5dbd1417332bec56c9 --- /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 0000000000000000000000000000000000000000..7fc57c77dbf76d8df08a2b802a55b948e3fcf968 --- /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 0000000000000000000000000000000000000000..3b057578a1bb4d591ee53054e39ab0154fc2e43a --- /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 0000000000000000000000000000000000000000..e3340f07e45ddc5dcadbb87012668555def2e6e0 --- /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 0000000000000000000000000000000000000000..69cb43cba3addcee1840403c67405134a2a9102c --- /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 0000000000000000000000000000000000000000..9311d7b4f638ff2dab586c1c4f6a1f566a8022de --- /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 Binary files /dev/null and b/ArkUIKit/InterAction/screenshots/device/image1.png differ diff --git a/ArkUIKit/InterAction/screenshots/device/image2.png b/ArkUIKit/InterAction/screenshots/device/image2.png new file mode 100644 index 0000000000000000000000000000000000000000..4c42d8b52e98583e4fbdb3e154111b64c9e64a35 Binary files /dev/null and b/ArkUIKit/InterAction/screenshots/device/image2.png differ diff --git a/ArkUIKit/InterAction/screenshots/device/image3.png b/ArkUIKit/InterAction/screenshots/device/image3.png new file mode 100644 index 0000000000000000000000000000000000000000..e78bd702be134a4d160027265d36b8d2f245d97a Binary files /dev/null and b/ArkUIKit/InterAction/screenshots/device/image3.png differ diff --git a/ArkUIKit/StyledStringNDK/README.md b/ArkUIKit/StyledStringNDK/README.md index 041551c62ba7d62271332313678678076ae0b5e6..a6b659e658784130ef9dbd189c8808fe1ae5fa2d 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 d4774ea1bd3391ce237ba9dcefe45f7061f99929..fd3e8fb5f5a10144a551109fc7d8f39b5f1e896c 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 9b5904523a7e5027acf6469ed9bb91003daf0237..a20094043a5b912b06e6fca193486f1fbaf0aafb 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 e281e0537b4a68b48b5820f242b35ea450db2c4f..16e42cb8d3eee2d2f7cde0883109e0edb51fb740 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 40d7565e58b7363d5d78d39301b6e699bb56f5e6..55b98a698bbe197db182c77b76f89e18e188ef28 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 8de3f3d6c4047f660641e603fe3dc3375cb99f61..0ef82312dac42685be4726c2b45e6abcd9f3ef84 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 da6cd329155de245079074d62cd65bdb08919a65..c09127fac743a5190aedf27d6e07056b20076bbd 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 4193211d18d31821f4c1a9a5e62a1faa0d462258..073f244e87c658da43efdecb3f509569af441c95 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 8b215df6b713ccad4e26b68cf4b5a491f71f90df..e816d2f02e6f81182f832e4b43cb21afe311efcf 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 0000000000000000000000000000000000000000..19b9dd01ee502b28d0496336f3bc9c2ab9469d77 --- /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 7f30942b81554a399e89aa253c7089eca4f8d8d1..153a6b2f73e5f397ccb64aaf6682e8036e1a5f7d 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 0000000000000000000000000000000000000000..66d72d2a361db81631c160b21e02019db25be951 --- /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 0000000000000000000000000000000000000000..073f244e87c658da43efdecb3f509569af441c95 --- /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 0000000000000000000000000000000000000000..1493be8f35b1939ad92b2b72836fa4e2aa86c24c --- /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 f6bdce9946cb02c0385e5a8836c133c93945013d..24ed42cb9db5fe44159ec83aeaddf5088d5c245f 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 0000000000000000000000000000000000000000..3c712962da3c2751c2b9ddb53559afcbd2b54a02 --- /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 0000000000000000000000000000000000000000..65d8fa5a7cf54aa3943dcd0214f58d1771bc1f6c --- /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 Binary files /dev/null and b/ArkUIKit/StyledStringNDK/entry/src/ohosTest/resources/base/media/icon.png differ diff --git a/ArkUIKit/StyledStringNDK/entry/src/ohosTest/resources/base/profile/test_pages.json b/ArkUIKit/StyledStringNDK/entry/src/ohosTest/resources/base/profile/test_pages.json new file mode 100644 index 0000000000000000000000000000000000000000..b7e7343cacb32ce982a45e76daad86e435e054fe --- /dev/null +++ b/ArkUIKit/StyledStringNDK/entry/src/ohosTest/resources/base/profile/test_pages.json @@ -0,0 +1,5 @@ +{ + "src": [ + "testability/pages/Index" + ] +} diff --git a/ArkUIKit/StyledStringNDK/entry/src/ohosTest/syscap.json b/ArkUIKit/StyledStringNDK/entry/src/ohosTest/syscap.json new file mode 100644 index 0000000000000000000000000000000000000000..19b9dd01ee502b28d0496336f3bc9c2ab9469d77 --- /dev/null +++ b/ArkUIKit/StyledStringNDK/entry/src/ohosTest/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/oh-package.json5 b/ArkUIKit/StyledStringNDK/oh-package.json5 index 4ffb5cd325f0fe70ac35599129f740cf059729d6..38abfd099681aeb547cf83a4966111dd5f4f6d13 100644 --- a/ArkUIKit/StyledStringNDK/oh-package.json5 +++ b/ArkUIKit/StyledStringNDK/oh-package.json5 @@ -18,6 +18,7 @@ "dependencies": { }, "devDependencies": { - "@ohos/hypium": "1.0.21" + "@ohos/hypium": "1.0.21", + "@ohos/hamock": "1.0.0" } } diff --git a/ArkUIKit/TextAreaEventNDK/README.md b/ArkUIKit/TextAreaEventNDK/README.md index f5212c87535ddf741b789ab3868b37abc1ac037e..6e4368f0471e5b9104ce10f18814de36b5274209 100644 --- a/ArkUIKit/TextAreaEventNDK/README.md +++ b/ArkUIKit/TextAreaEventNDK/README.md @@ -53,13 +53,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日)编译运行 ## 下载 @@ -68,7 +66,7 @@ entry/src/main/ ``` git init git config core.sparsecheckout true -echo ArkUIKit/TextAreaEventNDK > .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 d4774ea1bd3391ce237ba9dcefe45f7061f99929..fd3e8fb5f5a10144a551109fc7d8f39b5f1e896c 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 cff3c16ef337d5ed6b207c7e28be6aad4b0dfeeb..a20094043a5b912b06e6fca193486f1fbaf0aafb 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 d704d77694e92bcc8274d209af18cecf6ebb7b77..4594bfd3647fccb535a5a2d988931e6422b29148 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 d6c3b8258a83ecd21b4897aa17b77b3eaf327024..1af1f0cb81456b4e0695b8e36cade55eba1c4963 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 97b997cfa57bb0cf6e26af4b064c4a2da7bee34c..2bbb60b807299294a563c4fb81af59bd9ac6aec4 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 da6cd329155de245079074d62cd65bdb08919a65..c09127fac743a5190aedf27d6e07056b20076bbd 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 9c6014f988ee166eb8b3bf64d20564e5622d3714..0893689d542f8d549d9dde9dda9599da0c831dcd 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 8b215df6b713ccad4e26b68cf4b5a491f71f90df..e816d2f02e6f81182f832e4b43cb21afe311efcf 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 0000000000000000000000000000000000000000..19b9dd01ee502b28d0496336f3bc9c2ab9469d77 --- /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 7f30942b81554a399e89aa253c7089eca4f8d8d1..b2da585ec6f52649941635e0ef1c867b62b86073 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 0000000000000000000000000000000000000000..6d510ed63d225ea9c937d427b52d6e72d07b0b99 --- /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 0000000000000000000000000000000000000000..d61532abc93465ea94784cbd50d1988d6157507a --- /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 0000000000000000000000000000000000000000..1493be8f35b1939ad92b2b72836fa4e2aa86c24c --- /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 f6bdce9946cb02c0385e5a8836c133c93945013d..24ed42cb9db5fe44159ec83aeaddf5088d5c245f 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 0000000000000000000000000000000000000000..3c712962da3c2751c2b9ddb53559afcbd2b54a02 --- /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 0000000000000000000000000000000000000000..65d8fa5a7cf54aa3943dcd0214f58d1771bc1f6c --- /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 Binary files /dev/null and b/ArkUIKit/TextAreaEventNDK/entry/src/ohosTest/resources/base/media/icon.png differ diff --git a/ArkUIKit/TextAreaEventNDK/entry/src/ohosTest/resources/base/profile/test_pages.json b/ArkUIKit/TextAreaEventNDK/entry/src/ohosTest/resources/base/profile/test_pages.json new file mode 100644 index 0000000000000000000000000000000000000000..b7e7343cacb32ce982a45e76daad86e435e054fe --- /dev/null +++ b/ArkUIKit/TextAreaEventNDK/entry/src/ohosTest/resources/base/profile/test_pages.json @@ -0,0 +1,5 @@ +{ + "src": [ + "testability/pages/Index" + ] +} diff --git a/ArkUIKit/TextAreaEventNDK/entry/src/ohosTest/syscap.json b/ArkUIKit/TextAreaEventNDK/entry/src/ohosTest/syscap.json new file mode 100644 index 0000000000000000000000000000000000000000..19b9dd01ee502b28d0496336f3bc9c2ab9469d77 --- /dev/null +++ b/ArkUIKit/TextAreaEventNDK/entry/src/ohosTest/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/oh-package.json5 b/ArkUIKit/TextAreaEventNDK/oh-package.json5 index 4ffb5cd325f0fe70ac35599129f740cf059729d6..38abfd099681aeb547cf83a4966111dd5f4f6d13 100644 --- a/ArkUIKit/TextAreaEventNDK/oh-package.json5 +++ b/ArkUIKit/TextAreaEventNDK/oh-package.json5 @@ -18,6 +18,7 @@ "dependencies": { }, "devDependencies": { - "@ohos/hypium": "1.0.21" + "@ohos/hypium": "1.0.21", + "@ohos/hamock": "1.0.0" } }