diff --git a/ArkUIKit/Animation/.gitignore b/ArkUIKit/Animation/.gitignore new file mode 100644 index 0000000000000000000000000000000000000000..d2ff20141ceed86d87c0ea5d99481973005bab2b --- /dev/null +++ b/ArkUIKit/Animation/.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/Animation/AppScope/app.json5 b/ArkUIKit/Animation/AppScope/app.json5 new file mode 100644 index 0000000000000000000000000000000000000000..1e01400f30809cb5d43a42816db5eaf8d22ca7b6 --- /dev/null +++ b/ArkUIKit/Animation/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.samples.animation", + "vendor": "example", + "versionCode": 1000000, + "versionName": "1.0.0", + "icon": "$media:layered_image", + "label": "$string:app_name" + } +} diff --git a/ArkUIKit/Animation/AppScope/resources/base/element/string.json b/ArkUIKit/Animation/AppScope/resources/base/element/string.json new file mode 100644 index 0000000000000000000000000000000000000000..b86e4d568762b2d514c1bf734000d12e6a04e9d1 --- /dev/null +++ b/ArkUIKit/Animation/AppScope/resources/base/element/string.json @@ -0,0 +1,8 @@ +{ + "string": [ + { + "name": "app_name", + "value": "animation" + } + ] +} diff --git a/ArkUIKit/Animation/AppScope/resources/base/media/background.png b/ArkUIKit/Animation/AppScope/resources/base/media/background.png new file mode 100644 index 0000000000000000000000000000000000000000..923f2b3f27e915d6871871deea0420eb45ce102f Binary files /dev/null and b/ArkUIKit/Animation/AppScope/resources/base/media/background.png differ diff --git a/ArkUIKit/Animation/AppScope/resources/base/media/foreground.png b/ArkUIKit/Animation/AppScope/resources/base/media/foreground.png new file mode 100644 index 0000000000000000000000000000000000000000..97014d3e10e5ff511409c378cd4255713aecd85f Binary files /dev/null and b/ArkUIKit/Animation/AppScope/resources/base/media/foreground.png differ diff --git a/ArkUIKit/Animation/AppScope/resources/base/media/layered_image.json b/ArkUIKit/Animation/AppScope/resources/base/media/layered_image.json new file mode 100644 index 0000000000000000000000000000000000000000..fb49920440fb4d246c82f9ada275e26123a2136a --- /dev/null +++ b/ArkUIKit/Animation/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/Animation/README_zh.md b/ArkUIKit/Animation/README_zh.md new file mode 100644 index 0000000000000000000000000000000000000000..04aad6061b8a533eaa6857a87cbe1be6ecec93d9 --- /dev/null +++ b/ArkUIKit/Animation/README_zh.md @@ -0,0 +1,235 @@ +# ArkUI使用动效组件指南文档示例 + +### 介绍 + +本示例通过使用[ArkUI指南文档](https://gitcode.com/openharmony/docs/tree/master/zh-cn/application-dev/ui)中各场景的开发示例,展示在工程中,帮助开发者更好地理解ArkUI提供的组件及组件属性并合理使用。该工程中展示的代码详细描述可查如下链接: +1. [显示动画(animateTo)](https://gitcode.com/openharmony/docs/blob/master/zh-cn/application-dev/reference/apis-arkui/arkui-ts/ts-explicit-animation.md)。 +2. [属性动画(animation)](https://gitcode.com/openharmony/docs/blob/master/zh-cn/application-dev/reference/apis-arkui/arkui-ts/ts-animatorproperty.md)。 +3. [动画衔接](https://gitcode.com/openharmony/docs/blob/master/zh-cn/application-dev/ui/arkts-animation-smoothing.md)。 +4. [关键帧动画](https://gitcode.com/openharmony/docs/blob/master/zh-cn/application-dev/reference/apis-arkui/arkui-ts/ts-keyframeAnimateTo.md)。 +5. [页面间转场](https://gitcode.com/openharmony/docs/blob/master/zh-cn/application-dev/reference/apis-arkui/arkui-ts/ts-page-transition-animation.md)。 +6. [组件内转场](https://gitcode.com/openharmony/docs/blob/master/zh-cn/application-dev/reference/apis-arkui/arkui-ts/ts-transition-animation-component.md)。 +7. [共享元素转场](https://gitcode.com/openharmony/docs/blob/master/zh-cn/application-dev/reference/apis-arkui/arkui-ts/ts-transition-animation-shared-elements.md)。 +8. [路径动画](https://gitcode.com/openharmony/docs/blob/master/zh-cn/application-dev/reference/apis-arkui/arkui-ts/ts-motion-path-animation.md)。 +9. [粒子动画](https://gitcode.com/openharmony/docs/blob/master/zh-cn/application-dev/reference/apis-arkui/arkui-ts/ts-particle-animation.md)。 +10. [帧动画](https://gitcode.com/openharmony/docs/blob/master/zh-cn/application-dev/reference/apis-arkui/js-apis-animator.md)。 +11. [显式动画立即下发](https://gitcode.com/openharmony/docs/blob/master/zh-cn/application-dev/reference/apis-arkui/arkui-ts/ts-explicit-animatetoimmediately.md)。 +12. [旋转屏动画](https://gitcode.com/openharmony/docs/blob/master/zh-cn/application-dev/ui/arkts-rotation-transition-animation.md)。 +13. [模糊动画](https://gitcode.com/openharmony/docs/blob/master/zh-cn/application-dev/ui/arkts-blur-effect.md) +14. [自定义属性动画](https://gitcode.com/openharmony/docs/blob/master/zh-cn/application-dev/ui/arkts-custom-attribute-animation.md) +15. [组件动画](https://gitcode.com/openharmony/docs/blob/master/zh-cn/application-dev/ui/arkts-component-animation.md) + +### 效果预览 + +| 首页 | +|------------------------------------| +| ![](screenshots/device/image2.png) | + +### 使用说明 + +1. 在主界面,可以点击对应卡片,选择需要参考的组件示例。 + +2. 在组件目录选择详细的示例参考。 + +3. 进入示例界面,查看参考示例。 + +4. 通过自动测试框架可进行测试及维护。 + +### 工程目录 +``` +entry/src/main/ets/ +|---entryability +|---pages +| |---animatableProperty // 自定义属性动画 +| | |---template1 +| | | |---Index.ets // 示例1(改变Text组件宽度) +| | |---template2 +| | | |---Index.ets // 示例2(改变图形形状) +| |---animateTo // 显示动画(animateTo) +| | |---template1 +| | | |---Index.ets // 示例1(在组件出现时创建动画) +| | |---template2 +| | | |---Index.ets // 示例2(动画执行结束后组件消失) +| | |---template3 +| | | |---Index.ets // 示例3(在状态管理V2中使用animateTo) +| |---animateToImmediately // 显式动画立即下发 +| | |---template1 +| | | |---Index.ets +| |---animation // 属性动画(animation) +| | |---template1 +| | | |---Index.ets +| | |---template2 +| | | |---Index.ets // 示例2(使用animateTo产生属性动画) +| | |---template3 +| | | |---Index.ets // 示例3(使用animation产生属性动画) +| | |---template4 +| | | |---Index.ets // 示例4(使用keyframeAnimateTo产生属性动画) +| |---animationBlur // 属性动画(animation) +| | |---template1 +| | | |---Index.ets // 示例1(使用backdropBlur为组件添加背景模糊) +| | |---template2 +| | | |---Index.ets // 示例2(使用blur为组件添加内容模糊) +| | |---template3 +| | | |---Index.ets // 示例3(使用backgroundBlurStyle为组件添加背景模糊效果) +| | |---template4 +| | | |---Index.ets // 示例4(使用foregroundBlurStyle为组件添加内容模糊效果) +| | |---template5 +| | | |---Index.ets // 示例5(使用motionBlur为组件添加运动模糊效果) +| |---animator // 帧动画 +| | |---template1 // 示例1(基于ArkTS扩展的声明式开发范式) +| | | |---Index.ets +| | |---template2 // 示例2(位移动画示例) +| | | |---Index.ets +| | |---template3 // 示例3(使用帧动画实现小球抛物运动) +| | | |---Index.ets +| | |---template4 // 示例4(使用帧动画实现小球抛物运动) +| | | |---Index.ets +| |---cohesion // 动画衔接 +| | |---template1 +| | | |---Index.ets +| | |---template2 +| | | |---Index.ets +| |---component // 组件动画 +| | |---template1 +| | | |---Index.ets // 示例1(Scroll组件滑动动效) +| | |---template2 +| | | |---Index.ets // 示例2(List组件动态替换动效) +| |---compTransition // 组件内转场 +| | |---template1 +| | | |---Index.ets // 示例1(使用同一接口实现图片出现消失) +| | |---template2 +| | | |---Index.ets // 示例2(使用不同接口实现图片出现消失) +| | |---template3 +| | | |---Index.ets // 示例3(设置父子组件为transition) +| | |---template4 +| | | |---Index.ets // 示例4(出现/消失转场) +| | |---template5 +| | | |---Index.ets // 示例5(多个组件渐次出现消失) +| | |---template6 +| | | |---Index.ets // 示例6(旋转转场效果出现/消失) +| |---keyframeAnimateTo // 关键帧动画 +| | |---template1 +| | | |---Index.ets +| |---motionPath // 路径动画 +| | |---template1 +| | | |---Index.ets +| |---pageTransition // 页面间转场 +| | |---template1 +| | | |---Index.ets // 示例1(设置退入场动画) +| | |---template2 +| | | |---Index.ets // 示例2(设置退入场平移效果) +| | |---template3 +| | | |---Index.ets // 示例3(不推荐)(利用pushUrl跳转能力) +| | |---template4 +| | | |---Index.ets // 示例4(不推荐)(type为None的页面转场) +| | |---template5 +| | | |---Index.ets // 示例5(不推荐)(type配置为RouteType.None) +| | |---template6 +| | | |---Index.ets // 示例6(不推荐)(type配置为RouteType.Push或RouteType.Pop) +| |---particle // 粒子动画 +| | |---template1 +| | | |---Index.ets // 示例1(圆形初始化粒子) +| | |---template2 +| | | |---Index.ets // 示例2(图片初始化粒子) +| | |---template3 +| | | |---Index.ets // 示例3(粒子扰动场的干扰下运动轨迹发生变化) +| | |---template4 +| | | |---Index.ets // 示例4(调整粒子发射器位置) +| | |---template5 +| | | |---Index.ets // 示例5(环形发射器创建) +| | |---template6 +| | | |---Index.ets // 示例6(环形发射器更新) +| |---rotation // 旋转屏动画 +| | |---template1 +| | | |---Index.ets +| | |---template2 +| | | |---Index.ets +| |---shareTransition // 共享元素转场 +| | |---template1 +| | | |---Index.ets +|---pages +| |---Index.ets // 应用主页面 +entry/src/ohosTest/ +|---ets +| |---test +| | |---AnimatableProperty.test.ets // 自定义属性动画示例代码测试代码 +| | |---AnimateTo.test.ets // 显示动画(animateTo)示例代码测试代码 +| | |---AnimateToImmediately.test.ets // 显式动画立即下发示例代码测试代码 +| | |---Animation.test.ets // 属性动画(animation)示例代码测试代码 +| | |---Animator.test.ets // 帧动画示例代码测试代码 +| | |---Cohesion.test.ets // 动画衔接示例代码测试代码 +| | |---Component.test.ets // 组件动画示例代码测试代码 +| | |---ComponentTransition.test.ets // 组件内转场示例代码测试代码 +| | |---KeyFrameAnimateTo.test.ets // 关键帧动画示例代码测试代码 +| | |---MotionPath.test.ets // 路径动画示例代码测试代码 +| | |---PageTransition.test.ets // 页面间转场示例代码测试代码 +| | |---Particle.test.ets // 粒子动画示例代码测试代码 +| | |---Rotation.test.ets // 旋转屏动画示例代码测试代码 +| | |---ShareTransition.test.ets // 共享元素转场示例代码测试代码 +``` + +### 具体实现 +1. 自定义属性动画 + 数值类型可动画属性功能封装在AnimatablePropertyModule,源码参考:[Index.ets](https://gitcode.com/openharmony/applications_app_samples/blob/master/code/DocsSample/ArkUISample/Animation/entry/src/main/ets/pages/AnimatableProperty/template1/Index.ets) + * 自定义可动画属性接口:使用@AnimatableExtend装饰器为 Text 组件封装animatableWidth方法,内部调用系统width属性接口,源码参考上述AnimatablePropertyExample中对应方法。 + * 动画触发与使用:在AnimatablePropertyExample组件中,通过@State修饰的textWidth变量控制宽度值,为animatableWidth绑定animation配置动画参数,在 Button 的onClick事件中修改textWidth触发动画,实现 Text 组件宽度的动画效果。 + 自定义类型可动画属性功能封装在AnimatedShapeModule,源码参考:[Index.ets](https://gitcode.com/openharmony/applications_app_samples/blob/master/code/DocsSample/ArkUISample/Animation/entry/src/main/ets/pages/AnimatableProperty/template2/Index.ets) + * 自定义可动画数据类型:实现PointClass和PointVector类,分别继承数组并实现AnimatableArithmetic接口的add、subtract、multiply、equals等方法,支持动画框架对自定义点集合类型的计算,源码参考上述AnimatedShape中对应类的实现。 + * 自定义可动画属性接口:使用@AnimatableExtend装饰器为 Polyline 组件封装animatablePoints方法,内部调用系统points属性接口,源码参考上述AnimatedShape中对应方法。 + * 动画触发与使用:在AnimatedShape组件中,通过@State修饰的polyline1Vec等变量控制图形点集合,为animatablePoints绑定animation配置动画参数,在 Polyline 的onClick事件中切换点集合变量触发动画,实现 Polyline 图形形状的动画效果。 +2. 帧动画:通过向应用提供onFrame逐帧回调,帧动画使开发者能够在应用的每一帧设置属性值,从而实现组件属性值变化的自然过渡,营造出动画效果。源码参考[animator/template1/Index.ets](https://gitcode.com/openharmony/applications_app_samples/blob/master/code/DocsSample/ArkUISample/Animation/entry/src/main/ets/pages/animator/template1/Index.ets) + * 使用帧动画ohos.animator开发者可每帧修改UI侧属性值,UI侧属性实时更新。 + * 在属性动画UI侧只计算动画最终状态,动画过程为渲染值在改变,UI侧一直为动画最终状态,不感知实时渲染值。 + * 帧动画在动画过程中即可实时响应,而属性动画按最终状态响应。 +3. 模糊动画:使用backdropBlur为组件添加背景模糊。源码参考[animationBlur/template1/blurEffectsExample.ets](https://gitcode.com/openharmony/applications_app_samples/blob/master/code/DocsSample/ArkUISample/SupportingAgingFriendly/entry/src/main/ets/pages/animationBlur/template1/blurEffectsExample.ets) + * 模糊和阴影效果可以让物体看起来更加立体,使得动画更加生动。 + * 提供了丰富的效果接口,开发者可快速打造出精致、个性化的效果。 + * 常用的模糊、阴影和色彩效果。 +4. 动画衔接:使用animation接口作用的属性值,即可产生动画。源码参考[cohesion/template1/Index.ets](https://gitcode.com/openharmony/applications_app_samples/blob/master/code/DocsSample/ArkUISample/SupportingAgingFriendly/entry/src/main/ets/pages/cohesion/template1/Index.ets) + * 对于桌面翻页类从跟手到离手触发动画的场景,离手后动画的初始速度应承继手势速度,避免由于速度不接续导致停顿感的产生。 + * 系统已提供动画与动画、手势与动画之间的衔接能力,保证各类场景下动画平稳光滑地过渡的同时,尽可能降低开发难度。 + * 开发者仅需在animateTo动画闭包中改变属性值或者改变animation接口作用的属性值,即可产生动画。 +5. 组件动画 +组件默认动画功能封装在ComponentDefaultAnimationModule,源码参考:[Index.ets](https://gitcode.com/openharmony/applications_app_samples/blob/master/code/DocsSample/ArkUISample/Animation/entry/src/main/ets/pages/component/template1/Index.ets) +* 默认动画特性:ArkUI 部分基础组件(如 Checkbox、Button、List 等)内置了状态切换或交互反馈动画。例如 Checkbox 的勾选 / 取消动效、Button 的点击高亮反馈、List 的滑动过渡效果,这些动画无需开发者手动编写逻辑,能直观提示用户操作状态(如选中、点击生效)。 +* 使用方式:直接声明组件并配置基础属性(如 Checkbox 的shape、size、select状态),当组件状态发生变更时(如通过交互修改select值),默认动画会自动触发,简化了基础交互场景的动效实现。 +* 适用场景:适用于需要快速实现标准化交互反馈的场景,无需关注动画细节即可让界面具备基础生动性,减少开发工作量。 + Scroll 组件定制化动效封装在TaskSwitchModule,源码参考:[Index.ets](https://gitcode.com/openharmony/applications_app_samples/blob/master/code/DocsSample/ArkUISample/Animation/entry/src/main/ets/pages/component/template2/Index.ets) +* 动效定制逻辑:通过Scroller和PanGesture手势监控滑动距离,结合WindowManager获取屏幕尺寸,动态计算子组件的仿射属性。例如根据滑动进度调整卡片的scale(中间卡片放大、边缘卡片正常)、translate(位移偏移)和zIndex(层级叠加),实现滑动时的立体层次感。 +* 动画参数配置:为子组件绑定animation,设置不同曲线(如Curve.Smooth用于缩放过渡、curves.springMotion()用于位移弹性效果),确保滑动过程中动效自然流畅。 +* 边界与校准处理:在手势结束回调中,通过计算滑动速度和偏移量,校准卡片最终位置(如左滑 / 右滑到极限时锁定位置,未满足切换距离时自动回位),保证交互体验一致性。 +* 触发方式:支持滑动手势直接触发动效,也可通过点击 “Move to first/last” 按钮切换首尾位置,按钮点击会同步更新偏移量并触发动画。 + List 组件定制化动效封装在ListAutoSortModule,源码参考:[Index.ets](https://gitcode.com/openharmony/applications_app_samples/blob/master/code/DocsSample/ArkUISample/Animation/entry/src/main/ets/pages/component/template3/Index.ets) +* 动效核心实现:通过DragSortCtrl类管理列表项数据与视觉属性,该类封装了列表项移动逻辑(itemMove方法)和偏移量计算(onMove方法)。结合animateTo和createAnimator创建弹簧动画(使用interpolatingSpring曲线),在逐帧回调中更新translate属性,实现 Item 移动时的弹性过渡。 +* 交互触发机制:为 ListItem 配置swipeAction,滑动 Item 后显示 “To TOP” 按钮,点击按钮时启动动画;通过attributeModifier动态应用ListItemModify中的偏移量,让列表项在移动过程中实时更新位置。 +* 列表分组适配:支持将列表项分为多个ListItemGroup,动效会自动适配分组内的 Item 排列逻辑,确保移动时不破坏分组结构,保持界面布局合理性。 +* 动画控制细节:通过listScroll.closeAllSwipeActions确保滑动操作完成后再启动动画,避免交互冲突;动画结束后自动更新列表数据顺序,实现视觉与数据的同步。 +>>>>>>> master + +### 相关权限 + +不涉及。 + +### 依赖 + +不涉及。 + +### 约束与限制 + +1.本示例仅支持标准系统上运行, 支持设备:RK3568。 + +2.本示例为Stage模型,支持API20版本SDK,版本号:6.0.0.33,镜像版本号:OpenHarmony_6.0.0.33。 + +3.本示例需要使用DevEco Studio 6.0.0 Canary1 (Build Version: 6.0.0.270, built on May 9, 2025)及以上版本才可编译运行。 + +### 下载 + +如需单独下载本工程,执行如下命令: + +```` +git init +git config core.sparsecheckout true +echo code/DocsSample/ArkUISample/Animation > .git/info/sparse-checkout +git remote add origin https://gitcode.com/openharmony/applications_app_samples +git pull origin master +```` \ No newline at end of file diff --git a/ArkUIKit/Animation/build-profile.json5 b/ArkUIKit/Animation/build-profile.json5 new file mode 100644 index 0000000000000000000000000000000000000000..3ca5a93fb814017ac4c398aacbdf17b1d8b0a237 --- /dev/null +++ b/ArkUIKit/Animation/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": "6.0.0(20)", + "compatibleSdkVersion": "6.0.0(20)", + "targetSdkVersion": "6.0.0(20)", + "runtimeOS": "HarmonyOS", + "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/Animation/code-linter.json5 b/ArkUIKit/Animation/code-linter.json5 new file mode 100644 index 0000000000000000000000000000000000000000..5c4682f8164874ec7e9cb8f99ff8b3228ffbc126 --- /dev/null +++ b/ArkUIKit/Animation/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/Animation/entry/.gitignore b/ArkUIKit/Animation/entry/.gitignore new file mode 100644 index 0000000000000000000000000000000000000000..e2713a2779c5a3e0eb879efe6115455592caeea5 --- /dev/null +++ b/ArkUIKit/Animation/entry/.gitignore @@ -0,0 +1,6 @@ +/node_modules +/oh_modules +/.preview +/build +/.cxx +/.test \ No newline at end of file diff --git a/ArkUIKit/Animation/entry/build-profile.json5 b/ArkUIKit/Animation/entry/build-profile.json5 new file mode 100644 index 0000000000000000000000000000000000000000..982dbb524bd63408e05cfbed7204dd87a31dd681 --- /dev/null +++ b/ArkUIKit/Animation/entry/build-profile.json5 @@ -0,0 +1,42 @@ +/* + * 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": { + }, + "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/Animation/entry/hvigorfile.ts b/ArkUIKit/Animation/entry/hvigorfile.ts new file mode 100644 index 0000000000000000000000000000000000000000..8774588471ede4c1563f09d9a1d22f764bb1fd9e --- /dev/null +++ b/ArkUIKit/Animation/entry/hvigorfile.ts @@ -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 { 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. */ +} diff --git a/ArkUIKit/Animation/entry/obfuscation-rules.txt b/ArkUIKit/Animation/entry/obfuscation-rules.txt new file mode 100644 index 0000000000000000000000000000000000000000..272efb6ca3f240859091bbbfc7c5802d52793b0b --- /dev/null +++ b/ArkUIKit/Animation/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/Animation/entry/oh-package.json5 b/ArkUIKit/Animation/entry/oh-package.json5 new file mode 100644 index 0000000000000000000000000000000000000000..10cda399b0aec3099b257299a57d284393e4e55a --- /dev/null +++ b/ArkUIKit/Animation/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/Animation/entry/src/main/ets/common/resource.ets b/ArkUIKit/Animation/entry/src/main/ets/common/resource.ets new file mode 100644 index 0000000000000000000000000000000000000000..723a394265ee2e6bf6d895e9503c4b2d8e49207a --- /dev/null +++ b/ArkUIKit/Animation/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/Animation/entry/src/main/ets/entryability/EntryAbility.ets b/ArkUIKit/Animation/entry/src/main/ets/entryability/EntryAbility.ets new file mode 100644 index 0000000000000000000000000000000000000000..081b700cacec6def24d204fbc37ab93985f7b4ec --- /dev/null +++ b/ArkUIKit/Animation/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/Animation/entry/src/main/ets/entrybackupability/EntryBackupAbility.ets b/ArkUIKit/Animation/entry/src/main/ets/entrybackupability/EntryBackupAbility.ets new file mode 100644 index 0000000000000000000000000000000000000000..4ce6449f0e91914e73d4502c9f2e8e9a395ea4b1 --- /dev/null +++ b/ArkUIKit/Animation/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/Animation/entry/src/main/ets/pages/Index.ets b/ArkUIKit/Animation/entry/src/main/ets/pages/Index.ets new file mode 100644 index 0000000000000000000000000000000000000000..1cb9c86c23bf7ab7c18c9e9a727f7b75e2be2af5 --- /dev/null +++ b/ArkUIKit/Animation/entry/src/main/ets/pages/Index.ets @@ -0,0 +1,316 @@ +/* + * 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 AnimateIndex { + @Provide('router') router: NavPathStack = new NavPathStack(); + @State routes: RouteGroup[] = [ + { + name: "animateTo", + // $r('app.string.animate_to_label')需要替换为开发者所需的资源文件 + label: $r('app.string.animate_to_label'), + children: [ + // $r('app.string.animate_to_temp_label1')需要替换为开发者所需的资源文件 + { name: 'template1/Index', label: $r('app.string.animate_to_temp_label1') }, + { name: 'template2/Index', label: $r('app.string.animate_to_temp_label2') }, + { name: 'template3/Index', label: $r('app.string.animate_to_temp_label3') } + ] + }, + { + name: "animation", + // $r('app.string.animation_label')需要替换为开发者所需的资源文件 + label: $r('app.string.animation_label'), + children: [ + // $r('app.string.temp1')需要替换为开发者所需的资源文件 + { name: 'template1/Index', label: $r('app.string.temp1') }, + { name: 'template2/Index', label: $r('app.string.animation_temp_label2') }, + { name: 'template3/Index', label: $r('app.string.animation_temp_label3') }, + { name: 'template4/Index', label: $r('app.string.animation_temp_label4') } + ] + }, + { + name: "animationBlur", + label: $r("app.string.animation_blur_label"), + children: [ + { name: 'template1/BlurEffectsExample', label: $r("app.string.animation_blur_label1") }, + { name: 'template2/Index', label: $r("app.string.animation_blur_label2") }, + { name: 'template3/BackDropBlurStyleDemo', label: $r("app.string.animation_blur_label3") }, + { name: 'template4/ForegroundBlurStyleDemo', label: $r("app.string.animation_blur_label4") }, + { name: 'template5/MotionBlurTest', label: $r("app.string.animation_blur_label5") } + ] + }, + { + name: "cohesion", + // $r('app.string.cohesion_label')需要替换为开发者所需的资源文件 + label: $r('app.string.cohesion_label'), + children: [ + // $r('app.string.cohesion_temp_label1')需要替换为开发者所需的资源文件 + { name: 'template1/Index', label: $r('app.string.cohesion_temp_label1') }, + { name: 'template2/Index', label: $r('app.string.cohesion_temp_label2') } + ] + }, + { + name: "keyframeAnimateTo", + // $r('app.string.keyframeAnimateTo_label')需要替换为开发者所需的资源文件 + label: $r('app.string.keyframeAnimateTo_label'), + children: [ + // $r('app.string.temp1') 需要替换为开发者所需的资源文件 + { name: 'template1/Index', label: $r('app.string.temp1') } + ] + }, + { + name: "pageTransition", + // $r('app.string.pageTransition_label')需要替换为开发者所需的资源文件 + label: $r('app.string.pageTransition_label'), + children: [ + // $r('app.string.pageTransition_temp_label1')需要替换为开发者所需的资源文件 + { name: 'template1/Index', label: $r('app.string.pageTransition_temp_label1') }, + { name: 'template2/Index', label: $r('app.string.pageTransition_temp_label2') }, + { name: 'template3/pageTransitionSrc1', label: $r('app.string.pageTransition_temp_label3') }, + { name: 'template4/pageTransitionSrc2', label: $r('app.string.pageTransition_temp_label4') }, + { name: 'template5/PageTransitionSrc3', label: $r("app.string.pageTransition_temp_label5") }, + { name: 'template6/PageTransitionSrc4', label: $r("app.string.pageTransition_temp_label6") } + ] + }, + { + name: "compTransition", + // $r('app.string.compTransition_label')需要替换为开发者所需的资源文件 + label: $r('app.string.compTransition_label'), + children: [ + // $r('app.string.compTransition_temp_label1')需要替换为开发者所需的资源文件 + { name: 'template1/Index', label: $r('app.string.compTransition_temp_label1') }, + { name: 'template2/Index', label: $r('app.string.compTransition_temp_label2') }, + { name: 'template3/Index', label: $r('app.string.compTransition_temp_label3') }, + { name: 'template4/Index', label: $r('app.string.compTransition_temp_label4') }, + { name: 'template5/Index', label: $r('app.string.compTransition_temp_label5') }, + { name: 'template6/Index', label: $r('app.string.compTransition_temp_label6') } + ] + }, + { + name: "shareTransition", + // $r('app.string.shareTransition_label')需要替换为开发者所需的资源文件 + label: $r('app.string.shareTransition_label'), + children: [ + // $r('app.string.temp1') 需要替换为开发者所需的资源文件 + { name: 'template1/Index', label: $r('app.string.temp1') } + ] + }, + { + name: "motionPath", + // $r('app.string.motionPath_label')需要替换为开发者所需的资源文件 + label: $r('app.string.motionPath_label'), + children: [ + // $r('app.string.temp1')需要替换为开发者所需的资源文件 + { name: 'template1/Index', label: $r('app.string.temp1') } + ] + }, + { + name: "particle", + // $r('app.string.particle_label')需要替换为开发者所需的资源文件 + label: $r('app.string.particle_label'), + children: [ + // $r('app.string.particle_temp_label1')需要替换为开发者所需的资源文件 + { name: 'template1/Index', label: $r('app.string.particle_temp_label1') }, + { name: 'template2/Index', label: $r('app.string.particle_temp_label2') }, + { name: 'template3/Index', label: $r('app.string.particle_temp_label3') }, + { name: 'template4/Index', label: $r('app.string.particle_temp_label4') }, + { name: 'template5/Index', label: $r('app.string.particle_temp_label5') }, + { name: 'template6/Index', label: $r('app.string.particle_temp_label6') } + ] + }, + { + name: "animator", + // $r('app.string.animator_label')需要替换为开发者所需的资源文件 + label: $r('app.string.animator_label'), + children: [ + // $r('app.string.animator_temp_label1')需要替换为开发者所需的资源文件 + { name: 'template1/Index', label: $r("app.string.animator_temp_label1") }, + { name: 'template2/Index', label: $r("app.string.animator_temp_label2") }, + { name: 'template3/Index', label: $r("app.string.animator_temp_label3") }, + { name: 'template4/Index', label: $r("app.string.animator_temp_label4") } + ] + }, + { + name: "animateToImmediately", + // $r('app.string.animateToImmediately_label')需要替换为开发者所需的资源文件 + label: $r('app.string.animateToImmediately_label'), + children: [ + // $r('app.string.temp1')需要替换为开发者所需的资源文件 + { name: 'template1/Index', label: $r('app.string.temp1') } + ] + }, + { + name: "rotation", + // $r('app.string.rotation_label')需要替换为开发者所需的资源文件 + label: $r('app.string.rotation_label'), + children: [ + // $r('app.string.rotation_temp_label1')需要替换为开发者所需的资源文件 + { name: 'template1/Index', label: $r('app.string.rotation_temp_label1') }, + { name: 'template2/Index', label: $r('app.string.rotation_temp_label2') } + ] + }, + { + name: "animatableProperty", + // $r("app.string.animatableProperty_label")需要替换为开发者所需的资源文件 + label: $r("app.string.animatableProperty_label"), + children: [ + // $r("app.string.component_temp_label1")需要替换为开发者所需的资源文件 + { name: 'template1/Index', label: $r("app.string.animatableProperty_temp_label1") }, + { name: 'template2/Index', label: $r("app.string.animatableProperty_temp_label2") }, + ] + }, + { + name: "component", + // $r('app.string.component_label')需要替换为开发者所需的资源文件 + label: $r('app.string.component_label'), + children: [ + // $r('app.string.component_temp_label1')需要替换为开发者所需的资源文件 + { name: 'template1/Index', label: $r('app.string.component_temp_label1') }, + { name: 'template2/Index', label: $r('app.string.component_temp_label2') }, + ] + } + ]; + @State selection: string | null = null; + + @Builder + ListItemGroupHeader(route: RouteGroup) { + Row() { + Text(route.label) + // $r('app.string.ohos_id_color_text_primary')需要替换为开发者所需的资源文件 + .fontColor($r('sys.color.ohos_id_color_text_primary')) + .fontWeight(FontWeight.Medium) + + Blank() + + Text(`${route.children.length}`) + // $r('sys.color.ohos_id_color_text_secondary')需要替换为开发者所需的资源文件 + .fontColor($r('sys.color.ohos_id_color_text_secondary')) + .opacity(this.selection === route.name ? 0 : 1) + + // $r('sys.media.ohos_ic_public_arrow_right')需要替换为开发者所需的资源文件 + Image($r('sys.media.ohos_ic_public_arrow_right')) + // $r('sys.color.ohos_id_color_fourth')需要替换为开发者所需的资源文件 + .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(() => { + this.getUIContext().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() { + // $r('app.string.AnimateIndex')需要替换为开发者所需的资源文件 + Text($r('app.string.AnimateIndex')) + 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() + // $r('sys.media.ohos_ic_public_arrow_right')需要替换为开发者所需的资源文件 + Image($r('sys.media.ohos_ic_public_arrow_right')) + // $r('sys.color.ohos_id_color_fourth')需要替换为开发者所需的资源文件 + .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}`; + this.getUIContext().getRouter().pushUrl({ url: name }); + }) + } + .width('100%') + }) + } + } + .padding(2) + .divider({ strokeWidth: 0.5 }) + }) + }.padding({ bottom: 10 }) + } + } +} \ No newline at end of file diff --git a/ArkUIKit/Animation/entry/src/main/ets/pages/animatableProperty/template1/Index.ets b/ArkUIKit/Animation/entry/src/main/ets/pages/animatableProperty/template1/Index.ets new file mode 100644 index 0000000000000000000000000000000000000000..6ddc139fc91f4df020d572ec3923a95ff534c6d5 --- /dev/null +++ b/ArkUIKit/Animation/entry/src/main/ets/pages/animatableProperty/template1/Index.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 Animation_AnimatableProperty] +// 第一步:使用@AnimatableExtend装饰器,自定义可动画属性接口 +@AnimatableExtend(Text) +function animatableWidth(width: number) { + .width(width); // 调用系统属性接口,逐帧回调函数每帧修改可动画属性的值,实现逐帧布局的效果。 +} + +@Entry +@Component +struct AnimatablePropertyExample { + @State textWidth: number = 80; // 80: 初始文本宽度 + + build() { + Column() { + // $r('app.string.animatableProperty_AnimatableProperty')需要替换为开发者所需的资源文件 + Text($r('app.string.animatableProperty_AnimatableProperty')) + .animatableWidth(this.textWidth) // 第二步:将自定义可动画属性接口设置到组件上 + .animation({ duration: 2000, curve: Curve.Ease }); // 第三步:为自定义可动画属性接口绑定动画,2000: 动画持续时间(毫秒) + // $r('app.string.animatableProperty_Play')需要替换为开发者所需的资源文件 + Button($r('app.string.animatableProperty_Play')) + .onClick(() => { + this.textWidth = this.textWidth == 80 ? 160 : 80; // 第四步:改变自定义可动画属性的参数,产生动画,80: 最小宽度,160: 最大宽度 + }); + }.width('100%') + .padding(10); // 10: 内边距 + } +} +// [End Animation_AnimatableProperty] \ No newline at end of file diff --git a/ArkUIKit/Animation/entry/src/main/ets/pages/animatableProperty/template2/Index.ets b/ArkUIKit/Animation/entry/src/main/ets/pages/animatableProperty/template2/Index.ets new file mode 100644 index 0000000000000000000000000000000000000000..4b898c825708c048a09eaa16c56079347ffcdcd4 --- /dev/null +++ b/ArkUIKit/Animation/entry/src/main/ets/pages/animatableProperty/template2/Index.ets @@ -0,0 +1,152 @@ +/* + * 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 Animation_AnimatableProperty] +declare type Point = number[]; + +// 定义可动画属性接口的参数类型,实现AnimatableArithmetic接口中加法、减法、乘法和判断相等函数 +class PointClass extends Array { + constructor(value: Point) { + super(value[0], value[1]); + } + + add(rhs: PointClass): PointClass { + let result: Point = new Array() as Point; + for (let i = 0; i < 2; i++) { // 2: 二维坐标点 + result.push(rhs[i] + this[i]); + } + return new PointClass(result); + } + + subtract(rhs: PointClass): PointClass { + let result: Point = new Array() as Point; + for (let i = 0; i < 2; i++) { // 2: 二维坐标点 + result.push(this[i] - rhs[i]); + } + return new PointClass(result); + } + + multiply(scale: number): PointClass { + let result: Point = new Array() as Point; + for (let i = 0; i < 2; i++) { // 2: 二维坐标点 + result.push(this[i] * scale); + } + return new PointClass(result); + } +} + +// 定义可动画属性接口的参数类型,实现AnimatableArithmetic接口中加法、减法、乘法和判断相等函数 +// 模板T支持嵌套实现AnimatableArithmetic的类型 +class PointVector extends Array implements AnimatableArithmetic> { + constructor(initialValue: Array) { + super(); + if (initialValue.length) { + initialValue.forEach((p: Point) => this.push(new PointClass(p))); + } + } + + // implement the IAnimatableArithmetic interface + plus(rhs: PointVector): PointVector { + let result = new PointVector([]); + const len = Math.min(this.length, rhs.length); + for (let i = 0; i < len; i++) { + result.push(this[i].add(rhs[i])); + } + return result; + } + + subtract(rhs: PointVector): PointVector { + let result = new PointVector([]); + const len = Math.min(this.length, rhs.length); + for (let i = 0; i < len; i++) { + result.push(this[i].subtract(rhs[i])); + } + return result; + } + + multiply(scale: number): PointVector { + let result = new PointVector([]); + for (let i = 0; i < this.length; i++) { + result.push(this[i].multiply(scale)); + } + return result; + } + + equals(rhs: PointVector): boolean { + if (this.length !== rhs.length) { + return false; + } + for (let index = 0, size = this.length; index < size; ++index) { + if (this[index][0] !== rhs[index][0] || this[index][1] !== rhs[index][1]) { + return false; + } + } + return true; + } +} + +// 自定义可动画属性接口 +@AnimatableExtend(Polyline) +function animatablePoints(points: PointVector) { + .points(points); +} + +@Entry +@Component +struct AnimatedShape { + squareStartPointX: number = 75; // 75: 正方形起始点X坐标 + squareStartPointY: number = 25; // 25: 正方形起始点Y坐标 + squareWidth: number = 150; // 150: 正方形宽度 + squareEndTranslateX: number = 50; // 50: 正方形结束位置X轴平移量 + squareEndTranslateY: number = 50; // 50: 正方形结束位置Y轴平移量 + @State pointVec1: PointVector = new PointVector([ + [this.squareStartPointX, this.squareStartPointY], + [this.squareStartPointX + this.squareWidth, this.squareStartPointY], + [this.squareStartPointX + this.squareWidth, this.squareStartPointY + this.squareWidth], + [this.squareStartPointX, this.squareStartPointY + this.squareWidth] + ]); + @State pointVec2: PointVector = new PointVector([ + [this.squareStartPointX + this.squareEndTranslateX, this.squareStartPointY + this.squareStartPointY], + [this.squareStartPointX + this.squareWidth + this.squareEndTranslateX, + this.squareStartPointY + this.squareStartPointY], + [this.squareStartPointX + this.squareWidth, this.squareStartPointY + this.squareWidth], + [this.squareStartPointX, this.squareStartPointY + this.squareWidth] + ]); + @State color: Color = Color.Green; + @State fontSize: number = 20.0; // 20.0: 字体大小 + @State polyline1Vec: PointVector = this.pointVec1; + @State polyline2Vec: PointVector = this.pointVec2; + + build() { + Row() { + Polyline() + .width(300) // 300: 折线宽度 + .height(200) // 200: 折线高度 + .backgroundColor('#0C000000') // 0C000000: 背景颜色(黑色带透明度) + .fill('#317AF7') // 317AF7: 填充颜色(蓝色) + .animatablePoints(this.polyline1Vec) + .animation({ duration: 2000, delay: 0, curve: Curve.Ease }) // 2000: 动画持续时间(毫秒),0: 动画延迟时间 + .onClick(() => { + if (this.polyline1Vec.equals(this.pointVec1)) { + this.polyline1Vec = this.pointVec2; + } else { + this.polyline1Vec = this.pointVec1; + } + }); + } + .width('100%').height('100%').justifyContent(FlexAlign.Center); + } +} +// [End Animation_AnimatableProperty] \ No newline at end of file diff --git a/ArkUIKit/Animation/entry/src/main/ets/pages/animateTo/template1/Index.ets b/ArkUIKit/Animation/entry/src/main/ets/pages/animateTo/template1/Index.ets new file mode 100644 index 0000000000000000000000000000000000000000..c487840e0060b57cb9a879f83058e8fd7d72fd06 --- /dev/null +++ b/ArkUIKit/Animation/entry/src/main/ets/pages/animateTo/template1/Index.ets @@ -0,0 +1,83 @@ +/* + * 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. + */ +@Entry +@Component +struct AnimateToExample { + @State widthSize: number = 250; + @State heightSize: number = 100; + @State rotateAngle: number = 0; + private flag: boolean = true; + + build() { + Column() { + Button('change size') + .width(this.widthSize) + .height(this.heightSize) + .margin(30) + .onClick(() => { + if (this.flag) { + // 建议使用this.getUIContext()?.animateTo() + this.getUIContext()?.animateTo({ + duration: 2000, + curve: Curve.EaseOut, + iterations: 3, + playMode: PlayMode.Normal, + onFinish: () => { + console.info('play end'); + } + }, () => { + this.widthSize = 150; + this.heightSize = 60; + }) + } else { + // 建议使用this.getUIContext()?.animateTo() + this.getUIContext()?.animateTo({}, () => { + this.widthSize = 250; + this.heightSize = 100; + }) + } + this.flag = !this.flag; + }) + Button('stop rotating') + .margin(50) + .rotate({ x: 0, y: 0, z: 1, angle: this.rotateAngle }) + .onAppear(() => { + // 组件出现时开始做动画 + // 建议使用this.getUIContext()?.animateTo() + this.getUIContext()?.animateTo({ + duration: 1200, + curve: Curve.Friction, + delay: 500, + iterations: -1, // 设置-1表示动画无限循环 + playMode: PlayMode.Alternate, + expectedFrameRateRange: { + min: 10, + max: 120, + expected: 60, + } + }, () => { + this.rotateAngle = 90; + }) + }) + .onClick(() => { + // 建议使用this.getUIContext()?.animateTo() + this.getUIContext()?.animateTo({ duration: 0 }, () => { + // this.rotateAngle之前为90,在duration为0的动画中修改属性,可以停止该属性之前的动画,按新设置的属性显示 + this.rotateAngle = 0; + }) + }) + }.width('100%').margin({ top: 5 }) + } +} \ No newline at end of file diff --git a/ArkUIKit/Animation/entry/src/main/ets/pages/animateTo/template2/Index.ets b/ArkUIKit/Animation/entry/src/main/ets/pages/animateTo/template2/Index.ets new file mode 100644 index 0000000000000000000000000000000000000000..ff96a620d84ad792704f5d7453a7228c3c7706f9 --- /dev/null +++ b/ArkUIKit/Animation/entry/src/main/ets/pages/animateTo/template2/Index.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. + */ +@Entry +@Component +struct AnimateToExample2 { + @State heightSize: number = 100; + @State isShow: boolean= true; + @State count: number= 0; + private isToBottom: boolean = true; // 向下 + + build() { + Column() { + if (this.isShow) { + Column() + .width(200) + .height(this.heightSize) + .backgroundColor('blue') + .onClick(() => { + // 建议使用this.getUIContext()?.animateTo() + this.getUIContext()?.animateTo({ + duration: 2000, + curve: Curve.EaseOut, + iterations: 1, + playMode: PlayMode.Normal, + onFinish: () => { + this.count--; + if (this.count == 0 && !this.isToBottom) { // 组件只有在向下做完动画才会消失 + this.isShow = false; + } + } + }, () => { + this.count++; + if (this.isToBottom) { + this.heightSize = 60; + } else { + this.heightSize = 100; + } + this.isToBottom = !this.isToBottom; + }) + }) + } + }.width('100%').height('100%').margin({ top: 5 }) + .justifyContent(FlexAlign.End) + } +} \ No newline at end of file diff --git a/ArkUIKit/Animation/entry/src/main/ets/pages/animateTo/template3/Index.ets b/ArkUIKit/Animation/entry/src/main/ets/pages/animateTo/template3/Index.ets new file mode 100644 index 0000000000000000000000000000000000000000..e6041d21080aeaff67b3441021df03899d849fc4 --- /dev/null +++ b/ArkUIKit/Animation/entry/src/main/ets/pages/animateTo/template3/Index.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. + */ +@Entry +@ComponentV2 +struct AnimateToExample3 { + @Local w: number = 50; // 宽度 + @Local h: number = 50; // 高度 + @Local message: string = 'Hello'; + + build() { + Column() { + Button('change size') + .margin(20) + .onClick(() => { + // 在执行动画前,存在额外的修改 + this.w = 100; + this.h = 100; + this.message = 'Hello Word'; + animateToImmediately({ + duration: 0 + }, () => { + }) + this.getUIContext().animateTo({ + duration: 1000 + }, () => { + this.w = 200; + this.h = 200; + this.message = 'Hello ArkUI'; + }) + }) + Column() { + Text(`${this.message}`) + } + .backgroundColor('#ff17a98d') + .width(this.w) + .height(this.h) + } + } +} \ No newline at end of file diff --git a/ArkUIKit/Animation/entry/src/main/ets/pages/animateToImmediately/template1/Index.ets b/ArkUIKit/Animation/entry/src/main/ets/pages/animateToImmediately/template1/Index.ets new file mode 100644 index 0000000000000000000000000000000000000000..d32df74972df165757f680aa7ba3d5528c2f86ec --- /dev/null +++ b/ArkUIKit/Animation/entry/src/main/ets/pages/animateToImmediately/template1/Index.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. + */ +@Entry +@Component +struct AnimateToImmediatelyExample { + @State widthSize: number = 250; + @State heightSize: number = 100; + @State opacitySize: number = 0; + private flag: boolean = true; + + build() { + Column() { + Column() + .width(this.widthSize) + .height(this.heightSize) + .backgroundColor(Color.Green) + .opacity(this.opacitySize) + Button('change size') + .margin(30) + .onClick(() => { + if (this.flag) { + animateToImmediately({ + delay: 0, + duration: 1000 + }, () => { + this.opacitySize = 1; + }) + this.getUIContext()?.animateTo({ + delay: 1000, + duration: 1000 + }, () => { + this.widthSize = 150; + this.heightSize = 60; + }) + } else { + animateToImmediately({ + delay: 0, + duration: 1000 + }, () => { + this.widthSize = 250; + this.heightSize = 100; + }) + this.getUIContext()?.animateTo({ + delay: 1000, + duration: 1000 + }, () => { + this.opacitySize = 0; + }) + } + this.flag = !this.flag; + }) + }.width('100%').margin({ top: 5 }) + } +} \ No newline at end of file diff --git a/ArkUIKit/Animation/entry/src/main/ets/pages/animation/template1/Index.ets b/ArkUIKit/Animation/entry/src/main/ets/pages/animation/template1/Index.ets new file mode 100644 index 0000000000000000000000000000000000000000..9e9fa69304ba32657ed5ab8a6cc67a34139fb51d --- /dev/null +++ b/ArkUIKit/Animation/entry/src/main/ets/pages/animation/template1/Index.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. + */ +@Entry +@Component +struct AttrAnimationExample { + @State widthSize: number = 250; + @State heightSize: number = 100; + @State rotateAngle: number = 0; + @State flag: boolean = true; + + build() { + Column() { + Button('change size') + .onClick(() => { + if (this.flag) { + this.widthSize = 150 + this.heightSize = 60 + } else { + this.widthSize = 250 + this.heightSize = 100 + } + this.flag = !this.flag + }) + .margin(30) + .width(this.widthSize) + .height(this.heightSize) + .animation({ + duration: 2000, + curve: Curve.EaseOut, + iterations: 3, + playMode: PlayMode.Normal + }) + Button('change rotate angle') + .onClick(() => { + this.rotateAngle = 90 + }) + .margin(50) + .rotate({ angle: this.rotateAngle }) + .animation({ + duration: 1200, + curve: Curve.Friction, + delay: 500, + iterations: -1, // 设置-1表示动画无限循环 + playMode: PlayMode.Alternate, + expectedFrameRateRange: { + min: 20, + max: 120, + expected: 90, + } + }) + }.width('100%').margin({ top: 20 }) + } +} \ No newline at end of file diff --git a/ArkUIKit/Animation/entry/src/main/ets/pages/animation/template2/Index.ets b/ArkUIKit/Animation/entry/src/main/ets/pages/animation/template2/Index.ets new file mode 100644 index 0000000000000000000000000000000000000000..488ccea8c97741a4d0ea2de7b626ffbe1c1c93c1 --- /dev/null +++ b/ArkUIKit/Animation/entry/src/main/ets/pages/animation/template2/Index.ets @@ -0,0 +1,68 @@ +/* + * 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 attrAnimateToDemo2] +import { curves } from '@kit.ArkUI'; +@Entry +@Component +struct attrAnimateToDemo2 { + @State animate: boolean = false; + // 第一步: 声明相关状态变量 + @State rotateValue: number = 0; // 组件一旋转角度 + @State translateX: number = 0; // 组件二偏移量 + @State opacityValue: number = 1; // 组件二透明度 + + // 第二步:将状态变量设置到相关可动画属性接口 + build() { + Row() { + // 组件一 + Column() { + } + .rotate({ angle: this.rotateValue }) + .backgroundColor('#317AF7') + .justifyContent(FlexAlign.Center) + .width(100) + .height(100) + .borderRadius(30) + .onClick(() => { + this.getUIContext()?.animateTo({ curve: curves.springMotion() }, () => { + this.animate = !this.animate; + // 第三步:闭包内通过状态变量改变UI界面 + // 这里可以写任何能改变UI的逻辑比如数组添加,显隐控制,系统会检测改变后的UI界面与之前的UI界面的差异,对有差异的部分添加动画 + // 组件一的rotate属性发生变化,所以会给组件一添加rotate旋转动画 + this.rotateValue = this.animate ? 90 : 0; + // 组件二的透明度发生变化,所以会给组件二添加透明度的动画 + this.opacityValue = this.animate ? 0.6 : 1; + // 组件二的translate属性发生变化,所以会给组件二添加translate偏移动画 + this.translateX = this.animate ? 50 : 0; + }) + }) + + // 组件二 + Column() { + } + .justifyContent(FlexAlign.Center) + .width(100) + .height(100) + .backgroundColor('#D94838') + .borderRadius(30) + .opacity(this.opacityValue) + .translate({ x: this.translateX }) + } + .width('100%') + .height('100%') + .justifyContent(FlexAlign.Center) + } +} +// [End attrAnimateToDemo2] \ No newline at end of file diff --git a/ArkUIKit/Animation/entry/src/main/ets/pages/animation/template3/Index.ets b/ArkUIKit/Animation/entry/src/main/ets/pages/animation/template3/Index.ets new file mode 100644 index 0000000000000000000000000000000000000000..43ebba68fff36bdead746c1b1edf2a2d52fb9c12 --- /dev/null +++ b/ArkUIKit/Animation/entry/src/main/ets/pages/animation/template3/Index.ets @@ -0,0 +1,70 @@ +/* + * 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 attrAnimationDemo3] +import { curves } from '@kit.ArkUI'; +@Entry +@Component +struct attrAnimationDemo3 { + @State animate: boolean = false; + // 第一步: 声明相关状态变量 + @State rotateValue: number = 0; // 组件一旋转角度 + @State translateX: number = 0; // 组件二偏移量 + @State opacityValue: number = 1; // 组件二透明度 + + // 第二步:将状态变量设置到相关可动画属性接口 + build() { + Row() { + // 组件一 + Column() { + } + .opacity(this.opacityValue) + .rotate({ angle: this.rotateValue }) + // 第三步:通过属性动画接口开启属性动画 + .animation({ curve: curves.springMotion() }) + .backgroundColor('#317AF7') + .justifyContent(FlexAlign.Center) + .width(100) + .height(100) + .borderRadius(30) + .onClick(() => { + this.animate = !this.animate; + // 第四步:闭包内通过状态变量改变UI界面 + // 这里可以写任何能改变UI的逻辑比如数组添加,显隐控制,系统会检测改变后的UI界面与之前的UI界面的差异,对有差异的部分添加动画 + // 组件一的rotate属性发生变化,所以会给组件一添加rotate旋转动画 + this.rotateValue = this.animate ? 90 : 0; + // 组件二的translate属性发生变化,所以会给组件二添加translate偏移动画 + this.translateX = this.animate ? 50 : 0; + // 父组件column的opacity属性有变化,会导致其子节点的透明度也变化,所以这里会给column和其子节点的透明度属性都加动画 + this.opacityValue = this.animate ? 0.6 : 1; + }) + + // 组件二 + Column() { + } + .justifyContent(FlexAlign.Center) + .width(100) + .height(100) + .backgroundColor('#D94838') + .borderRadius(30) + .opacity(this.opacityValue) + .translate({ x: this.translateX }) + .animation({ curve: curves.springMotion() }) + } + .width('100%') + .height('100%') + .justifyContent(FlexAlign.Center) + } +} +// [End attrAnimationDemo3] \ No newline at end of file diff --git a/ArkUIKit/Animation/entry/src/main/ets/pages/animation/template4/Index.ets b/ArkUIKit/Animation/entry/src/main/ets/pages/animation/template4/Index.ets new file mode 100644 index 0000000000000000000000000000000000000000..097b078a61a70430c3a43aaf477f18f22527714c --- /dev/null +++ b/ArkUIKit/Animation/entry/src/main/ets/pages/animation/template4/Index.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 KeyframeAnimateToDemo] +@Entry +@Component +struct KeyframeAnimateToDemo { + // 第一步: 声明相关状态变量 + @State rotateValue: number = 0; // 组件一旋转角度 + @State translateX: number = 0; // 组件二偏移量 + @State opacityValue: number = 1; // 组件二透明度 + // 第二步:将状态变量设置到相关可动画属性接口 + build() { + Row() { + // 组件一 + Column() { + } + .rotate({ angle: this.rotateValue }) + .backgroundColor('#317AF7') + .justifyContent(FlexAlign.Center) + .width(100) + .height(100) + .borderRadius(30) + .onClick(() => { + // 第三步:调用keyframeAnimateTo接口 + this.getUIContext()?.keyframeAnimateTo({ + iterations: 1 + }, [ + { + // 第一段关键帧动画时长为800ms,组件一顺时针旋转90度,组件二的透明度变从1变为0.6,组件二的translate从0位移到50 + duration: 800, + event: () => { + this.rotateValue = 90; + this.opacityValue = 0.6; + this.translateX = 50; + } + }, + { + // 第二段关键帧动画时长为500ms,组件一逆时针旋转90度恢复至0度,组件二的透明度变从0.6变为1,组件二的translate从50位移到0 + duration: 500, + event: () => { + this.rotateValue = 0; + this.opacityValue = 1; + this.translateX = 0; + } + } + ]); + }) + // 组件二 + Column() { + } + .justifyContent(FlexAlign.Center) + .width(100) + .height(100) + .backgroundColor('#D94838') + .borderRadius(30) + .opacity(this.opacityValue) + .translate({ x: this.translateX }) + } + .width('100%') + .height('100%') + .justifyContent(FlexAlign.Center) + } +} +// [End KeyframeAnimateToDemo] \ No newline at end of file diff --git a/ArkUIKit/Animation/entry/src/main/ets/pages/animationBlur/template1/BlurEffectsExample.ets b/ArkUIKit/Animation/entry/src/main/ets/pages/animationBlur/template1/BlurEffectsExample.ets new file mode 100644 index 0000000000000000000000000000000000000000..f9c5f75e94f0e78647715c53e15bb7cae4ce10a3 --- /dev/null +++ b/ArkUIKit/Animation/entry/src/main/ets/pages/animationBlur/template1/BlurEffectsExample.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. + */ +// [Start animationBlur_template1_start] +@Entry +@Component +struct BlurEffectsExample { + build() { + Column({ space: 10 }) { + Text('backdropBlur') + .width('90%') + .height('90%') + .fontSize(20) + .fontColor(Color.White) + .textAlign(TextAlign.Center) + .backdropBlur(10)// 对背景进行模糊 + .backgroundImage($r('app.media.bg')) + .backgroundImageSize({ width: 400, height: 300 }) + } + .width('100%') + .height('50%') + .margin({ top: 20 }) + } +} +// [End animationBlur_template1_start] \ No newline at end of file diff --git a/ArkUIKit/Animation/entry/src/main/ets/pages/animationBlur/template2/Index.ets b/ArkUIKit/Animation/entry/src/main/ets/pages/animationBlur/template2/Index.ets new file mode 100644 index 0000000000000000000000000000000000000000..4ddfd9752ef010272fdc9c657ab2430ff404b213 --- /dev/null +++ b/ArkUIKit/Animation/entry/src/main/ets/pages/animationBlur/template2/Index.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 animationBlur_template2_start] +import { common } from '@kit.AbilityKit'; + +@Entry +@Component +struct Index { + private context = this.getUIContext().getHostContext() as common.UIAbilityContext; + @State radius: number = 0; + @State text: string = ''; + @State y: Resource | string = this.context.resourceManager.getStringSync($r('app.string.animation_blur_text1').id); + + aboutToAppear() { + // $r('app.string.xxx')需要替换为开发着所需要的资源文件 + this.text = this.context.resourceManager.getStringSync($r('app.string.animation_blur_text2').id) + "\n" + this.context.resourceManager.getStringSync($r('app.string.animation_blur_text3').id) + this.y + + "\n" + this.context.resourceManager.getStringSync($r('app.string.animation_blur_text4').id) + this.radius; + } + + build() { + Flex({ direction: FlexDirection.Column, alignItems: ItemAlign.Center, justifyContent: FlexAlign.SpaceBetween }) { + Text(this.text) + .height(200) + .fontSize(20) + .fontWeight(FontWeight.Bold) + .fontFamily("cursive") + .fontStyle(FontStyle.Italic) + Image($r("app.media.bg")) + .blur(this.radius)// 使用blur接口为照片组件添加内容模糊效果 + .height('100%') + .width("100%") + .objectFit(ImageFit.Cover) + }.height('100%') + .width("100%") + .onTouch((event?: TouchEvent) => { + if (event) { + if (event.type === TouchType.Move) { + this.y = Number(event.touches[0].y.toString()).toString(); + this.radius = Number(this.y) / 10; // 根据跟手过程中的滑动距离修改模糊半径,配合模糊接口,形成跟手模糊效果 + } + if (event.type === TouchType.Up) { + this.radius = 0; + // $r('app.string.animation_blur_text1')需要替换为开发着所需要的资源文件 + this.y = this.context.resourceManager.getStringSync($r('app.string.animation_blur_text1').id); + } + } + // $r('app.string.xxx')需要替换为开发着所需要的资源文件 + this.text = this.context.resourceManager.getStringSync($r('app.string.animation_blur_text2').id) + "\n" + this.context.resourceManager.getStringSync($r('app.string.animation_blur_text3').id) + this.y + + "\n" + this.context.resourceManager.getStringSync($r('app.string.animation_blur_text4').id) + this.radius; + }) + } +} +// [End animationBlur_template2_start] \ No newline at end of file diff --git a/ArkUIKit/Animation/entry/src/main/ets/pages/animationBlur/template3/BackDropBlurStyleDemo.ets b/ArkUIKit/Animation/entry/src/main/ets/pages/animationBlur/template3/BackDropBlurStyleDemo.ets new file mode 100644 index 0000000000000000000000000000000000000000..d0aabb3e287da6fb344edb8d504db8796bf7599c --- /dev/null +++ b/ArkUIKit/Animation/entry/src/main/ets/pages/animationBlur/template3/BackDropBlurStyleDemo.ets @@ -0,0 +1,277 @@ +/* + * 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 animationBlur_template3_start] +@Entry +@Component +struct BackDropBlurStyleDemo { + build() { + Grid() { + GridItem() { + Column() { + Column() { + // $r('app.string.originalImage')需要替换为开发着所需要的资源文件 + Text($r('app.string.originalImage')) + .fontSize(20) + .fontColor(Color.White) + .textAlign(TextAlign.Center) + .width('100%') + .height('100%') + } + .height(100) + .aspectRatio(1) + .borderRadius(10) + // $r('app.media.bg')需要替换为开发着所需要的资源文件 + .backgroundImage($r('app.media.bg')) + + // $r('app.string.originalImage')需要替换为开发着所需要的资源文件 + Text($r('app.string.originalImage')) + .fontSize(12) + .fontColor(Color.Black) + } + .height('100%') + .justifyContent(FlexAlign.Start) + } + .width(200) + .height(200) + + GridItem() { + Column() { + Column() { + Text('Thin') + .fontSize(20) + .fontColor(Color.White) + .textAlign(TextAlign.Center) + .width('100%') + .height('100%') + } + .height(100) + .aspectRatio(1) + .borderRadius(10) + // $r('app.media.bg')需要替换为开发着所需要的资源文件 + .backgroundImage($r('app.media.bg')) + // BlurStyle.Thin: 为组件添加轻薄材质模糊效果 + // ThemeColorMode.LIGHT: 固定使用浅色模式效果 + // AdaptiveColor.DEFAULT: 不使用取色模糊,使用默认的颜色作为蒙版颜色 + // scale: 背景材质模糊效果程度,默认值是1 + .backgroundBlurStyle(BlurStyle.Thin, { + colorMode: ThemeColorMode.LIGHT, + adaptiveColor: AdaptiveColor.DEFAULT, + scale: 0.1 + }) + + Text('Thin') + .fontSize(12) + .fontColor(Color.Black) + } + .height('100%') + .justifyContent(FlexAlign.Start) + } + .width(200) + .height(200) + + GridItem() { + Column() { + Column() { + Text('Regular') + .fontSize(20) + .fontColor(Color.White) + .textAlign(TextAlign.Center) + .width('100%') + .height('100%') + } + .height(100) + .aspectRatio(1) + .borderRadius(10) + // $r('app.media.bg')需要替换为开发着所需要的资源文件 + .backgroundImage($r('app.media.bg')) + .backgroundBlurStyle(BlurStyle.Regular, { + colorMode: ThemeColorMode.LIGHT, + adaptiveColor: AdaptiveColor.DEFAULT, + scale: 0.1 + }) + + Text('Regular') + .fontSize(12) + .fontColor(Color.Black) + } + .height('100%') + .justifyContent(FlexAlign.Start) + } + .width(200) + .height(200) + + GridItem() { + Column() { + Column() { + Text('Thick') + .fontSize(20) + .fontColor(Color.White) + .textAlign(TextAlign.Center) + .width('100%') + .height('100%') + } + .height(100) + .aspectRatio(1) + .borderRadius(10) + // $r('app.media.bg')需要替换为开发着所需要的资源文件 + .backgroundImage($r('app.media.bg')) + .backgroundBlurStyle(BlurStyle.Thick, { + colorMode: ThemeColorMode.LIGHT, + adaptiveColor: AdaptiveColor.DEFAULT, + scale: 0.1 + }) + + Text('Thick') + .fontSize(12) + .fontColor(Color.Black) + } + .height('100%') + .justifyContent(FlexAlign.Start) + } + .width(200) + .height(200) + + GridItem() { + Column() { + Column() { + Text('BACKGROUND_THIN') + .fontSize(12) + .fontColor(Color.White) + .textAlign(TextAlign.Center) + .width('100%') + .height('100%') + } + .height(100) + .aspectRatio(1) + .borderRadius(10) + // $r('app.media.bg')需要替换为开发着所需要的资源文件 + .backgroundImage($r('app.media.bg')) + .backgroundBlurStyle(BlurStyle.BACKGROUND_THIN, { + colorMode: ThemeColorMode.LIGHT, + adaptiveColor: AdaptiveColor.DEFAULT, + scale: 0.1 + }) + + Text('BACKGROUND_THIN') + .fontSize(12) + .fontColor(Color.Black) + } + .height('100%') + .justifyContent(FlexAlign.Start) + } + .width(200) + .height(200) + + GridItem() { + Column() { + Column() { + Text('BACKGROUND_REGULAR') + .fontSize(12) + .fontColor(Color.White) + .textAlign(TextAlign.Center) + .width('100%') + .height('100%') + } + .height(100) + .aspectRatio(1) + .borderRadius(10) + // $r('app.media.bg')需要替换为开发着所需要的资源文件 + .backgroundImage($r('app.media.bg')) + .backgroundBlurStyle(BlurStyle.BACKGROUND_REGULAR, { + colorMode: ThemeColorMode.LIGHT, + adaptiveColor: AdaptiveColor.DEFAULT, + scale: 0.1 + }) + + Text('BACKGROUND_REGULAR') + .fontSize(12) + .fontColor(Color.Black) + } + .height('100%') + .justifyContent(FlexAlign.Start) + } + .width(200) + .height(200) + + GridItem() { + Column() { + Column() { + Text('BACKGROUND_THICK') + .fontSize(12) + .fontColor(Color.White) + .textAlign(TextAlign.Center) + .width('100%') + .height('100%') + } + .height(100) + .aspectRatio(1) + .borderRadius(10) + // $r('app.media.bg')需要替换为开发着所需要的资源文件 + .backgroundImage($r('app.media.bg')) + .backgroundBlurStyle(BlurStyle.BACKGROUND_THICK, { + colorMode: ThemeColorMode.LIGHT, + adaptiveColor: AdaptiveColor.DEFAULT, + scale: 0.1 + }) + + Text('BACKGROUND_THICK') + .fontSize(12) + .fontColor(Color.Black) + } + .height('100%') + .justifyContent(FlexAlign.Start) + } + .width(200) + .height(200) + + GridItem() { + Column() { + Column() { + Text('BACKGROUND_ULTRA_THICK') + .fontSize(12) + .fontColor(Color.White) + .textAlign(TextAlign.Center) + .width('100%') + .height('100%') + } + .height(100) + .aspectRatio(1) + .borderRadius(10) + // $r('app.media.bg')需要替换为开发着所需要的资源文件 + .backgroundImage($r('app.media.bg')) + .backgroundBlurStyle(BlurStyle.BACKGROUND_ULTRA_THICK, { + colorMode: ThemeColorMode.LIGHT, + adaptiveColor: AdaptiveColor.DEFAULT, + scale: 0.1 + }) + + Text('BACKGROUND_ULTRA_THICK') + .fontSize(12) + .fontColor(Color.Black) + } + .height('100%') + .justifyContent(FlexAlign.Start) + } + .width(200) + .height(200) + } + .columnsTemplate('1fr 1fr') + .rowsTemplate('1fr 1fr 1fr 1fr') + .width('100%') + .height('100%') + .margin({ top: 40 }) + } +} +// [End animationBlur_template3_start] \ No newline at end of file diff --git a/ArkUIKit/Animation/entry/src/main/ets/pages/animationBlur/template4/ForegroundBlurStyleDemo.ets b/ArkUIKit/Animation/entry/src/main/ets/pages/animationBlur/template4/ForegroundBlurStyleDemo.ets new file mode 100644 index 0000000000000000000000000000000000000000..c6f3cc6ece3b962b4c4d74df35d43fa9d72fce9c --- /dev/null +++ b/ArkUIKit/Animation/entry/src/main/ets/pages/animationBlur/template4/ForegroundBlurStyleDemo.ets @@ -0,0 +1,277 @@ +/* + * 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 animationBlur_template4_start] +@Entry +@Component +struct ForegroundBlurStyleDemo { + build() { + Grid() { + GridItem() { + Column() { + Column() { + // $r('app.string.originalImage')需要替换为开发着所需要的资源文件 + Text($r('app.string.originalImage')) + .fontSize(20) + .fontColor(Color.White) + .textAlign(TextAlign.Center) + .width('100%') + .height('100%') + } + .height(100) + .aspectRatio(1) + .borderRadius(10) + // $r('app.media.bg')需要替换为开发着所需要的资源文件 + .backgroundImage($r('app.media.bg')) + + // $r('app.string.originalImage')需要替换为开发着所需要的资源文件 + Text($r('app.string.originalImage')) + .fontSize(12) + .fontColor(Color.Black) + } + .height('100%') + .justifyContent(FlexAlign.Start) + } + .width(200) + .height(200) + + GridItem() { + Column() { + Column() { + Text('Thin') + .fontSize(20) + .fontColor(Color.White) + .textAlign(TextAlign.Center) + .width('100%') + .height('100%') + } + .height(100) + .aspectRatio(1) + .borderRadius(10) + // $r('app.media.bg')需要替换为开发着所需要的资源文件 + .backgroundImage($r('app.media.bg')) + // BlurStyle.Thin: 为组件添加轻薄材质模糊效果 + // ThemeColorMode.LIGHT: 固定使用浅色模式效果 + // AdaptiveColor.DEFAULT: 不使用取色模糊,使用默认的颜色作为蒙版颜色 + // scale: 背景材质模糊效果程度,默认值是1 + .foregroundBlurStyle(BlurStyle.Thin, { + colorMode: ThemeColorMode.LIGHT, + adaptiveColor: AdaptiveColor.DEFAULT, + scale: 0.1 + }) + + Text('Thin') + .fontSize(12) + .fontColor(Color.Black) + } + .height('100%') + .justifyContent(FlexAlign.Start) + } + .width(200) + .height(200) + + GridItem() { + Column() { + Column() { + Text('Regular') + .fontSize(20) + .fontColor(Color.White) + .textAlign(TextAlign.Center) + .width('100%') + .height('100%') + } + .height(100) + .aspectRatio(1) + .borderRadius(10) + // $r('app.media.bg')需要替换为开发着所需要的资源文件 + .backgroundImage($r('app.media.bg')) + .foregroundBlurStyle(BlurStyle.Regular, { + colorMode: ThemeColorMode.LIGHT, + adaptiveColor: AdaptiveColor.DEFAULT, + scale: 0.1 + }) + + Text('Regular') + .fontSize(12) + .fontColor(Color.Black) + } + .height('100%') + .justifyContent(FlexAlign.Start) + } + .width(200) + .height(200) + + GridItem() { + Column() { + Column() { + Text('Thick') + .fontSize(20) + .fontColor(Color.White) + .textAlign(TextAlign.Center) + .width('100%') + .height('100%') + } + .height(100) + .aspectRatio(1) + .borderRadius(10) + // $r('app.media.bg')需要替换为开发着所需要的资源文件 + .backgroundImage($r('app.media.bg')) + .foregroundBlurStyle(BlurStyle.Thick, { + colorMode: ThemeColorMode.LIGHT, + adaptiveColor: AdaptiveColor.DEFAULT, + scale: 0.1 + }) + + Text('Thick') + .fontSize(12) + .fontColor(Color.Black) + } + .height('100%') + .justifyContent(FlexAlign.Start) + } + .width(200) + .height(200) + + GridItem() { + Column() { + Column() { + Text('BACKGROUND_THIN') + .fontSize(12) + .fontColor(Color.White) + .textAlign(TextAlign.Center) + .width('100%') + .height('100%') + } + .height(100) + .aspectRatio(1) + .borderRadius(10) + // $r('app.media.bg')需要替换为开发着所需要的资源文件 + .backgroundImage($r('app.media.bg')) + .foregroundBlurStyle(BlurStyle.BACKGROUND_THIN, { + colorMode: ThemeColorMode.LIGHT, + adaptiveColor: AdaptiveColor.DEFAULT, + scale: 0.1 + }) + + Text('BACKGROUND_THIN') + .fontSize(12) + .fontColor(Color.Black) + } + .height('100%') + .justifyContent(FlexAlign.Start) + } + .width(200) + .height(200) + + GridItem() { + Column() { + Column() { + Text('BACKGROUND_REGULAR') + .fontSize(12) + .fontColor(Color.White) + .textAlign(TextAlign.Center) + .width('100%') + .height('100%') + } + .height(100) + .aspectRatio(1) + .borderRadius(10) + // $r('app.media.bg')需要替换为开发着所需要的资源文件 + .backgroundImage($r('app.media.bg')) + .foregroundBlurStyle(BlurStyle.BACKGROUND_REGULAR, { + colorMode: ThemeColorMode.LIGHT, + adaptiveColor: AdaptiveColor.DEFAULT, + scale: 0.1 + }) + + Text('BACKGROUND_REGULAR') + .fontSize(12) + .fontColor(Color.Black) + } + .height('100%') + .justifyContent(FlexAlign.Start) + } + .width(200) + .height(200) + + GridItem() { + Column() { + Column() { + Text('BACKGROUND_THICK') + .fontSize(12) + .fontColor(Color.White) + .textAlign(TextAlign.Center) + .width('100%') + .height('100%') + } + .height(100) + .aspectRatio(1) + .borderRadius(10) + // $r('app.media.bg')需要替换为开发着所需要的资源文件 + .backgroundImage($r('app.media.bg')) + .foregroundBlurStyle(BlurStyle.BACKGROUND_THICK, { + colorMode: ThemeColorMode.LIGHT, + adaptiveColor: AdaptiveColor.DEFAULT, + scale: 0.1 + }) + + Text('BACKGROUND_THICK') + .fontSize(12) + .fontColor(Color.Black) + } + .height('100%') + .justifyContent(FlexAlign.Start) + } + .width(200) + .height(200) + + GridItem() { + Column() { + Column() { + Text('BACKGROUND_ULTRA_THICK') + .fontSize(12) + .fontColor(Color.White) + .textAlign(TextAlign.Center) + .width('100%') + .height('100%') + } + .height(100) + .aspectRatio(1) + .borderRadius(10) + // $r('app.media.bg')需要替换为开发着所需要的资源文件 + .backgroundImage($r('app.media.bg')) + .foregroundBlurStyle(BlurStyle.BACKGROUND_ULTRA_THICK, { + colorMode: ThemeColorMode.LIGHT, + adaptiveColor: AdaptiveColor.DEFAULT, + scale: 0.1 + }) + + Text('BACKGROUND_ULTRA_THICK') + .fontSize(12) + .fontColor(Color.Black) + } + .height('100%') + .justifyContent(FlexAlign.Start) + } + .width(200) + .height(200) + } + .columnsTemplate('1fr 1fr') + .rowsTemplate('1fr 1fr 1fr 1fr') + .width('100%') + .height('100%') + .margin({ top: 40 }) + } +} +// [End animationBlur_template4_start] \ No newline at end of file diff --git a/ArkUIKit/Animation/entry/src/main/ets/pages/animationBlur/template5/MotionBlurTest.ets b/ArkUIKit/Animation/entry/src/main/ets/pages/animationBlur/template5/MotionBlurTest.ets new file mode 100644 index 0000000000000000000000000000000000000000..b004454b9106e9f4ad98f4148bab5a7a72d69b34 --- /dev/null +++ b/ArkUIKit/Animation/entry/src/main/ets/pages/animationBlur/template5/MotionBlurTest.ets @@ -0,0 +1,60 @@ +/* + * 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 animationBlur_template5_start] +import { curves } from '@kit.ArkUI'; + +@Entry +@Component +struct motionBlurTest { + @State widthSize: number = 400; + @State heightSize: number = 320; + @State flag: boolean = true; + @State radius: number = 0; + @State x: number = 0; + @State y: number = 0; + + build() { + Column() { + Column() { + // $r('app.media.testImg')需要替换为开发着所需要的资源文件 + Image($r('app.media.testImg')) + .width(this.widthSize) + .height(this.heightSize) + .onClick(() => { + this.radius = 5; + this.x = 0.5; + this.y = 0.5; + if (this.flag) { + this.widthSize = 100; + this.heightSize = 80; + } else { + this.widthSize = 400; + this.heightSize = 320; + } + this.flag = !this.flag; + }) + .animation({ + duration: 2000, + curve: curves.springCurve(10, 1, 228, 30), + onFinish: () => { + this.radius = 0; + } + }) + .motionBlur({ radius: this.radius, anchor: { x: this.x, y: this.y } }) + } + }.width('100%').margin({ top: 5 }) + } +} +// [End animationBlur_template5_start] \ No newline at end of file diff --git a/ArkUIKit/Animation/entry/src/main/ets/pages/animator/template1/Index.ets b/ArkUIKit/Animation/entry/src/main/ets/pages/animator/template1/Index.ets new file mode 100644 index 0000000000000000000000000000000000000000..b4650375cfeec49f1b5db75086089cc5d6d0c2ab --- /dev/null +++ b/ArkUIKit/Animation/entry/src/main/ets/pages/animator/template1/Index.ets @@ -0,0 +1,175 @@ +/* + * 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 { Animator as animator, AnimatorResult } from '@kit.ArkUI'; + +@Entry +@Component +struct AnimatorTest { + private TAG: string = '[AnimatorTest]'; + private backAnimator: AnimatorResult | undefined = undefined; + private flag: boolean = false; + @State wid: number = 100; + @State hei: number = 100; + + create() { + this.backAnimator = animator.create({ + // 建议使用 this.getUIContext.createAnimator()接口 + duration: 2000, + easing: "ease", + delay: 0, + fill: "forwards", + direction: 'normal', + iterations: 1, + begin: 100, + end: 200 + }) + this.backAnimator.onFinish = () => { + this.flag = true + console.info(this.TAG, 'backAnimator onFinish') + } + this.backAnimator.onRepeat = () => { + console.info(this.TAG, 'backAnimator repeat') + } + this.backAnimator.onCancel = () => { + console.info(this.TAG, 'backAnimator cancel') + } + this.backAnimator.onFrame = (value: number) => { + this.wid = value + this.hei = value + } + } + + aboutToDisappear() { + // 自定义组件消失时调用finish使未完成的动画结束,避免动画继续运行。 + // 由于backAnimator在onframe中引用了this, this中保存了backAnimator, + // 在自定义组件消失时应该将保存在组件中的backAnimator置空,避免内存泄漏 + this.backAnimator?.finish(); + this.backAnimator = undefined; + } + + build() { + Column() { + Column() { + Column() + .width(this.wid) + .height(this.hei) + .backgroundColor(Color.Red) + } + .width('100%') + .height(300) + + Column() { + Row() { + Button('create') + .fontSize(30) + .fontColor(Color.Black) + .onClick(() => { + this.create() + }) + } + .padding(10) + + Row() { + Button('play') + .fontSize(30) + .fontColor(Color.Black) + .onClick(() => { + this.flag = false + if (this.backAnimator) { + this.backAnimator.play() + } + }) + } + .padding(10) + + Row() { + Button('pause') + .fontSize(30) + .fontColor(Color.Black) + .onClick(() => { + if (this.backAnimator) { + this.backAnimator.pause() + } + }) + } + .padding(10) + + Row() { + Button('finish') + .fontSize(30) + .fontColor(Color.Black) + .onClick(() => { + this.flag = true + if (this.backAnimator) { + this.backAnimator.finish() + } + }) + } + .padding(10) + + Row() { + Button('reverse') + .fontSize(30) + .fontColor(Color.Black) + .onClick(() => { + this.flag = false + if (this.backAnimator) { + this.backAnimator.reverse() + } + }) + } + .padding(10) + + Row() { + Button('cancel') + .fontSize(30) + .fontColor(Color.Black) + .onClick(() => { + if (this.backAnimator) { + this.backAnimator.cancel() + } + }) + } + .padding(10) + + Row() { + Button('reset') + .fontSize(30) + .fontColor(Color.Black) + .onClick(() => { + if (this.flag) { + this.flag = false + if (this.backAnimator) { + this.backAnimator.reset({ + duration: 3000, + easing: "ease-in", + delay: 0, + fill: "forwards", + direction: "alternate", + iterations: 3, + begin: 100, + end: 300 + }) + } + } else { + console.info(this.TAG, 'Animation not ended') + } + }) + } + .padding(10) + } + } + } +} \ No newline at end of file diff --git a/ArkUIKit/Animation/entry/src/main/ets/pages/animator/template2/Index.ets b/ArkUIKit/Animation/entry/src/main/ets/pages/animator/template2/Index.ets new file mode 100644 index 0000000000000000000000000000000000000000..e2fe7a514330fc64ff8f90c1d61287146178236d --- /dev/null +++ b/ArkUIKit/Animation/entry/src/main/ets/pages/animator/template2/Index.ets @@ -0,0 +1,106 @@ +/* + * 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 { AnimatorResult, SimpleAnimatorOptions } from '@kit.ArkUI'; + +@Entry +@Component +struct AnimatorTest { + private TAG: string = '[AnimatorTest]'; + private backAnimator: AnimatorResult | undefined = undefined; + private flag: boolean = false; + @State translate_: number = 0; + + create() { + this.backAnimator = this.getUIContext()?.createAnimator( + new SimpleAnimatorOptions(0, 100) + ) + this.backAnimator.onFinish = ()=> { + this.flag = true + console.info(this.TAG, 'backAnimator onFinish') + } + this.backAnimator.onFrame = (value:number)=> { + this.translate_ = value + } + } + + aboutToDisappear() { + // 由于backAnimator在onFrame中引用了this, this中保存了backAnimator, + // 在自定义组件消失时应该将保存在组件中的backAnimator置空,避免内存泄漏 + this.backAnimator = undefined; + } + + build() { + Column() { + Column() { + Column() + .width(100) + .height(100) + .translate({x: this.translate_}) + .backgroundColor(Color.Green) + } + .width('100%') + .height(300) + + Column() { + Column() { + Button('create') + .fontSize(30) + .fontColor(Color.Black) + .onClick(() => { + this.create() + }) + } + .padding(10) + + Column() { + Button('play') + .fontSize(30) + .fontColor(Color.Black) + .onClick(() => { + this.flag = false + if(this.backAnimator){ + this.backAnimator.play() + } + }) + } + .padding(10) + + Column() { + Button('reset') + .fontSize(30) + .fontColor(Color.Black) + .onClick(() => { + if (this.flag) { + this.flag = false + if(this.backAnimator){ + this.backAnimator.reset( + new SimpleAnimatorOptions(0, -100) + .duration(2000) + .easing("ease-in") + .fill(FillMode.Forwards) + .direction(PlayMode.Alternate) + .iterations(2) + ) + } + } else { + console.info(this.TAG, 'Animation not ended') + } + }) + } + .padding(10) + } + } + } +} \ No newline at end of file diff --git a/ArkUIKit/Animation/entry/src/main/ets/pages/animator/template3/Index.ets b/ArkUIKit/Animation/entry/src/main/ets/pages/animator/template3/Index.ets new file mode 100644 index 0000000000000000000000000000000000000000..d15268020b967fb974e74646d980a5cfbd873fb9 --- /dev/null +++ b/ArkUIKit/Animation/entry/src/main/ets/pages/animator/template3/Index.ets @@ -0,0 +1,96 @@ +/* + * 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 animator_template3_start] +import { AnimatorOptions, AnimatorResult } from '@kit.ArkUI'; +import resource from '../../../common/resource'; + +@Entry +@Component +struct Index { + @State animatorOptions: AnimatorResult | undefined = undefined; + @State animatorStatus: Resource = $r('app.string.create'); + begin: number = 0; + end: number = 300; + topWidth: number = 150; + bottomHeight: number = 100; + g: number = 0.18; + animatorOption: AnimatorOptions = { + duration: 4000, + delay: 0, + easing: 'linear', + iterations: 1, + fill: "forwards", + direction: 'normal', + begin: this.begin, + end: this.end + }; + @State translateX: number = 0; + @State translateY: number = 0; + + onPageShow(): void { + this.animatorOptions = this.getUIContext().createAnimator(this.animatorOption); + this.animatorOptions.onFrame = (progress: number) => { + this.translateX = progress; + if (progress > this.topWidth && this.translateY < this.bottomHeight) { + this.translateY = Math.pow(progress - this.topWidth, 2) * this.g; + } + } + this.animatorOptions.onCancel = () => { + this.animatorStatus = $r('app.string.cancel'); + } + this.animatorOptions.onFinish = () => { + this.animatorStatus = $r('app.string.complete'); + } + this.animatorOptions.onRepeat = () => { + console.log('repeat play'); + } + } + + onPageHide(): void { + this.animatorOptions = undefined; + } + + build() { + Column() { + Column({ space: 30 }) { + Button($r('app.string.play')).onClick(() => { + this.animatorOptions?.play(); + this.animatorStatus = $r('app.string.playing'); + }).width(80).height(35) + Button($r('app.string.reset')).onClick(() => { + this.translateX = 0; + this.translateY = 0; + }).width(80).height(35) + Button($r('app.string.pause')).onClick(() => { + this.animatorOptions?.pause(); + this.animatorStatus = $r('app.string.pause'); + }).width(80).height(35) + }.width('100%').height('25%') + + Stack() { + Button() + .width(60) + .height(60) + .translate({ x: this.translateX, y: this.translateY }) + } + .width('100%') + .height('45%') + .align(Alignment.Start) + + Text(resource.resourceToString($r('app.string.animatorStatus')) + resource.resourceToString(this.animatorStatus)) + }.width('100%').height('100%') + } +} +// [End animator_template3_start] \ No newline at end of file diff --git a/ArkUIKit/Animation/entry/src/main/ets/pages/animator/template4/Index.ets b/ArkUIKit/Animation/entry/src/main/ets/pages/animator/template4/Index.ets new file mode 100644 index 0000000000000000000000000000000000000000..8ea5d93e2b57fa8d1b93f876b2d7630dcaa2481b --- /dev/null +++ b/ArkUIKit/Animation/entry/src/main/ets/pages/animator/template4/Index.ets @@ -0,0 +1,107 @@ +/* + * 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 animator_template4_import_start] +import { AnimatorOptions, AnimatorResult } from '@kit.ArkUI'; +// [End animator_template4_import_start] +import resource from '../../../common/resource'; + +@Entry +@Component +struct Index { + @State animatorOptions: AnimatorResult | undefined = undefined; + @State animatorStatus: Resource = $r('app.string.create'); + begin: number = 0; + end: number = 300; + topWidth: number = 150; + bottomHeight: number = 100; + g: number = 0.18; + animatorOption: AnimatorOptions = { + duration: 4000, + delay: 0, + easing: 'linear', + iterations: 1, + fill: "forwards", + direction: 'normal', + begin: this.begin, + end: this.end + }; + @State translateX: number = 0; + @State translateY: number = 0; + + // [Start animator_template4_show_start] + onPageShow(): void { + this.animatorOptions = this.getUIContext().createAnimator(this.animatorOption); + this.animatorOptions.onFrame = (progress: number) => { + this.translateX = progress; + if (progress > this.topWidth && this.translateY < this.bottomHeight) { + this.translateY = Math.pow(progress - this.topWidth, 2) * this.g; + } + } + //动画取消时执行方法 + this.animatorOptions.onCancel = () => { + this.animatorStatus = $r('app.string.cancel'); + } + //动画完成时执行方法 + this.animatorOptions.onFinish = () => { + this.animatorStatus = $r('app.string.complete'); + } + //动画重复播放时执行方法 + this.animatorOptions.onRepeat = () => { + console.log('repeat play'); + } + } + // [End animator_template4_show_start] + + // [Start animator_template4_hide_start] + onPageHide(): void { + this.animatorOptions = undefined; + } + // [End animator_template4_hide_start] + + build() { + Column() { + Column({ space: 30 }) { + // [Start animator_template4_buttons_start] + Button($r('app.string.play')).onClick(() => { + this.animatorOptions?.play(); + this.animatorStatus = $r('app.string.playing'); + }).width(80).height(35) + Button($r('app.string.reset')).onClick(() => { + this.translateX = 0; + this.translateY = 0; + }).width(80).height(35) + Button($r('app.string.pause')).onClick(() => { + this.animatorOptions?.pause(); + this.animatorStatus = $r('app.string.pause'); + }).width(80).height(35) + // [End animator_template4_buttons_start] + }.width('100%').height('25%') + + Stack() { + // [Start animator_template4_button_start] + Button() + .width(60) + .height(60) + .translate({ x: this.translateX, y: this.translateY }) + // [End animator_template4_button_start] + } + .width('100%') + .height('45%') + .align(Alignment.Start) + + Text(resource.resourceToString($r('app.string.animatorStatus')) + resource.resourceToString(this.animatorStatus)) + }.width('100%').height('100%') + } +} \ No newline at end of file diff --git a/ArkUIKit/Animation/entry/src/main/ets/pages/cohesion/template1/Index.ets b/ArkUIKit/Animation/entry/src/main/ets/pages/cohesion/template1/Index.ets new file mode 100644 index 0000000000000000000000000000000000000000..bc6f04d7d93d9859e3089019dd0294af4ba6e0b3 --- /dev/null +++ b/ArkUIKit/Animation/entry/src/main/ets/pages/cohesion/template1/Index.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 animation_template1_start] +import { curves } from '@kit.ArkUI'; + +class SetAnimationVariables { + isAnimation: boolean = true + + set(): void { + this.isAnimation = !this.isAnimation; + } +} + +@Entry +@Component +struct AnimationToAnimationDemo { + // 第一步:声明相关状态变量 + @State setAnimation: SetAnimationVariables = new SetAnimationVariables(); + + build() { + Column() { + Text('ArkUI') + .fontWeight(FontWeight.Bold) + .fontSize(12) + .fontColor(Color.White) + .textAlign(TextAlign.Center) + .borderRadius(10) + .backgroundColor(0xf56c6c) + .width(100) + .height(100) + .scale({ + // 第二步:将状态变量设置到相关可动画属性接口 + x: this.setAnimation.isAnimation ? 2 : 1, + y: this.setAnimation.isAnimation ? 2 : 1 + }) + .animation({ curve: curves.springMotion(0.4, 0.8) }) // 第四步:通过animation接口开启动画,动画终点值改变时,系统自动添加衔接动画 + + Button('Click') + .margin({ top: 200 }) + .onClick(() => { + // 第三步:通过点击事件改变状态变量值,影响可动画属性值 + this.setAnimation.set() + }) + } + .width('100%') + .height('100%') + .justifyContent(FlexAlign.Center) + } +} +// [End animation_template1_start] \ No newline at end of file diff --git a/ArkUIKit/Animation/entry/src/main/ets/pages/cohesion/template2/Index.ets b/ArkUIKit/Animation/entry/src/main/ets/pages/cohesion/template2/Index.ets new file mode 100644 index 0000000000000000000000000000000000000000..9b5746a9c9a467bc41893c97862599684fbffd75 --- /dev/null +++ b/ArkUIKit/Animation/entry/src/main/ets/pages/cohesion/template2/Index.ets @@ -0,0 +1,71 @@ +/* + * 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 animation_template2_start] +import { curves } from '@kit.ArkUI'; + +@Entry +@Component +struct SpringMotionDemo { + // 第一步:声明相关状态变量 + @State positionX: number = 100; + @State positionY: number = 100; + diameter: number = 50; + + build() { + Column() { + Row() { + Circle({ width: this.diameter, height: this.diameter }) + .fill(Color.Blue) + .position({ x: this.positionX, y: this.positionY })// 第二步:将状态变量设置到相关可动画属性接口 + .onTouch((event?: TouchEvent) => { + // 第三步:在跟手过程改变状态变量值,并且采用responsiveSpringMotion动画运动到新的值 + if (event) { + if (event.type === TouchType.Move) { + // 跟手过程,使用responsiveSpringMotion曲线 + this.getUIContext()?.animateTo({ curve: curves.responsiveSpringMotion() }, () => { + // 减去半径,以使球的中心运动到手指位置 + this.positionX = event.touches[0].windowX - this.diameter / 2; + this.positionY = event.touches[0].windowY - this.diameter / 2; + console.info(`move, animateTo x:${this.positionX}, y:${this.positionY}`); + }) + } else if (event.type === TouchType.Up) { + // 第四步:在离手过程设定状态变量终点值,并且用springMotion动画运动到新的值,springMotion动画将继承跟手阶段的动画速度 + this.getUIContext()?.animateTo({ curve: curves.springMotion() }, () => { + this.positionX = 100; + this.positionY = 100; + console.info(`touchUp, animateTo x:100, y:100`); + }) + } + } + }) + } + .width('100%').height("80%") + .clip(true) // 如果球超出父组件范围,使球不可见 + .backgroundColor(Color.Orange) + + Flex({ direction: FlexDirection.Row, alignItems: ItemAlign.Start, justifyContent: FlexAlign.Center }) { + Text("拖动小球").fontSize(16) + } + .width('100%') + + Row() { + Text('点击位置: [x: ' + Math.round(this.positionX) + ', y:' + Math.round(this.positionY) + ']').fontSize(16) + } + .padding(10) + .width('100%') + }.height('100%').width('100%') + } +} +// [End animation_template2_start] \ No newline at end of file diff --git a/ArkUIKit/Animation/entry/src/main/ets/pages/common/Index.ets b/ArkUIKit/Animation/entry/src/main/ets/pages/common/Index.ets new file mode 100644 index 0000000000000000000000000000000000000000..02c5c6b987280c6731d3e40af7c56c416176a3af --- /dev/null +++ b/ArkUIKit/Animation/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/Animation/entry/src/main/ets/pages/compTransition/template1/Index.ets b/ArkUIKit/Animation/entry/src/main/ets/pages/compTransition/template1/Index.ets new file mode 100644 index 0000000000000000000000000000000000000000..3882e01414f1fdf48b5df9b45993c783f3025342 --- /dev/null +++ b/ArkUIKit/Animation/entry/src/main/ets/pages/compTransition/template1/Index.ets @@ -0,0 +1,44 @@ +/* + * 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. + */ +@Entry +@Component +struct TransitionEffectExample1 { + @State flag: boolean = true; + @State show: string = 'show'; + + build() { + Column() { + Button(this.show).width(80).height(30).margin(30) + .onClick(() => { + // 点击Button控制Image的显示和消失 + if (this.flag) { + this.show = 'hide'; + } else { + this.show = 'show'; + } + this.flag = !this.flag; + }) + if (this.flag) { + // Image的显示和消失配置为相同的过渡效果(出现和消失互为逆过程) + // 出现时从指定的透明度为0、绕z轴旋转180°的状态,变为默认的透明度为1、旋转角为0的状态,透明度与旋转动画时长都为2000ms + // 消失时从默认的透明度为1、旋转角为0的状态,变为指定的透明度为0、绕z轴旋转180°的状态,透明度与旋转动画时长都为2000ms + Image($r('app.media.testImg')).width(200).height(200) + .transition(TransitionEffect.OPACITY.animation({ duration: 2000, curve: Curve.Ease }).combine( + TransitionEffect.rotate({ z: 1, angle: 180 }) + )) + } + }.width('100%') + } +} \ No newline at end of file diff --git a/ArkUIKit/Animation/entry/src/main/ets/pages/compTransition/template2/Index.ets b/ArkUIKit/Animation/entry/src/main/ets/pages/compTransition/template2/Index.ets new file mode 100644 index 0000000000000000000000000000000000000000..784df84f6931e39aad853f4b492d469d6f1d7492 --- /dev/null +++ b/ArkUIKit/Animation/entry/src/main/ets/pages/compTransition/template2/Index.ets @@ -0,0 +1,63 @@ +/* + * 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. + */ +@Entry +@Component +struct TransitionEffectExample2 { + @State flag: boolean = true; + @State show: string = 'show'; + + build() { + Column() { + Button(this.show).width(80).height(30).margin(30) + .onClick(() => { + // 点击Button控制Image的显示和消失 + if (this.flag) { + this.show = 'hide'; + } else { + this.show = 'show'; + } + this.getUIContext().animateTo({ duration: 2000 }, () => { + // 第一张图的TransitionEffect包含了animation,transition的动画参数由TransitionEffect指定 + // 第二张图的TransitionEffect不包含animation,transition的动画参数由animateTo指定 + this.flag = !this.flag; + }); + }) + if (this.flag) { + // Image的显示和消失配置为不同的过渡效果 + // 出现时做从指定的透明度为0变为默认的透明度1的动画,该动画时长为1000ms,以及做从指定的绕z轴旋转180°变为默认的旋转角为0的动画,该动画1000ms后播放,时长为1000ms + // 消失时做从默认的透明度为1变为指定的透明度0的动画,该动画1000ms后播放,时长为1000ms,以及做从默认的旋转角0变为指定的绕z轴旋转180°的动画,该动画时长为1000ms + Image($r('app.media.testImg')).width(200).height(200) + .transition( + TransitionEffect.asymmetric( + TransitionEffect.OPACITY.animation({ duration: 1000 }).combine( + TransitionEffect.rotate({ z: 1, angle: 180 }).animation({ delay: 1000, duration: 1000 })) + , + TransitionEffect.OPACITY.animation({ delay: 1000, duration: 1000 }).combine( + TransitionEffect.rotate({ z: 1, angle: 180 }).animation({ duration: 1000 })) + ) + ) + // 出现时做从x方向和y方向scale都为0变为默认的x方向和y方向scale都为1的动画,该动画时长为animateTo中指定的2000ms + // 消失时无转场效果 + Image($r('app.media.testImg')).width(200).height(200).margin({ top: 100 }) + .transition( + TransitionEffect.asymmetric( + TransitionEffect.scale({ x: 0, y: 0 }), + TransitionEffect.IDENTITY + ) + ) + } + }.width('100%') + } +} \ No newline at end of file diff --git a/ArkUIKit/Animation/entry/src/main/ets/pages/compTransition/template3/Index.ets b/ArkUIKit/Animation/entry/src/main/ets/pages/compTransition/template3/Index.ets new file mode 100644 index 0000000000000000000000000000000000000000..0a6234142ee5974171548614189043059137822f --- /dev/null +++ b/ArkUIKit/Animation/entry/src/main/ets/pages/compTransition/template3/Index.ets @@ -0,0 +1,60 @@ +/* + * 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. + */ +@Entry +@Component +struct TransitionEffectExample3 { + @State flag: boolean = true; + @State show: string = 'show'; + + build() { + Column() { + Button(this.show).width(80).height(30).margin(30) + .onClick(() => { + // 点击Button控制Image的显示和消失 + if (this.flag) { + this.show = 'hide'; + } else { + this.show = 'show'; + } + this.flag = !this.flag; + }) + if (this.flag) { + // 改flag条件时,会触发id为"column1"、"image1"、"image2"的transition动画。 + // id为"column1"的组件是这棵新出现/消失的子树的根节点。 + Column() { + Row() { + Image($r('app.media.testImg')).width(150).height(150).id("image1") + .transition(TransitionEffect.OPACITY.animation({ duration: 1000 })) + } + + Image($r('app.media.testImg')) + .width(150) + .height(150) + .margin({ top: 50 }) + .id("image2") + .transition(TransitionEffect.scale({ x: 0, y: 0 }).animation({ duration: 1000 })) + Text("view").margin({ top: 50 }) + } + .id("column1") + .transition(TransitionEffect.opacity(0.99).animation({ duration: 1000 }), + // 结束回调设置在消失的第一层节点上,确保能有消失的结束回调 + (transitionIn: boolean) => { + console.info("transition finish, transitionIn:" + transitionIn); + } + ) + } + }.width('100%') + } +} \ No newline at end of file diff --git a/ArkUIKit/Animation/entry/src/main/ets/pages/compTransition/template4/Index.ets b/ArkUIKit/Animation/entry/src/main/ets/pages/compTransition/template4/Index.ets new file mode 100644 index 0000000000000000000000000000000000000000..9b4da9b82efa3872d09377a037271ee7c57ab8dc --- /dev/null +++ b/ArkUIKit/Animation/entry/src/main/ets/pages/compTransition/template4/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. + */ +// [Start transition_effectExample4] +import { curves } from '@kit.ArkUI'; + +@Entry +@Component +struct TransitionEffectDemo { + @State isPresent: boolean = false; + // 第一步,创建TransitionEffect + private effect: TransitionEffect = + // 创建默认透明度转场效果,并指定了springMotion(0.6, 0.8)曲线 + TransitionEffect.OPACITY.animation({ + curve: curves.springMotion(0.6, 0.8) + })// 通过combine方法,这里的动画参数会跟随上面的TransitionEffect,也就是springMotion(0.6, 0.8) + .combine(TransitionEffect.scale({ + x: 0, + y: 0 + }))// 添加旋转转场效果,这里的动画参数会跟随上面带animation的TransitionEffect,也就是springMotion(0.6, 0.8) + .combine(TransitionEffect.rotate({ angle: 90 }))// 添加平移转场效果,这里的动画参数使用指定的springMotion() + .combine(TransitionEffect.translate({ y: 150 }) + .animation({ curve: curves.springMotion() }))// 添加move转场效果,这里的动画参数会跟随上面的TransitionEffect,也就是springMotion() + .combine(TransitionEffect.move(TransitionEdge.END)); + + build() { + Stack() { + if (this.isPresent) { + Column() { + Text('ArkUI') + .fontWeight(FontWeight.Bold) + .fontSize(20) + .fontColor(Color.White) + } + .justifyContent(FlexAlign.Center) + .width(150) + .height(150) + .borderRadius(10) + .backgroundColor(0xf56c6c) + // 第二步:将转场效果通过transition接口设置到组件 + .transition(this.effect) + } + + // 边框 + Column() + .width(155) + .height(155) + .border({ + width: 5, + radius: 10, + color: Color.Black + }) + + // 第三步:新增或者删除组件触发转场,控制新增或者删除组件 + Button('Click') + .margin({ top: 320 }) + .onClick(() => { + this.isPresent = !this.isPresent; + }) + } + .width('100%') + .height('60%') + } +} +// [End transition_effectExample4] \ No newline at end of file diff --git a/ArkUIKit/Animation/entry/src/main/ets/pages/compTransition/template5/Index.ets b/ArkUIKit/Animation/entry/src/main/ets/pages/compTransition/template5/Index.ets new file mode 100644 index 0000000000000000000000000000000000000000..1fdcb0f8ded48a03706d6d2ff15e6eee1887a324 --- /dev/null +++ b/ArkUIKit/Animation/entry/src/main/ets/pages/compTransition/template5/Index.ets @@ -0,0 +1,78 @@ +/* + * 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 transition_effectExample5] +// Total number of grid items (3x3 grid) +const ITEM_COUNTS = 9; +// Grid item theme color (orange) +const ITEM_COLOR = '#ED6F21'; +// Animation stagger delay is 30ms +const INTERVAL = 30; +// The animation duration for a single grid item is 300ms +const DURATION = 300; + +@Entry +@Component +struct Index1 { + @State isGridShow: boolean = false; + private dataArray: number[] = new Array(ITEM_COUNTS); + + aboutToAppear(): void { + for (let i = 0; i < ITEM_COUNTS; i++) { + this.dataArray[i] = i; + } + } + + build() { + Stack() { + if (this.isGridShow) { + Grid() { + ForEach(this.dataArray, (item: number, index: number) => { + GridItem() { + Stack() { + Text((item + 1).toString()) + } + .size({ width: 50, height: 50 }) + .backgroundColor(ITEM_COLOR) + .transition(TransitionEffect.OPACITY + .combine(TransitionEffect.scale({ x: 0.5, y: 0.5 }))// 对每个方格的转场添加delay,实现组件的渐次出现消失效果 + .animation({ duration: DURATION, curve: Curve.Friction, delay: INTERVAL * index })) + .borderRadius(10) + } + // 消失时,如果不对方格的所有父控件添加转场效果,则方格的消失转场不会生效 + // 此处让方格的父控件在出现消失转场时一直以0.99的透明度显示,使得方格的转场效果不受影响 + .transition(TransitionEffect.opacity(0.99)) + }, (item: number) => item.toString()) + } + .columnsTemplate('1fr 1fr 1fr') + .rowsGap(15) + .columnsGap(15) + .size({ width: 180, height: 180 }) + // 消失时,如果不对方格的所有父控件添加转场效果,则方格的消失转场不会生效 + // 此处让父控件在出现消失转场时一直以0.99的透明度显示,使得方格的转场效果不受影响 + .transition(TransitionEffect.opacity(0.99)) + } + } + .size({ width: '100%', height: '100%' }) + .onClick(() => { + this.getUIContext()?.animateTo({ + duration: DURATION + INTERVAL * (ITEM_COUNTS - 1), + curve: Curve.Friction + }, () => { + this.isGridShow = !this.isGridShow; + }) + }) + } +} +// [End transition_effectExample5] \ No newline at end of file diff --git a/ArkUIKit/Animation/entry/src/main/ets/pages/compTransition/template6/Index.ets b/ArkUIKit/Animation/entry/src/main/ets/pages/compTransition/template6/Index.ets new file mode 100644 index 0000000000000000000000000000000000000000..543356ba55f0bb6fe2d23895baa152e76bf10411 --- /dev/null +++ b/ArkUIKit/Animation/entry/src/main/ets/pages/compTransition/template6/Index.ets @@ -0,0 +1,93 @@ +/* + * 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 '@kit.ArkUI'; + +@Entry +@Component +struct TransitionEffectDemo { + // [Start transition_animation] + @State isPresent: boolean = false; + // 出现时会是所有转场效果的出现效果叠加,消失时会是所有消失转场效果的叠加 + // 说明各个effect跟随的动画参数 + private effect: object = + TransitionEffect.OPACITY // 创建了透明度转场效果,这里没有调用animation接口,会跟随animateTo的动画参数 + // 通过combine方法,添加缩放转场效果,并指定了springMotion(0.6, 1.2)曲线 + .combine(TransitionEffect.scale({ x: 0, y: 0 }).animation({ curve: curves.springMotion(0.6, 1.2) })) + // 添加旋转转场效果,这里的动画参数会跟随上面的TransitionEffect,也就是springMotion(0.6, 1.2) + .combine(TransitionEffect.rotate({ angle: 90 })) + // 添加平移转场效果,动画参数会跟随其之上带animation的TransitionEffect,也就是springMotion(0.6, 1.2) + .combine(TransitionEffect.translate({ x: 150, y: 150 })) + // 添加move转场效果,并指定了springMotion曲线 + .combine(TransitionEffect.move(TransitionEdge.END)).animation({curve: curves.springMotion()}) + // 添加非对称的转场效果,由于这里没有设置animation,会跟随上面的TransitionEffect的animation效果,也就是springMotion + .combine(TransitionEffect.asymmetric(TransitionEffect.scale({ + x: 0, + y: 0 + }), TransitionEffect.rotate({ angle: 90 }))); + // [End transition_animation] + build() { + Stack() { + if (this.isPresent) { + // [Start set_transition_effects] + Column() { + Text('Test') + .fontWeight(FontWeight.Bold) + .fontSize(20) + .fontColor(Color.White) + } + .justifyContent(FlexAlign.Center) + .width(150) + .height(150) + .borderRadius(10) + .backgroundColor(0xf56c6c) + // 第二步:将转场效果通过transition接口设置到组件 + .transition(this.effect) + // [End set_transition_effects] + } + + // 边框 + Column() + .width(155) + .height(155) + .border({ + width: 5, + radius: 10, + color: Color.Black + }) + + // [Start transition_method] + Column() { + Button('Click1') + .margin({ bottom: 10 }) + .onClick(() => { + // 方式一:直接控制删除或者新增组件,动画参数由TransitionEffect的animation接口配置 + this.isPresent = !this.isPresent; + }) + + Button('Click2') + .onClick(() => { + // 方式二:将控制变量放到animateTo闭包内,未通过animation接口定义动画参数的TransitionEffect将跟随animateTo的动画参数 + this.getUIContext()?.animateTo({ curve: curves.springMotion() }, () => { + this.isPresent = !this.isPresent; + }) + }) + } + // [End transition_method] + .margin({ top: 320 }) + } + .width('100%') + .height('60%') + } +} \ No newline at end of file diff --git a/ArkUIKit/Animation/entry/src/main/ets/pages/component/template1/Index.ets b/ArkUIKit/Animation/entry/src/main/ets/pages/component/template1/Index.ets new file mode 100644 index 0000000000000000000000000000000000000000..6d6b1da2e4dca9e59742855e0303dbf5cae4fe64 --- /dev/null +++ b/ArkUIKit/Animation/entry/src/main/ets/pages/component/template1/Index.ets @@ -0,0 +1,311 @@ +/* + * 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, window, display, mediaquery, UIContext } from '@kit.ArkUI'; +import { UIAbility } from '@kit.AbilityKit'; + +export default class GlobalContext extends AppStorage { + static mainWin: window.Window | undefined = undefined; + static mainWindowSize: window.Size | undefined = undefined; +} + +/** + * 窗口、屏幕相关信息管理类 + */ +export class WindowManager { + private static instance: WindowManager | null = null; + private displayInfo: display.Display | null = null; + private uiContext: UIContext; + private orientationListener: mediaquery.MediaQueryListener; + + constructor(uiContext: UIContext) { + this.uiContext = uiContext; + this.orientationListener = this.uiContext.getMediaQuery().matchMediaSync('(orientation: landscape)'); + this.orientationListener.on('change', (mediaQueryResult: mediaquery.MediaQueryResult) => { + this.onPortrait(mediaQueryResult); + }); + this.loadDisplayInfo(); + } + + /** + * 设置主window窗口 + * @param win 当前app窗口 + */ + setMainWin(win: window.Window) { + if (win == null) { + return; + } + GlobalContext.mainWin = win; + win.on('windowSizeChange', (data: window.Size) => { + if (GlobalContext.mainWindowSize == undefined || GlobalContext.mainWindowSize == null) { + GlobalContext.mainWindowSize = data; + } else { + if (GlobalContext.mainWindowSize.width == data.width && GlobalContext.mainWindowSize.height == data.height) { + return; + } + GlobalContext.mainWindowSize = data; + } + + let winWidth = this.getMainWindowWidth(); + AppStorage.setOrCreate('mainWinWidth', winWidth); + let winHeight = this.getMainWindowHeight(); + AppStorage.setOrCreate('mainWinHeight', winHeight); + let context: UIAbility = new UIAbility(); + context.context.eventHub.emit('windowSizeChange', winWidth, winHeight); + }); + } + + static getInstance(uiContext: UIContext): WindowManager { + if (WindowManager.instance == null) { + WindowManager.instance = new WindowManager(uiContext); + } + return WindowManager.instance; + } + + private onPortrait(mediaQueryResult: mediaquery.MediaQueryResult) { + if (mediaQueryResult.matches == AppStorage.get('isLandscape')) { + return; + } + AppStorage.setOrCreate('isLandscape', mediaQueryResult.matches); + this.loadDisplayInfo(); + } + + /** + * 切换屏幕方向 + * @param ori 常量枚举值:window.Orientation + */ + changeOrientation(ori: window.Orientation) { + if (GlobalContext.mainWin != null) { + GlobalContext.mainWin.setPreferredOrientation(ori); + } + } + + private loadDisplayInfo() { + this.displayInfo = display.getDefaultDisplaySync(); + AppStorage.setOrCreate('displayWidth', this.getDisplayWidth()); + AppStorage.setOrCreate('displayHeight', this.getDisplayHeight()); + } + + /** + * 获取main窗口宽度,单位vp + */ + getMainWindowWidth(): number { + return GlobalContext.mainWindowSize != null ? this.uiContext.px2vp(GlobalContext.mainWindowSize.width) : 0; + } + + /** + * 获取main窗口高度,单位vp + */ + getMainWindowHeight(): number { + return GlobalContext.mainWindowSize != null ? this.uiContext.px2vp(GlobalContext.mainWindowSize.height) : 0; + } + + /** + * 获取屏幕宽度,单位vp + */ + getDisplayWidth(): number { + return this.displayInfo != null ? this.uiContext.px2vp(this.displayInfo.width) : 0; + } + + /** + * 获取屏幕高度,单位vp + */ + getDisplayHeight(): number { + return this.displayInfo != null ? this.uiContext.px2vp(this.displayInfo.height) : 0; + } + + /** + * 释放资源 + */ + release() { + if (this.orientationListener) { + this.orientationListener.off('change', (mediaQueryResult: mediaquery.MediaQueryResult) => { + this.onPortrait(mediaQueryResult); + }); + } + if (GlobalContext.mainWin != null) { + GlobalContext.mainWin.off('windowSizeChange'); + } + WindowManager.instance = null; + } +} + +/** + * 封装任务卡片信息数据类 + */ +export class TaskData { + bgColor: Color | string | Resource = Color.White; + index: number = 0; + taskInfo: string = 'music'; + + constructor(bgColor: Color | string | Resource, index: number, taskInfo: string) { + this.bgColor = bgColor; + this.index = index; + this.taskInfo = taskInfo; + } +} + +export const taskDataArr: Array = + [ + new TaskData('#317AF7', 0, 'music'), + new TaskData('#D94838', 1, 'mall'), + new TaskData('#DB6B42', 2, 'photos'), + new TaskData('#5BA854', 3, 'setting'), + new TaskData('#317AF7', 4, 'call'), + new TaskData('#D94838', 5, 'music'), + new TaskData('#DB6B42', 6, 'mall'), + new TaskData('#5BA854', 7, 'photos'), + new TaskData('#D94838', 8, 'setting'), + new TaskData('#DB6B42', 9, 'call'), + new TaskData('#5BA854', 10, 'music') + + ]; + +@Entry +@Component +export struct TaskSwitchMainPage { + displayWidth: number = WindowManager.getInstance(this.getUIContext()).getDisplayWidth(); + scroller: Scroller = new Scroller(); + cardSpace: number = 0; // 卡片间距 + cardWidth: number = this.displayWidth / 2 - this.cardSpace / 2; // 卡片宽度 + cardHeight: number = 400; // 卡片高度 + cardPosition: Array = []; // 卡片初始位置 + clickIndex: boolean = false; + @State taskViewOffsetX: number = 0; + @State cardOffset: number = this.displayWidth / 4; + lastCardOffset: number = this.cardOffset; + startTime: number | undefined = undefined; + + // 每个卡片初始位置 + aboutToAppear() { + for (let i = 0; i < taskDataArr.length; i++) { + this.cardPosition[i] = i * (this.cardWidth + this.cardSpace); + } + } + + // 每个卡片位置 + getProgress(index: number): number { + let progress = (this.cardOffset + this.cardPosition[index] - this.taskViewOffsetX + + this.cardWidth / 2) / this.displayWidth; + return progress; + } + + build() { + Stack({ alignContent: Alignment.Bottom }) { + // 背景 + Column() + .width('100%') + .height('100%') + .backgroundColor(0xF0F0F0); + + // 滑动组件 + Scroll(this.scroller) { + Row({ space: this.cardSpace }) { + ForEach(taskDataArr, (item: TaskData, index) => { + Column() + .width(this.cardWidth) + .height(this.cardHeight) + .backgroundColor(item.bgColor) + .borderStyle(BorderStyle.Solid) + .borderWidth(1) + .borderColor(0xAFEEEE) + .borderRadius(15) + // 计算子组件的仿射属性 + .scale((this.getProgress(index) >= 0.4 && this.getProgress(index) <= 0.6) ? + { + x: 1.1 - Math.abs(0.5 - this.getProgress(index)), + y: 1.1 - Math.abs(0.5 - this.getProgress(index)) + } : + { x: 1, y: 1 }) + .animation({ curve: Curve.Smooth }) + // 滑动动画 + .translate({ x: this.cardOffset }) + .animation({ curve: curves.springMotion() }) + .zIndex((this.getProgress(index) >= 0.4 && this.getProgress(index) <= 0.6) ? 2 : 1); + }, (item: TaskData) => item.toString()) + } + .width((this.cardWidth + this.cardSpace) * (taskDataArr.length + 1)) + .height('100%'); + } + .gesture( + GestureGroup(GestureMode.Parallel, + PanGesture({ direction: PanDirection.Horizontal, distance: 5 }) + .onActionStart((event: GestureEvent | undefined) => { + if (event) { + this.startTime = event.timestamp; + } + }) + .onActionUpdate((event: GestureEvent | undefined) => { + if (event) { + this.cardOffset = this.lastCardOffset + event.offsetX; + } + }) + .onActionEnd((event: GestureEvent | undefined) => { + if (event) { + let time = 0; + if (this.startTime) { + time = event.timestamp - this.startTime; + } + let speed = event.offsetX / (time / 1000000000); + let moveX = Math.pow(speed, 2) / 7000 * (speed > 0 ? 1 : -1); + + this.cardOffset += moveX; + // 左滑大于最右侧位置 + let cardOffsetMax = -(taskDataArr.length - 1) * (this.displayWidth / 2); + if (this.cardOffset < cardOffsetMax) { + this.cardOffset = cardOffsetMax; + } + // 右滑大于最左侧位置 + if (this.cardOffset > this.displayWidth / 4) { + this.cardOffset = this.displayWidth / 4; + } + + // 左右滑动距离不满足/满足切换关系时,补位/退回 + let remainMargin = this.cardOffset % (this.displayWidth / 2); + if (remainMargin < 0) { + remainMargin = this.cardOffset % (this.displayWidth / 2) + this.displayWidth / 2; + } + if (remainMargin <= this.displayWidth / 4) { + this.cardOffset += this.displayWidth / 4 - remainMargin; + } else { + this.cardOffset -= this.displayWidth / 4 - (this.displayWidth / 2 - remainMargin); + } + + // 记录本次滑动偏移量 + this.lastCardOffset = this.cardOffset; + } + }) + ), GestureMask.IgnoreInternal) + .scrollable(ScrollDirection.Horizontal) + .scrollBar(BarState.Off); + + // 滑动到首尾位置 + Button('Move to first/last') + .backgroundColor(0x888888) + .margin({ bottom: 30 }) + .onClick(() => { + this.clickIndex = !this.clickIndex; + + if (this.clickIndex) { + this.cardOffset = this.displayWidth / 4; + } else { + this.cardOffset = this.displayWidth / 4 - (taskDataArr.length - 1) * this.displayWidth / 2; + } + this.lastCardOffset = this.cardOffset; + }); + } + .width('100%') + .height('100%'); + } +} \ No newline at end of file diff --git a/ArkUIKit/Animation/entry/src/main/ets/pages/component/template2/Index.ets b/ArkUIKit/Animation/entry/src/main/ets/pages/component/template2/Index.ets new file mode 100644 index 0000000000000000000000000000000000000000..bc4620e0e518820a85efc8532861ff8de3010ccd --- /dev/null +++ b/ArkUIKit/Animation/entry/src/main/ets/pages/component/template2/Index.ets @@ -0,0 +1,177 @@ +/* + * 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, AnimatorResult } from '@kit.ArkUI'; + +// 该接口控制列表项视觉属性 +class ListItemModify implements AttributeModifier { + public offsetY: number = 0; // Y轴偏移量 + + applyNormalAttribute(instance: ListItemAttribute): void { + instance.translate({ y: this.offsetY }); // Y轴位移 + } +} + +@Observed +class DragSortCtrl { + private arr: Array; // 数据数组 + private modify: Array; // 属性修改器数组 + private uiContext: UIContext; // 新增UIContext成员 + private dragRefOffset: number = 0; // 拖拽参考偏移量 + offsetY: number = 0; // 当前Y轴偏移量 + private ITEM_INTV: number = 0; // 列表项间隔 + + constructor(arr: Array, intv: number, uiContext: UIContext) { + this.arr = arr; + this.uiContext = uiContext; + this.modify = []; + this.ITEM_INTV = intv; // 120: 列表项高度间隔 + arr.forEach(() => { + this.modify.push(new ListItemModify()); + }); + } + + itemMove(index: number, newIndex: number): void { + let tmp = this.arr.splice(index, 1); // 移除当前传入的index + this.arr.splice(newIndex, 0, tmp[0]); // 将当前移除的index插入到数组前一个位置 + let tmp2 = this.modify.splice(index, 1); + this.modify.splice(newIndex, 0, tmp2[0]); + } + + setDragRef(item: T): void { + this.dragRefOffset = 0; + } + + onMove(item: T, offset: number) { + this.offsetY = offset - this.dragRefOffset; // 逐帧计算传入的offect,每满足一个item高度时,进入下方if逻辑,更新dragRefOffset的值 + let index = this.arr.indexOf(item); // 在数组中查找传入的item + this.modify[index].offsetY = this.offsetY; + if (this.offsetY < -this.ITEM_INTV / 2) { // 通过判断使指定的item逐一移动到首位 + // 使用interpolatingSpring曲线生成弹簧动画 + this.uiContext.animateTo({ curve: curves.interpolatingSpring(0, 1, 400, 38) }, () => { // 400: 弹簧刚度,38: 弹簧阻尼 + this.offsetY += this.ITEM_INTV; // 调整偏移量实现平滑移动 + this.dragRefOffset -= this.ITEM_INTV; // 移动的总偏移量 + console.info(`item offsetY ${this.offsetY} dragRefOffset ${this.dragRefOffset}`); + this.itemMove(index, index - 1); // 执行列表项位置交换 + }); + } + } + + getModify(item: T): ListItemModify { + let index = this.arr.indexOf(item); + return this.modify[index]; + } +} + +@Entry +@Component +struct ListAutoSortExample { + @State private arr: Array = [0, 1, 2, 3, 4, 5]; // 列表数据数组 + @State dragSortCtrl: DragSortCtrl = new DragSortCtrl(this.arr, 120, this.getUIContext()); // 120: 列表项高度间隔 + @State firstListItemGroupCount: number = 3; // 第一个列表项组包含的项目数量 + private listScroll: ListScroller = new ListScroller(); // 列表滚动控制器 + private backAnimator: AnimatorResult | null = null; // 动画控制器 + + @Builder + itemEnd(item: number, index: number) { + Row() { + Button('To TOP').margin('4vp').onClick(() => { // 4vp: 按钮边距 + console.info(`item number item ${item} index ${index}`); + this.listScroll.closeAllSwipeActions({ + onFinish: () => { + this.dragSortCtrl.setDragRef(item); + let length = 120 * (this.arr.indexOf(item)); // 120: 列表项高度间隔 + this.backAnimator = this.getUIContext()?.createAnimator({ // 创建弹簧动画 + duration: 1000, // 动画持续时间,单位毫秒 + easing: 'interpolating-spring(0, 1, 150, 24)', // 150: 弹簧刚度,24: 弹簧阻尼 + delay: 0, // 动画延迟时间 + fill: 'none', + direction: 'normal', + iterations: 1, // 动画迭代次数 + begin: 0, // 动画起始值 + end: -length + }); + this.backAnimator.onFrame = (value) => { // 逐帧回调更新位置 + this.dragSortCtrl.onMove(item, value); // 处理list的移动替换动效 + }; + this.backAnimator.onFinish = () => {}; + this.backAnimator.play(); // 启动动画 + } + }); + }); + }.padding('4vp').justifyContent(FlexAlign.SpaceEvenly); // 4vp: 内边距 + } + + @Builder + header(title: string) { + Row() { + Text(title); + }; + } + + build() { + Row() { + Column() { + List({ space: 20, scroller: this.listScroll }) { // 20: 列表项间距 + ListItemGroup({ header: this.header('first ListItemGroup'), space: 20 }) { // 20: 列表项组内间距 + ForEach(this.arr, (item: number, index) => { + if (index < this.firstListItemGroupCount) { + ListItem() { + Text('' + item) + .width('100%') + .height(100) // 100: 列表项高度 + .fontSize(16) // 16: 字体大小 + .borderRadius(10) // 10: 边框圆角半径 + .textAlign(TextAlign.Center) + .backgroundColor(0xFFFFFF); // 0xFFFFFF: 白色背景 + } + .swipeAction({ + end: this.itemEnd(item, index) + }) + .clip(true) + .attributeModifier(this.dragSortCtrl.getModify(item)) // 动态设置属性修改 + .borderRadius(10) // 10: 边框圆角半径 + .margin({ left: 20, right: 20 }); // 20: 左右外边距 + } + }); + } + ListItemGroup({ header: this.header('second ListItemGroup'), space: 20 }) { // 20: 列表项组内间距 + ForEach(this.arr, (item: number, index) => { + if (index > this.firstListItemGroupCount - 1) { // 1: 索引偏移量 + ListItem() { + Text('' + item) + .width('100%') + .height(100) // 100: 列表项高度 + .fontSize(16) // 16: 字体大小 + .borderRadius(10) // 10: 边框圆角半径 + .textAlign(TextAlign.Center) + .backgroundColor(0xFFFFFF); // 0xFFFFFF: 白色背景 + } + .swipeAction({ + end: this.itemEnd(item, index) + }) + .clip(true) + .attributeModifier(this.dragSortCtrl.getModify(item)) + .borderRadius(10) // 10: 边框圆角半径 + .margin({ left: 20, right: 20 }); // 20: 左右外边距 + } + }); + } + } + .padding({ top: 20 }) // 20: 顶部内边距 + .height('100%'); + } + }.backgroundColor(0xDCDCDC); // 0xDCDCDC: 浅灰色背景 + } +} \ No newline at end of file diff --git a/ArkUIKit/Animation/entry/src/main/ets/pages/keyframeAnimateTo/template1/Index.ets b/ArkUIKit/Animation/entry/src/main/ets/pages/keyframeAnimateTo/template1/Index.ets new file mode 100644 index 0000000000000000000000000000000000000000..18b29a34b679e15637ec2f60a6d4486fc8ff6d51 --- /dev/null +++ b/ArkUIKit/Animation/entry/src/main/ets/pages/keyframeAnimateTo/template1/Index.ets @@ -0,0 +1,68 @@ +/* + * 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 { UIContext } from '@kit.ArkUI'; + +@Entry +@Component +struct KeyframeDemo { + @State myScale: number = 1.0; + uiContext: UIContext | undefined = undefined; + + aboutToAppear() { + this.uiContext = this.getUIContext?.(); + } + + build() { + Column() { + Circle() + .width(100) + .height(100) + .fill("#46B1E3") + .margin(100) + .scale({ x: this.myScale, y: this.myScale }) + .onClick(() => { + if (!this.uiContext) { + console.info("no uiContext, keyframe failed"); + return; + } + this.myScale = 1; + // 设置关键帧动画整体播放3次 + this.uiContext.keyframeAnimateTo({ + iterations: 3, + expectedFrameRateRange: { + min: 10, + max: 120, + expected: 60, + } + }, [ + { + // 第一段关键帧动画时长为800ms,scale属性做从1到1.5的动画 + duration: 800, + event: () => { + this.myScale = 1.5; + } + }, + { + // 第二段关键帧动画时长为500ms,scale属性做从1.5到1的动画 + duration: 500, + event: () => { + this.myScale = 1; + } + } + ]); + }) + }.width('100%').margin({ top: 5 }) + } +} \ No newline at end of file diff --git a/ArkUIKit/Animation/entry/src/main/ets/pages/motionPath/template1/Index.ets b/ArkUIKit/Animation/entry/src/main/ets/pages/motionPath/template1/Index.ets new file mode 100644 index 0000000000000000000000000000000000000000..97db6e2734688969e1f36cee799bea3a3e9de205 --- /dev/null +++ b/ArkUIKit/Animation/entry/src/main/ets/pages/motionPath/template1/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. + */ +@Entry +@Component +struct MotionPathExample { + @State toggle: boolean = true; + + build() { + Column() { + Button('click me').margin(50) + .motionPath({ + path: 'Mstart.x start.y L300 200 L300 500 Lend.x end.y', + from: 0.0, + to: 1.0, + rotatable: true + }) // 执行动画:从起点移动到(300,200),再到(300,500),再到终点 + .onClick(() => { + this.getUIContext()?.animateTo({ duration: 4000, curve: Curve.Linear }, () => { + this.toggle = !this.toggle; // 通过this.toggle变化组件的位置 + }); + }) + }.width('100%').height('100%').alignItems(this.toggle ? HorizontalAlign.Start : HorizontalAlign.Center) + } +} \ No newline at end of file diff --git a/ArkUIKit/Animation/entry/src/main/ets/pages/pageTransition/template1/Index.ets b/ArkUIKit/Animation/entry/src/main/ets/pages/pageTransition/template1/Index.ets new file mode 100644 index 0000000000000000000000000000000000000000..985716355150f40b4fdb091fd4a4920617d7143a --- /dev/null +++ b/ArkUIKit/Animation/entry/src/main/ets/pages/pageTransition/template1/Index.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. + */ +@Entry +@Component +struct pageTransition1 { + @State scale1: number = 1; + @State opacity1: number = 1; + + build() { + Column() { + Image($r("app.media.transition_image1")).width('100%').height('100%') + } + .width('100%') + .height('100%') + .scale({ x: this.scale1 }) + .opacity(this.opacity1) + .onClick(() => { + this.getUIContext().getRouter().pushUrl({ url: 'pages/pageTransition/template1/Page1' }); + }) + } + + pageTransition() { + PageTransitionEnter({ duration: 1200, curve: Curve.Linear }) + .onEnter((type: RouteType, progress: number) => { + if (type == RouteType.Push || type == RouteType.Pop) { + this.scale1 = progress; + this.opacity1 = progress; + } + }) + PageTransitionExit({ duration: 1200, curve: Curve.Ease }) + .onExit((type: RouteType, progress: number) => { + if (type == RouteType.Push) { + this.scale1 = 1 - progress; + this.opacity1 = 1 - progress; + } + }) + } +} \ No newline at end of file diff --git a/ArkUIKit/Animation/entry/src/main/ets/pages/pageTransition/template1/Page1.ets b/ArkUIKit/Animation/entry/src/main/ets/pages/pageTransition/template1/Page1.ets new file mode 100644 index 0000000000000000000000000000000000000000..02727ee0ffd1579b5fadf0e76435ff40f06a42c9 --- /dev/null +++ b/ArkUIKit/Animation/entry/src/main/ets/pages/pageTransition/template1/Page1.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. + */ +@Entry +@Component +struct pageTransitionPage1 { + @State scale2: number = 1; + @State opacity2: number = 1; + + build() { + Column() { + Image($r("app.media.transition_image2")).width('100%').height('100%') // 图片存放在media文件夹下 + } + .width('100%') + .height('100%') + .scale({ x: this.scale2 }) + .opacity(this.opacity2) + .onClick(() => { + this.getUIContext().getRouter().pushUrl({ url: 'pages/pageTransition/template1/Index' }); + }) + } + + pageTransition() { + PageTransitionEnter({ duration: 1200, curve: Curve.Linear }) + .onEnter((type: RouteType, progress: number) => { + if (type == RouteType.Push || type == RouteType.Pop) { + this.scale2 = progress; + } + this.opacity2 = progress; + }) + PageTransitionExit({ duration: 1200, curve: Curve.Ease }) + .onExit((type: RouteType, progress: number) => { + if (type == RouteType.Pop) { + this.scale2 = 1 - progress; + this.opacity2 = 1 - progress; + } + }) + } +} \ No newline at end of file diff --git a/ArkUIKit/Animation/entry/src/main/ets/pages/pageTransition/template2/Index.ets b/ArkUIKit/Animation/entry/src/main/ets/pages/pageTransition/template2/Index.ets new file mode 100644 index 0000000000000000000000000000000000000000..b334a8f43305046339d2df7f507fc039f319e213 --- /dev/null +++ b/ArkUIKit/Animation/entry/src/main/ets/pages/pageTransition/template2/Index.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. + */ +@Entry +@Component +struct pageTransition2 { + @State scale1: number = 1; + @State opacity1: number = 1; + + build() { + Column() { + Button($r('app.string.page1')).onClick(() => { + this.getUIContext().getRouter().pushUrl({ + url: "pages/pageTransition/template2/Page1" + }) + }) + .width(200) + .height(60) + .fontSize(36) + Text("START") + .fontSize(36) + .textAlign(TextAlign.Center) + } + .scale({ x: this.scale1 }) + .opacity(this.opacity1) + .height('100%') + .width('100%') + .justifyContent(FlexAlign.Center) + } + + // 自定义方式2:使用系统提供的多种默认效果(平移、缩放、透明度等) + pageTransition() { + //设置入场动效 + PageTransitionEnter({ duration: 200 }) + .slide(SlideEffect.START) + //设置退场动效 + PageTransitionExit({ delay: 100 }) + .slide(SlideEffect.START) //Left + } +} \ No newline at end of file diff --git a/ArkUIKit/Animation/entry/src/main/ets/pages/pageTransition/template2/Page1.ets b/ArkUIKit/Animation/entry/src/main/ets/pages/pageTransition/template2/Page1.ets new file mode 100644 index 0000000000000000000000000000000000000000..61f33307bd9b70d150a4f18163967bc8f9b43f4b --- /dev/null +++ b/ArkUIKit/Animation/entry/src/main/ets/pages/pageTransition/template2/Page1.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. + */ +@Entry +@Component +struct Page1 { + @State scale1: number = 1; + @State opacity1: number = 1; + + build() { + Column() { + Button($r('app.string.page2')).onClick(() => { + this.getUIContext().getRouter().pushUrl({ + url: "pages/pageTransition/template2/Index" + }); + }) + .width(200) + .height(60) + .fontSize(36) + Text("END") + .fontSize(36) + .textAlign(TextAlign.Center) + } + .scale({ x: this.scale1 }) + .opacity(this.opacity1) + .height('100%') + .width('100%') + .justifyContent(FlexAlign.Center) + } + + // 自定义方式2:使用系统提供的多种默认效果(平移、缩放、透明度等) + pageTransition() { + PageTransitionEnter({ duration: 200 }) + .slide(SlideEffect.END) //Right + PageTransitionExit({ delay: 100 }) + .slide(SlideEffect.END) //Right + } +} \ No newline at end of file diff --git a/ArkUIKit/Animation/entry/src/main/ets/pages/pageTransition/template3/pageTransitionDst1.ets b/ArkUIKit/Animation/entry/src/main/ets/pages/pageTransition/template3/pageTransitionDst1.ets new file mode 100644 index 0000000000000000000000000000000000000000..b93ce968e7cf9e030286694c9ab48f34919046ab --- /dev/null +++ b/ArkUIKit/Animation/entry/src/main/ets/pages/pageTransition/template3/pageTransitionDst1.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 pageTransition_template3_pageTransitionDst1_start] +// PageTransitionDst1 +@Entry +@Component +struct PageTransitionDst1 { + build() { + Column() { + Image($r('app.media.forest')) + .width('90%') + .height('80%') + .objectFit(ImageFit.Fill) + .syncLoad(true) // 同步加载图片,使页面出现时图片已经加载完成 + .margin(30) + + Row({ space: 10 }) { + Button("pushUrl") + .onClick(() => { + // 路由到下一页面,push操作 + this.getUIContext().getRouter().pushUrl({ url: 'pages/pageTransition/template3/pageTransitionSrc1' }); + }) + Button("back") + .onClick(() => { + // 返回到上一页面,相当于pop操作 + this.getUIContext().getRouter().back(); + }) + }.justifyContent(FlexAlign.Center) + } + .width('100%').height('100%') + .alignItems(HorizontalAlign.Center) + } + + pageTransition() { + // 定义页面进入时的效果,从右侧滑入,时长为1000ms,页面栈发生push操作时该效果才生效 + PageTransitionEnter({ type: RouteType.Push, duration: 1000 }) + .slide(SlideEffect.Right) + // 定义页面进入时的效果,从左侧滑入,时长为1000ms,页面栈发生pop操作时该效果才生效 + PageTransitionEnter({ type: RouteType.Pop, duration: 1000 }) + .slide(SlideEffect.Left) + // 定义页面退出时的效果,向左侧滑出,时长为1000ms,页面栈发生push操作时该效果才生效 + PageTransitionExit({ type: RouteType.Push, duration: 1000 }) + .slide(SlideEffect.Left) + // 定义页面退出时的效果,向右侧滑出,时长为1000ms,页面栈发生pop操作时该效果才生效 + PageTransitionExit({ type: RouteType.Pop, duration: 1000 }) + .slide(SlideEffect.Right) + } +} +// [End pageTransition_template3_pageTransitionDst1_start] \ No newline at end of file diff --git a/ArkUIKit/Animation/entry/src/main/ets/pages/pageTransition/template3/pageTransitionSrc1.ets b/ArkUIKit/Animation/entry/src/main/ets/pages/pageTransition/template3/pageTransitionSrc1.ets new file mode 100644 index 0000000000000000000000000000000000000000..584ee255cea686c55d3586dbefc888611e84c7b8 --- /dev/null +++ b/ArkUIKit/Animation/entry/src/main/ets/pages/pageTransition/template3/pageTransitionSrc1.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 pageTransition_template3_pageTransitionSrc1_start] +// PageTransitionSrc1 +@Entry +@Component +struct PageTransitionSrc1 { + build() { + Column() { + Image($r('app.media.mountain')) + .width('90%') + .height('80%') + .objectFit(ImageFit.Fill) + .syncLoad(true) // 同步加载图片,使页面出现时图片已经加载完成 + .margin(30) + + Row({ space: 10 }) { + Button("pushUrl") + .onClick(() => { + // 路由到下一个页面,push操作 + this.getUIContext().getRouter().pushUrl({ url: 'pages/pageTransition/template3/pageTransitionDst1' }); + }) + Button("back") + .onClick(() => { + // 返回到上一页面,相当于pop操作 + this.getUIContext().getRouter().back(); + }) + }.justifyContent(FlexAlign.Center) + } + .width('100%').height('100%') + .alignItems(HorizontalAlign.Center) + } + + pageTransition() { + // 定义页面进入时的效果,从右侧滑入,时长为1000ms,页面栈发生push操作时该效果才生效 + PageTransitionEnter({ type: RouteType.Push, duration: 1000 }) + .slide(SlideEffect.Right) + // 定义页面进入时的效果,从左侧滑入,时长为1000ms,页面栈发生pop操作时该效果才生效 + PageTransitionEnter({ type: RouteType.Pop, duration: 1000 }) + .slide(SlideEffect.Left) + // 定义页面退出时的效果,向左侧滑出,时长为1000ms,页面栈发生push操作时该效果才生效 + PageTransitionExit({ type: RouteType.Push, duration: 1000 }) + .slide(SlideEffect.Left) + // 定义页面退出时的效果,向右侧滑出,时长为1000ms,页面栈发生pop操作时该效果才生效 + PageTransitionExit({ type: RouteType.Pop, duration: 1000 }) + .slide(SlideEffect.Right) + } +} +// [End pageTransition_template3_pageTransitionSrc1_start] \ No newline at end of file diff --git a/ArkUIKit/Animation/entry/src/main/ets/pages/pageTransition/template4/pageTransitionDst2.ets b/ArkUIKit/Animation/entry/src/main/ets/pages/pageTransition/template4/pageTransitionDst2.ets new file mode 100644 index 0000000000000000000000000000000000000000..7ce6ea70af7022b0e89de340b621e0b6329f6e9a --- /dev/null +++ b/ArkUIKit/Animation/entry/src/main/ets/pages/pageTransition/template4/pageTransitionDst2.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 pageTransition_template4_pageTransitionDst2_start] +// PageTransitionDst2 +@Entry +@Component +struct PageTransitionDst2 { + build() { + Column() { + Image($r('app.media.forest')) + .width('90%') + .height('80%') + .objectFit(ImageFit.Fill) + .syncLoad(true) // 同步加载图片,使页面出现时图片已经加载完成 + .margin(30) + + Row({ space: 10 }) { + Button("pushUrl") + .onClick(() => { + // 路由到下一页面,push操作 + this.getUIContext().getRouter().pushUrl({ url: 'pages/pageTransition/template4/pageTransitionSrc2' }); + }) + Button("back") + .onClick(() => { + // 返回到上一页面,相当于pop操作 + this.getUIContext().getRouter().back(); + }) + }.justifyContent(FlexAlign.Center) + } + .width('100%').height('100%') + .alignItems(HorizontalAlign.Center) + } + + pageTransition() { + // 定义页面进入时的效果,从左侧滑入,时长为1200ms,无论页面栈发生push还是pop操作均可生效 + PageTransitionEnter({ duration: 1200 }) + .slide(SlideEffect.Left) + // 定义页面退出时的效果,相对于正常页面位置x方向平移100vp,y方向平移100vp,透明度变为0,时长为1000ms,无论页面栈发生push还是pop操作均可生效 + PageTransitionExit({ duration: 1000 }) + .translate({ x: 100.0, y: 100.0 }) + .opacity(0) + } +} +// [End pageTransition_template4_pageTransitionDst2_start] \ No newline at end of file diff --git a/ArkUIKit/Animation/entry/src/main/ets/pages/pageTransition/template4/pageTransitionSrc2.ets b/ArkUIKit/Animation/entry/src/main/ets/pages/pageTransition/template4/pageTransitionSrc2.ets new file mode 100644 index 0000000000000000000000000000000000000000..c00f22b394c9740f31eaae9be3a7bfd441a40eef --- /dev/null +++ b/ArkUIKit/Animation/entry/src/main/ets/pages/pageTransition/template4/pageTransitionSrc2.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 pageTransition_template4_pageTransitionSrc2_start] +// PageTransitionSrc2 +@Entry +@Component +struct PageTransitionSrc2 { + build() { + Column() { + Image($r('app.media.mountain')) + .width('90%') + .height('80%') + .objectFit(ImageFit.Fill) + .syncLoad(true) // 同步加载图片,使页面出现时图片已经加载完成 + .margin(30) + + Row({ space: 10 }) { + Button("pushUrl") + .onClick(() => { + // 路由到下一页面,push操作 + this.getUIContext().getRouter().pushUrl({ url: 'pages/pageTransition/template4/pageTransitionDst2' }); + }) + Button("back") + .onClick(() => { + // 返回到上一页面,相当于pop操作 + this.getUIContext().getRouter().back(); + }) + }.justifyContent(FlexAlign.Center) + } + .width('100%').height('100%') + .alignItems(HorizontalAlign.Center) + } + + pageTransition() { + // 定义页面进入时的效果,从左侧滑入,时长为1000ms,无论页面栈发生push还是pop操作均可生效 + PageTransitionEnter({ duration: 1000 }) + .slide(SlideEffect.Left) + // 定义页面退出时的效果,相对于正常页面位置x方向平移100vp,y方向平移100vp,透明度变为0,时长为1200ms,无论页面栈发生push还是pop操作均可生效 + PageTransitionExit({ duration: 1200 }) + .translate({ x: 100.0, y: 100.0 }) + .opacity(0) + } +} +// [End pageTransition_template4_pageTransitionSrc2_start] \ No newline at end of file diff --git a/ArkUIKit/Animation/entry/src/main/ets/pages/pageTransition/template5/PageTransitionDst3.ets b/ArkUIKit/Animation/entry/src/main/ets/pages/pageTransition/template5/PageTransitionDst3.ets new file mode 100644 index 0000000000000000000000000000000000000000..daad8e2ea8ba8ee0baf149b253af9676cc0a04f0 --- /dev/null +++ b/ArkUIKit/Animation/entry/src/main/ets/pages/pageTransition/template5/PageTransitionDst3.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. + */ +@Entry +@Component +struct PagePageTransition3 { + build() { + Column() { + // $r('app.media.mountain')需要替换为开发着所需要的资源文件 + Image($r('app.media.mountain')) + .width('90%') + .height('80%') + .objectFit(ImageFit.Fill) + .syncLoad(true) // 同步加载图片,使页面出现时图片已经加载完成 + .margin(30) + + Row({ space: 10 }) { + Button('pushUrl') + .onClick(() => { + // 路由到下一页面,push操作 + this.getUIContext().getRouter().pushUrl({ url: 'pages/pageTransition/template5/pageA' }); + }) + Button('back') + .onClick(() => { + // 返回到上一页面,相当于pop操作 + this.getUIContext().getRouter().back(); + }) + }.justifyContent(FlexAlign.Center) + } + .width('100%').height('100%') + .alignItems(HorizontalAlign.Center) + } + + // [Start pageTransition_template5_pageB_start] + // page B + pageTransition() { + // 定义页面进入时的效果,从右侧滑入,时长为1000ms,无论页面栈发生push还是pop操作均可生效 + PageTransitionEnter({ type: RouteType.None, duration: 1000 }) + .slide(SlideEffect.Right) + // 定义页面退出时的效果,向右侧滑出,时长为1200ms,无论页面栈发生push还是pop操作均可生效 + PageTransitionExit({ type: RouteType.None, duration: 1200 }) + .slide(SlideEffect.Right) + } + // [End pageTransition_template5_pageB_start] +} diff --git a/ArkUIKit/Animation/entry/src/main/ets/pages/pageTransition/template5/PageTransitionSrc3.ets b/ArkUIKit/Animation/entry/src/main/ets/pages/pageTransition/template5/PageTransitionSrc3.ets new file mode 100644 index 0000000000000000000000000000000000000000..ede84f6382c039dfd0ebd14e6dc10cf59823d0d2 --- /dev/null +++ b/ArkUIKit/Animation/entry/src/main/ets/pages/pageTransition/template5/PageTransitionSrc3.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. + */ +@Entry +@Component +struct PageTransitionSrc3 { + build() { + Column() { + // $r('app.media.forest')需要替换为开发着所需要的资源文件 + Image($r('app.media.forest')) + .width('90%') + .height('80%') + .objectFit(ImageFit.Fill) + .syncLoad(true) // 同步加载图片,使页面出现时图片已经加载完成 + .margin(30) + + Row({ space: 10 }) { + Button('pushUrl') + .onClick(() => { + // 路由到下一页面,push操作 + this.getUIContext().getRouter().pushUrl({ url: 'pages/pageTransition/template5/pageB' }); + }) + Button('back') + .onClick(() => { + // 返回到上一页面,相当于pop操作 + this.getUIContext().getRouter().back(); + }) + }.justifyContent(FlexAlign.Center) + } + .width('100%').height('100%') + .alignItems(HorizontalAlign.Center) + } + + // [Start pageTransition_template5_pageA_start] + // page A + pageTransition() { + // 定义页面进入时的效果,从左侧滑入,时长为1200ms,无论页面栈发生push还是pop操作均可生效 + PageTransitionEnter({ type: RouteType.None, duration: 1200 }) + .slide(SlideEffect.Left) + // 定义页面退出时的效果,向左侧滑出,时长为1000ms,无论页面栈发生push还是pop操作均可生效 + PageTransitionExit({ type: RouteType.None, duration: 1000 }) + .slide(SlideEffect.Left) + } + // [End pageTransition_template5_pageA_start] +} diff --git a/ArkUIKit/Animation/entry/src/main/ets/pages/pageTransition/template6/PageTransitionDst4.ets b/ArkUIKit/Animation/entry/src/main/ets/pages/pageTransition/template6/PageTransitionDst4.ets new file mode 100644 index 0000000000000000000000000000000000000000..527f28c063bf4ffd8127596c9d79c5a6a0cfce20 --- /dev/null +++ b/ArkUIKit/Animation/entry/src/main/ets/pages/pageTransition/template6/PageTransitionDst4.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. + */ +@Entry +@Component +struct PagePageTransition4 { + build() { + Column() { + // $r('app.media.forest')需要替换为开发着所需要的资源文件 + Image($r('app.media.forest')) + .width('90%') + .height('80%') + .objectFit(ImageFit.Fill) + .syncLoad(true) // 同步加载图片,使页面出现时图片已经加载完成 + .margin(30) + + Row({ space: 10 }) { + Button('pushUrl') + .onClick(() => { + // 路由到下一页面,push操作 + this.getUIContext().getRouter().pushUrl({ url: 'pages/pageTransition/template6/pageA' }); + }) + Button('back') + .onClick(() => { + // 返回到上一页面,相当于pop操作 + this.getUIContext().getRouter().back(); + }) + }.justifyContent(FlexAlign.Center) + } + .width('100%').height('100%') + .alignItems(HorizontalAlign.Center) + } + + // [Start pageTransition_template6_pageB_start] + // page B + pageTransition() { + // 定义页面进入时的效果,从右侧滑入,时长为1000ms,页面栈发生push操作时该效果才生效 + PageTransitionEnter({ type: RouteType.Push, duration: 1000 }) + .slide(SlideEffect.Right) + // 定义页面进入时的效果,从左侧滑入,时长为1000ms,页面栈发生pop操作时该效果才生效 + PageTransitionEnter({ type: RouteType.Pop, duration: 1000 }) + .slide(SlideEffect.Left) + // 定义页面退出时的效果,向左侧滑出,时长为1200ms,页面栈发生push操作时该效果才生效 + PageTransitionExit({ type: RouteType.Push, duration: 1200 }) + .slide(SlideEffect.Left) + // 定义页面退出时的效果,向右侧滑出,时长为1200ms,页面栈发生pop操作时该效果才生效 + PageTransitionExit({ type: RouteType.Pop, duration: 1200 }) + .slide(SlideEffect.Right) + } + // [End pageTransition_template6_pageB_start] +} diff --git a/ArkUIKit/Animation/entry/src/main/ets/pages/pageTransition/template6/PageTransitionSrc4.ets b/ArkUIKit/Animation/entry/src/main/ets/pages/pageTransition/template6/PageTransitionSrc4.ets new file mode 100644 index 0000000000000000000000000000000000000000..f3f1230fec2b913c3513bcea57c2379501f9c82a --- /dev/null +++ b/ArkUIKit/Animation/entry/src/main/ets/pages/pageTransition/template6/PageTransitionSrc4.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. + */ +@Entry +@Component +struct PageTransitionSrc4 { + build() { + Column() { + // $r('app.media.mountain')需要替换为开发着所需要的资源文件 + Image($r('app.media.mountain')) + .width('90%') + .height('80%') + .objectFit(ImageFit.Fill) + .syncLoad(true) // 同步加载图片,使页面出现时图片已经加载完成 + .margin(30) + + Row({ space: 10 }) { + Button('pushUrl') + .onClick(() => { + // 路由到下一个页面,push操作 + this.getUIContext().getRouter().pushUrl({ url: 'pages/pageTransition/template6/pageB' }); + }) + Button('back') + .onClick(() => { + // 返回到上一页面,相当于pop操作 + this.getUIContext().getRouter().back(); + }) + }.justifyContent(FlexAlign.Center) + } + .width('100%').height('100%') + .alignItems(HorizontalAlign.Center) + } + + // [Start pageTransition_template6_pageA_start] + // page A + pageTransition() { + // 定义页面进入时的效果,从右侧滑入,时长为1200ms,页面栈发生push操作时该效果才生效 + PageTransitionEnter({ type: RouteType.Push, duration: 1200 }) + .slide(SlideEffect.Right) + // 定义页面进入时的效果,从左侧滑入,时长为1200ms,页面栈发生pop操作时该效果才生效 + PageTransitionEnter({ type: RouteType.Pop, duration: 1200 }) + .slide(SlideEffect.Left) + // 定义页面退出时的效果,向左侧滑出,时长为1000ms,页面栈发生push操作时该效果才生效 + PageTransitionExit({ type: RouteType.Push, duration: 1000 }) + .slide(SlideEffect.Left) + // 定义页面退出时的效果,向右侧滑出,时长为1000ms,页面栈发生pop操作时该效果才生效 + PageTransitionExit({ type: RouteType.Pop, duration: 1000 }) + .slide(SlideEffect.Right) + } + // [End pageTransition_template6_pageA_start] +} diff --git a/ArkUIKit/Animation/entry/src/main/ets/pages/particle/template1/Index.ets b/ArkUIKit/Animation/entry/src/main/ets/pages/particle/template1/Index.ets new file mode 100644 index 0000000000000000000000000000000000000000..778cc61229eceff3c18fd385d5f3d1234397b7c4 --- /dev/null +++ b/ArkUIKit/Animation/entry/src/main/ets/pages/particle/template1/Index.ets @@ -0,0 +1,127 @@ +/* + * 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 particle_example] +@Entry +@Component +struct ParticleExample { + build() { + Stack() { + Text() + .width(300).height(300).backgroundColor(Color.Black) + Particle({ + particles: [ + { + emitter: { + particle: { + type: ParticleType.POINT, //粒子类型 + config: { + radius: 10//圆点半径 + }, + count: 500, //粒子总数 + lifetime: 10000, //粒子生命周期,单位ms + lifetimeRange: 100//粒子生命周期取值范围,单位ms + }, + emitRate: 10, //每秒发射粒子数 + position: [0, 0], + shape: ParticleEmitterShape.RECTANGLE//发射器形状 + }, + color: { + range: [Color.Red, Color.Yellow], //初始颜色范围 + distributionType: DistributionType.GAUSSIAN, // 初始颜色随机值分布 + updater: { + type: ParticleUpdater.CURVE, //变化方式为曲线变化 + config: [ + { + from: Color.White, //变化起始值 + to: Color.Pink, //变化终点值 + startMillis: 0, //开始时间 + endMillis: 3000, //结束时间 + curve: Curve.EaseIn//变化曲线 + }, + { + from: Color.Pink, + to: Color.Orange, + startMillis: 3000, + endMillis: 5000, + curve: Curve.EaseIn + }, + { + from: Color.Orange, + to: Color.Pink, + startMillis: 5000, + endMillis: 8000, + curve: Curve.EaseIn + }, + ] + } + }, + opacity: { + range: [0.0, 1.0], //粒子透明度的初始值从【0.0到1.0】随机产生 + updater: { + type: ParticleUpdater.CURVE, + config: [ + { + from: 0.0, + to: 1.0, + startMillis: 0, + endMillis: 3000, + curve: Curve.EaseIn + }, + { + from: 1.0, + to: 0.0, + startMillis: 5000, + endMillis: 10000, + curve: Curve.EaseIn + } + ] + } + }, + scale: { + range: [0.0, 0.0], + updater: { + type: ParticleUpdater.CURVE, + config: [ + { + from: 0.0, + to: 0.5, + startMillis: 0, + endMillis: 3000, + curve: Curve.EaseIn + } + ] + } + }, + acceleration: { + //加速度的配置,从大小和方向两个维度变化,speed表示加速度大小,angle表示加速度方向 + speed: { + range: [3, 9], + updater: { + type: ParticleUpdater.RANDOM, //Speed的变化方式是随机变化 + config: [1, 20] + } + }, + angle: { + range: [90, 90] + } + } + + } + ] + }).width(300).height(300) + }.width('100%').height('100%').align(Alignment.Center) + } +} +// [End particle_example] \ No newline at end of file diff --git a/ArkUIKit/Animation/entry/src/main/ets/pages/particle/template2/Index.ets b/ArkUIKit/Animation/entry/src/main/ets/pages/particle/template2/Index.ets new file mode 100644 index 0000000000000000000000000000000000000000..e74f213b4f8ae8edb56fa3c868d168af69948a4f --- /dev/null +++ b/ArkUIKit/Animation/entry/src/main/ets/pages/particle/template2/Index.ets @@ -0,0 +1,402 @@ +/* + * 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 particle_example2] +@Entry +@Component +struct ParticleExample2 { + @State + myCount: number = 100; + flag: boolean = false; + + build() { + Column() { + Stack() { + Particle({ + particles: [ + { + emitter: { + particle: { + type: ParticleType.IMAGE, + config: { + src: $r("app.media.book"), + size: [10, 10] + }, + count: this.myCount, + lifetime: 10000, + lifetimeRange: 100 + }, + emitRate: 3, + position: [0, 0], + shape: ParticleEmitterShape.CIRCLE + }, + color: { + range: [Color.White, Color.White] + }, + opacity: { + range: [1.0, 1.0], + updater: { + type: ParticleUpdater.CURVE, + config: [ + { + from: 0, + to: 1.0, + startMillis: 0, + endMillis: 6000 + }, + { + from: 1.0, + to: 0, + startMillis: 6000, + endMillis: 10000 + } + ] + } + }, + scale: { + range: [0.1, 1.0], + updater: { + type: ParticleUpdater.CURVE, + config: [ + { + from: 0, + to: 1.5, + startMillis: 0, + endMillis: 8000, + curve: Curve.EaseIn + } + + ] + } + }, + acceleration: { + speed: { + range: [3, 9], + updater: { + type: ParticleUpdater.CURVE, + config: [ + { + from: 10, + to: 20, + startMillis: 0, + endMillis: 3000, + curve: Curve.EaseIn + }, + { + from: 10, + to: 2, + startMillis: 3000, + endMillis: 8000, + curve: Curve.EaseIn + } + ] + } + }, + angle: { + range: [0, 180], + updater: { + type: ParticleUpdater.CURVE, + config: [{ + from: 1, + to: 2, + startMillis: 0, + endMillis: 1000, + curve: Curve.EaseIn + }, + { + from: 50, + to: -50, + startMillis: 1000, + endMillis: 3000, + curve: Curve.EaseIn + }, + { + from: 3, + to: 5, + startMillis: 3000, + endMillis: 8000, + curve: Curve.EaseIn + } + ] + } + } + }, + spin: { + range: [0.1, 1.0], + updater: { + type: ParticleUpdater.CURVE, + config: [ + { + from: 0, + to: 360, + startMillis: 0, + endMillis: 8000, + curve: Curve.EaseIn + } + ] + } + }, + } + , { + emitter: { + particle: { + type: ParticleType.IMAGE, + config: { + src: $r('app.media.heart'), + size: [10, 10] + }, + count: this.myCount, + lifetime: 10000, + lifetimeRange: 100 + }, + emitRate: 3, + shape: ParticleEmitterShape.CIRCLE + }, + color: { + range: [Color.White, Color.White] + }, + opacity: { + range: [1.0, 1.0], + updater: { + type: ParticleUpdater.CURVE, + config: [ + { + from: 0, + to: 1.0, + startMillis: 0, + endMillis: 6000 + }, + { + from: 1.0, + to: 0, + startMillis: 6000, + endMillis: 10000 + } + ] + } + }, + scale: { + range: [0.1, 1.0], + updater: { + type: ParticleUpdater.CURVE, + config: [ + { + from: 0, + to: 2.0, + startMillis: 0, + endMillis: 10000, + curve: Curve.EaseIn + } + + ] + } + }, + acceleration: { + speed: { + range: [3, 9], + updater: { + type: ParticleUpdater.CURVE, + config: [ + { + from: 10, + to: 20, + startMillis: 0, + endMillis: 3000, + curve: Curve.EaseIn + }, + { + from: 10, + to: 2, + startMillis: 3000, + endMillis: 8000, + curve: Curve.EaseIn + } + ] + } + }, + angle: { + range: [0, 180], + updater: { + type: ParticleUpdater.CURVE, + config: [{ + from: 1, + to: 2, + startMillis: 0, + endMillis: 1000, + curve: Curve.EaseIn + }, + { + from: 50, + to: -50, + startMillis: 0, + endMillis: 3000, + curve: Curve.EaseIn + }, + { + from: 3, + to: 5, + startMillis: 3000, + endMillis: 10000, + curve: Curve.EaseIn + } + ] + } + } + }, + spin: { + range: [0.1, 1.0], + updater: { + type: ParticleUpdater.CURVE, + config: [ + { + from: 0, + to: 360, + startMillis: 0, + endMillis: 10000, + curve: Curve.EaseIn + } + ] + } + }, + }, { + emitter: { + particle: { + type: ParticleType.IMAGE, + config: { + src: $r('app.media.sun'), + size: [10, 10] + }, + count: this.myCount, + lifetime: 10000, + lifetimeRange: 100 + }, + emitRate: 3, + shape: ParticleEmitterShape.CIRCLE + }, + color: { + range: [Color.White, Color.White] + }, + opacity: { + range: [1.0, 1.0], + updater: { + type: ParticleUpdater.CURVE, + config: [ + { + from: 0, + to: 1.0, + startMillis: 0, + endMillis: 6000 + }, + { + from: 1.0, + to: 0, + startMillis: 6000, + endMillis: 10000 + } + ] + } + }, + scale: { + range: [0.1, 1.0], + updater: { + type: ParticleUpdater.CURVE, + config: [ + { + from: 0, + to: 2.0, + startMillis: 0, + endMillis: 10000, + curve: Curve.EaseIn + } + + ] + } + }, + acceleration: { + speed: { + range: [3, 9], + updater: { + type: ParticleUpdater.CURVE, + config: [ + { + from: 10, + to: 20, + startMillis: 0, + endMillis: 3000, + curve: Curve.EaseIn + }, + { + from: 10, + to: 2, + startMillis: 3000, + endMillis: 8000, + curve: Curve.EaseIn + } + ] + } + }, + angle: { + range: [0, 180], + updater: { + type: ParticleUpdater.CURVE, + config: [{ + from: 1, + to: 2, + startMillis: 0, + endMillis: 1000, + curve: Curve.EaseIn + }, + { + from: 50, + to: -50, + startMillis: 1000, + endMillis: 3000, + curve: Curve.EaseIn + }, + { + from: 3, + to: 5, + startMillis: 3000, + endMillis: 8000, + curve: Curve.EaseIn + } + ] + } + } + }, + spin: { + range: [0.1, 1.0], + updater: { + type: ParticleUpdater.CURVE, + config: [ + { + from: 0, + to: 360, + startMillis: 0, + endMillis: 10000, + curve: Curve.EaseIn + } + ] + } + }, + } + ] + }).width(300).height(300) + + }.width(500).height(500).align(Alignment.Center) + }.width('100%').height('100%') + + } +} +// [End particle_example2] \ No newline at end of file diff --git a/ArkUIKit/Animation/entry/src/main/ets/pages/particle/template3/Index.ets b/ArkUIKit/Animation/entry/src/main/ets/pages/particle/template3/Index.ets new file mode 100644 index 0000000000000000000000000000000000000000..238dfbca49c5f4b26e5b6f936994898709a60ed9 --- /dev/null +++ b/ArkUIKit/Animation/entry/src/main/ets/pages/particle/template3/Index.ets @@ -0,0 +1,134 @@ +/* + * 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 particle_example3] +@Entry +@Component +struct ParticleExample3 { + build() { + Stack() { + Text() + .width(300).height(300).backgroundColor(Color.Black) + Particle({ + particles: [ + { + emitter: { + particle: { + type: ParticleType.POINT, //粒子类型 + config: { + radius: 10//圆点半径 + }, + count: 500, //粒子总数 + lifetime: 10000//粒子生命周期,单位ms + }, + emitRate: 10, //每秒发射粒子数 + position: [0, 0], + shape: ParticleEmitterShape.RECTANGLE//发射器形状 + }, + color: { + range: [Color.Red, Color.Yellow], //初始颜色范围 + updater: { + type: ParticleUpdater.CURVE, //变化方式为曲线变化 + config: [ + { + from: Color.White, //变化起始值 + to: Color.Pink, //变化终点值 + startMillis: 0, //开始时间 + endMillis: 3000, //结束时间 + curve: Curve.EaseIn//变化曲线 + }, + { + from: Color.Pink, + to: Color.Orange, + startMillis: 3000, + endMillis: 5000, + curve: Curve.EaseIn + }, + { + from: Color.Orange, + to: Color.Pink, + startMillis: 5000, + endMillis: 8000, + curve: Curve.EaseIn + }, + ] + } + }, + opacity: { + range: [0.0, 1.0], //粒子透明度的初始值从[0.0,1.0]随机产生 + updater: { + type: ParticleUpdater.CURVE, + config: [ + { + from: 0.0, + to: 1.0, + startMillis: 0, + endMillis: 3000, + curve: Curve.EaseIn + }, + { + from: 1.0, + to: 0.0, + startMillis: 5000, + endMillis: 10000, + curve: Curve.EaseIn + } + ] + } + }, + scale: { + range: [0.0, 0.0], + updater: { + type: ParticleUpdater.CURVE, + config: [ + { + from: 0.0, + to: 0.5, + startMillis: 0, + endMillis: 3000, + curve: Curve.EaseIn + } + ] + } + }, + acceleration: { + //加速度的配置,从大小和方向两个维度变化,speed表示加速度大小,angle表示加速度方向 + speed: { + range: [3, 9], + updater: { + type: ParticleUpdater.RANDOM, + config: [1, 20] + } + }, + angle: { + range: [90, 90] + } + } + + } + ] + }).width(300).height(300).disturbanceFields([{ + strength: 10, + shape: DisturbanceFieldShape.RECT, + size: { width: 100, height: 100 }, + position: { x: 100, y: 100 }, + feather: 15, + noiseScale: 10, + noiseFrequency: 15, + noiseAmplitude: 5 + }]) + }.width('100%').height('100%').align(Alignment.Center) + } +} +// [End particle_example3] \ No newline at end of file diff --git a/ArkUIKit/Animation/entry/src/main/ets/pages/particle/template4/Index.ets b/ArkUIKit/Animation/entry/src/main/ets/pages/particle/template4/Index.ets new file mode 100644 index 0000000000000000000000000000000000000000..1ce18cc795d9d0e2729a85fe8e03eb96b60f5052 --- /dev/null +++ b/ArkUIKit/Animation/entry/src/main/ets/pages/particle/template4/Index.ets @@ -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 particle_example4] +@Entry +@Component +struct ParticleExample4 { + @State emitterProperties: Array = [ + { + index: 0, + emitRate: 100, + position: { x: 60, y: 80 }, + size: { width: 200, height: 200 } + } + ]; + + build() { + Stack() { + Text() + .width(300).height(300).backgroundColor(Color.Black) + Particle({ + particles: [ + { + emitter: { + particle: { + type: ParticleType.POINT, // 粒子类型 + config: { + radius: 5// 圆点半径 + }, + count: 400, // 粒子总数 + lifetime: -1// 粒子的生命周期,-1表示粒子生命周期无限大 + }, + emitRate: 10, // 每秒发射粒子数 + position: [0, 0], // 粒子发射位置 + shape: ParticleEmitterShape.CIRCLE// 发射器形状 + }, + color: { + range: [Color.Red, Color.Yellow], // 初始颜色范围 + updater: { + type: ParticleUpdater.CURVE, // 变化方式为曲线变化 + config: [ + { + from: Color.White, + to: Color.Pink, + startMillis: 0, + endMillis: 3000, + curve: Curve.EaseIn + }, + { + from: Color.Pink, + to: Color.Orange, + startMillis: 3000, + endMillis: 5000, + curve: Curve.EaseIn + }, + { + from: Color.Orange, + to: Color.Pink, + startMillis: 5000, + endMillis: 8000, + curve: Curve.EaseIn + }, + ] + } + }, + }, + ] + }) + .width(300) + .height(300) + .emitter(this.emitterProperties) + }.width('100%').height('100%').align(Alignment.Center) + } +} +// [End particle_example4] \ No newline at end of file diff --git a/ArkUIKit/Animation/entry/src/main/ets/pages/particle/template5/Index.ets b/ArkUIKit/Animation/entry/src/main/ets/pages/particle/template5/Index.ets new file mode 100644 index 0000000000000000000000000000000000000000..2c7d8375d5fc7f49c3ba33bf47de84fb04c335a8 --- /dev/null +++ b/ArkUIKit/Animation/entry/src/main/ets/pages/particle/template5/Index.ets @@ -0,0 +1,94 @@ +/* + * 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 { LengthMetrics } from '@kit.ArkUI'; + +// [Start particle_example5] +@Entry +@Component +struct ParticleExample5 { + build() { + Stack() { + Text() + .width(300).height(300).backgroundColor(Color.Black) + Particle({ + particles: [ + { + emitter: { + particle: { + type: ParticleType.POINT, //粒子类型 + config: { + radius: 5//圆点半径 + }, + count: 2000, //粒子总数 + lifetime: 10000, //粒子生命周期,单位ms + lifetimeRange: 100//粒子生命周期取值范围,单位ms + }, + emitRate: 100, //每秒发射粒子数 + shape: ParticleEmitterShape.ANNULUS,//环形发射器 + annulusRegion:{ + center:{x:LengthMetrics.percent(0.5),y:LengthMetrics.percent(0.5)}, // 圆环的圆心坐标 + innerRadius:LengthMetrics.vp(100), // 圆环的外圆半径 + outerRadius:LengthMetrics.vp(120), // 圆环的内圆半径 + startAngle:0, // 圆环的起始角度 + endAngle:360 // 圆环的结束角度 + } + }, + color: { + range: [Color.Pink, Color.White], + }, + opacity: { + range: [0.0, 1.0], + updater: { + type: ParticleUpdater.CURVE, + config: [ + { + from: 0.0, + to: 1.0, + startMillis: 0, + endMillis: 3000, + curve: Curve.EaseIn + }, + { + from: 1.0, + to: 0.0, + startMillis: 5000, + endMillis: 10000, + curve: Curve.EaseIn + } + ] + } + }, + scale: { + range: [0.0, 0.0], + updater: { + type: ParticleUpdater.CURVE, + config: [ + { + from: 0.0, + to: 0.5, + startMillis: 0, + endMillis: 3000, + curve: Curve.EaseIn + } + ] + } + }, + } + ] + }).width(300).height(300) + }.width('100%').height('100%').align(Alignment.Center) + } +} +// [End particle_example5] \ No newline at end of file diff --git a/ArkUIKit/Animation/entry/src/main/ets/pages/particle/template6/Index.ets b/ArkUIKit/Animation/entry/src/main/ets/pages/particle/template6/Index.ets new file mode 100644 index 0000000000000000000000000000000000000000..b56c8f455c9f87b2bc6d12b2c174964872cb0117 --- /dev/null +++ b/ArkUIKit/Animation/entry/src/main/ets/pages/particle/template6/Index.ets @@ -0,0 +1,131 @@ +/* + * 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 { LengthMetrics } from '@kit.ArkUI' + +// [Start particle_example6] +@Entry +@Component +struct ParticleExample6 { + + @State radius: number = 1; + @State shape: ParticleEmitterShape = ParticleEmitterShape.ANNULUS; + @State emitRate: number = 200; + @State count: number = 2000; + private timerID: number = -1; + private centerX: LengthMetrics = LengthMetrics.percent(0.5); + private centerY: LengthMetrics = LengthMetrics.percent(0.5); + private inRadius: LengthMetrics = LengthMetrics.vp(120); + private outRadius: LengthMetrics = LengthMetrics.vp(120); + private startAngle: number = 0; + private endAngle: number = 90; + @State emitterProperties: Array = [ + { + index: 0, + emitRate: 100, + annulusRegion: { + center:{x:this.centerX, y: this.centerY}, // 圆环的圆心坐标 + outerRadius: this.outRadius, // 圆环的外圆半径 + innerRadius: this.inRadius, // 圆环的内圆半径 + startAngle: -90, // 圆环的起始角度 + endAngle: 0 // 圆环的结束角度 + } + } + ]; + @State region: ParticleAnnulusRegion = { + center:{x:this.centerX, y: this.centerY}, + outerRadius: this.outRadius, + innerRadius: this.inRadius, + startAngle: -90, + endAngle: 0 + }; + + aboutToDisappear(): void { + // 页面销毁时清除计时器 + if (this.timerID != -1) { + clearInterval(this.timerID); + } + } + + build() { + Column({ space: 10}) { + Stack() { + Text() + .width(300).height(300).backgroundColor(Color.Black) + + Particle({ + particles: [ + { + emitter: { + particle: { + type: ParticleType.POINT, // 粒子类型 + config: { + radius: this.radius // 圆点半径 + }, + count: this.count, // 粒子总数 + lifetime: -1 // 粒子的生命周期,-1表示粒子生命周期无限大 + }, + emitRate: this.emitRate, // 每秒发射粒子数 + shape: this.shape, //发射器形状 + annulusRegion: this.region + }, + color: { + range: [Color.White, Color.Pink], // 初始颜色范围 + }, + }, + ] + }).width('100%') + .height('100%') + .emitter(this.emitterProperties) + .onClick(()=>{ + // 清除已有定时器 + if (this.timerID != -1) { + clearInterval(this.timerID); + } + + // 创建定时器(每秒更新) + this.timerID = setInterval(() => { + this.emitterProperties = [ + { + index: 0, + emitRate: this.emitRate, + annulusRegion: { + center:{x:this.centerX, y: this.centerY}, + outerRadius: this.outRadius, + innerRadius: this.inRadius, + startAngle: this.startAngle, + endAngle: this.endAngle + } + } + ]; + if (this.endAngle >= 270) { + if (this.timerID != -1) { + clearInterval(this.timerID); + } + return; + } + // 更新角度值(5度/秒) + this.startAngle += 30; + this.endAngle += 30; + }, 1000); + + }) + } + .width('100%') + .height('100%') + .align(Alignment.Center) + } + } +} +// [End particle_example6] \ No newline at end of file diff --git a/ArkUIKit/Animation/entry/src/main/ets/pages/rotation/template1/Index.ets b/ArkUIKit/Animation/entry/src/main/ets/pages/rotation/template1/Index.ets new file mode 100644 index 0000000000000000000000000000000000000000..ec7946947d9710cb03e48463203c133899e82866 --- /dev/null +++ b/ArkUIKit/Animation/entry/src/main/ets/pages/rotation/template1/Index.ets @@ -0,0 +1,31 @@ +/* + * 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 { display } from '@kit.ArkUI'; + +@Entry +@Component +struct rotation { + + build() { + Stack() { + Image($r('app.media.tree')) + .position({ x: 0, y: 0 }) + .size({ width: 100, height: 100 }) + .id('image1') + } + .backgroundColor(Color.White) + .size({ width: '100%', height: '100%' }) + } +} \ No newline at end of file diff --git a/ArkUIKit/Animation/entry/src/main/ets/pages/rotation/template2/Index.ets b/ArkUIKit/Animation/entry/src/main/ets/pages/rotation/template2/Index.ets new file mode 100644 index 0000000000000000000000000000000000000000..29f6df2372d6e936055ff5a0d10091c2c4fb4d9e --- /dev/null +++ b/ArkUIKit/Animation/entry/src/main/ets/pages/rotation/template2/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 { display } from '@kit.ArkUI'; + +@Entry +@Component +struct rotation { + + // 获取通过监听窗口的windowsSizeChange事件得到的屏幕显示方向 + @StorageLink('orientation') myOrientation: display.Orientation = display.Orientation.PORTRAIT; + + build() { + Stack() { + + // 当屏幕显示方向变化时,切换组件的视图效果 + if (this.myOrientation == display.Orientation.PORTRAIT || this.myOrientation == display.Orientation.PORTRAIT_INVERTED) { + Image($r('app.media.sky')) + .size({ width: 100, height: 100 }) + .id('image1') + + // 开发者也可以通过自行设置transition的TransitionEffect.OPACITY转场效果来实现旋转屏动画的透明度变化 + // .transition(TransitionEffect.OPACITY) + } else { + Image($r('app.media.tree')) + .position({ x: 0, y: 0 }) + .size({ width: 200, height: 200 }) + .id('image2') + + // 开发者也可以通过自行设置transition的TransitionEffect.OPACITY来实现旋转屏动画的透明度变化 + // .transition(TransitionEffect.OPACITY) + } + } + .backgroundColor(Color.White) + .size({ width: '100%', height: '100%' }) + } +} \ No newline at end of file diff --git a/ArkUIKit/Animation/entry/src/main/ets/pages/shareTransition/template1/Index.ets b/ArkUIKit/Animation/entry/src/main/ets/pages/shareTransition/template1/Index.ets new file mode 100644 index 0000000000000000000000000000000000000000..520b62a1a3b93bab55d1c0cf8c1346253909ea71 --- /dev/null +++ b/ArkUIKit/Animation/entry/src/main/ets/pages/shareTransition/template1/Index.ets @@ -0,0 +1,28 @@ +/* + * 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. + */ +@Entry +@Component +struct SharedTransitionExample { + + build() { + Column() { + Image($r('app.media.ic_health_heart')).width(50).height(50).margin({ left: 20, top: 20 }) + .sharedTransition('sharedImage', { duration: 800, curve: Curve.Linear, delay: 100 }) + }.width('100%').height('100%').alignItems(HorizontalAlign.Start) + .onClick(() => { + this.getUIContext().getRouter().pushUrl({ url: 'pages/shareTransition/template1/PageB' }) + }) + } +} \ No newline at end of file diff --git a/ArkUIKit/Animation/entry/src/main/ets/pages/shareTransition/template1/PageB.ets b/ArkUIKit/Animation/entry/src/main/ets/pages/shareTransition/template1/PageB.ets new file mode 100644 index 0000000000000000000000000000000000000000..7fa35ab5e86e2a2dfeeaf34f60aafa9aa1ccad58 --- /dev/null +++ b/ArkUIKit/Animation/entry/src/main/ets/pages/shareTransition/template1/PageB.ets @@ -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. + */ +@Entry +@Component +struct pageBExample { + build() { + Stack() { + Image($r('app.media.ic_health_heart')).width(150).height(150) + .sharedTransition('sharedImage', { duration: 800, curve: Curve.Linear, delay: 100 }) + }.width('100%').height('100%') + } +} \ No newline at end of file diff --git a/ArkUIKit/Animation/entry/src/main/module.json5 b/ArkUIKit/Animation/entry/src/main/module.json5 new file mode 100644 index 0000000000000000000000000000000000000000..00d847b7bfd514973fbade9f670e96253df4a7be --- /dev/null +++ b/ArkUIKit/Animation/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", + "orientation": "auto_rotation", + "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/Animation/entry/src/main/resources/base/element/color.json b/ArkUIKit/Animation/entry/src/main/resources/base/element/color.json new file mode 100644 index 0000000000000000000000000000000000000000..3c712962da3c2751c2b9ddb53559afcbd2b54a02 --- /dev/null +++ b/ArkUIKit/Animation/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/Animation/entry/src/main/resources/base/element/float.json b/ArkUIKit/Animation/entry/src/main/resources/base/element/float.json new file mode 100644 index 0000000000000000000000000000000000000000..153478e3f449f86a897686bc35316bd4fc96fb99 --- /dev/null +++ b/ArkUIKit/Animation/entry/src/main/resources/base/element/float.json @@ -0,0 +1,17 @@ +{ + "float": [ + { + "name": "page_text_font_size", + "value": "50fp" + }, { + "name": "size_16", + "value": "16" + }, { + "name": "size_100", + "value": "100" + }, { + "name": "size_64", + "value": "64" + } + ] +} diff --git a/ArkUIKit/Animation/entry/src/main/resources/base/element/string.json b/ArkUIKit/Animation/entry/src/main/resources/base/element/string.json new file mode 100644 index 0000000000000000000000000000000000000000..0f731181cd22043f5d3baa117350a0b9a493a9cc --- /dev/null +++ b/ArkUIKit/Animation/entry/src/main/resources/base/element/string.json @@ -0,0 +1,328 @@ +{ + "string": [ + { + "name": "module_desc", + "value": "module description" + }, + { + "name": "EntryAbility_desc", + "value": "description" + }, + { + "name": "EntryAbility_label", + "value": "Animation" + }, + { + "name": "navigation_toolbar_add", + "value": "add" + }, + { + "name": "navigation_toolbar_app", + "value": "app" + }, + { + "name": "page1", + "value": "页面1" + }, + { + "name": "page2", + "value": "页面2" + }, + { + "name": "create", + "value": "创建" + }, + { + "name": "cancel", + "value": "取消" + }, + { + "name": "complete", + "value": "完成" + }, + { + "name": "playing", + "value": "播放中" + }, + { + "name": "animatorStatus", + "value": "当前动画状态为:" + }, + { + "name": "play", + "value": "播放" + }, + { + "name": "reset", + "value": "重置" + }, + { + "name": "pause", + "value": "暂停" + }, + { + "name": "originalImage", + "value": "原图" + }, + { + "name": "animation_blur_text1", + "value": "手指不在屏幕上" + }, + { + "name": "animation_blur_text2", + "value": "按住屏幕上下滑动" + }, + { + "name": "animation_blur_text3", + "value": "当前手指所在y轴位置 : " + }, + { + "name": "animation_blur_text4", + "value": "当前图片模糊程度为 : " + }, + { + "name": "navigation_toolbar_collect", + "value": "collect" + }, + { + "name": "temp1", + "value": "示例1" + }, + { + "name": "animate_to_label", + "value": "显示动画(animateTo)" + }, + { + "name": "animate_to_temp_label1", + "value": "示例1(在组件出现时创建动画)" + }, + { + "name": "animate_to_temp_label2", + "value": "示例2(动画执行结束后组件消失)" + }, + { + "name": "animate_to_temp_label3", + "value": "示例3(在状态管理V2中使用animateTo)" + }, + { + "name": "animation_label", + "value": "属性动画(animation)" + }, + { + "name": "animation_temp_label2", + "value": "示例2(使用animateTo产生属性动画)" + }, + { + "name": "animation_temp_label3", + "value": "示例3(使用animation产生属性动画)" + }, + { + "name": "animation_temp_label4", + "value": "示例4(使用keyframeAnimateTo产生属性动画)" + }, + { + "name": "cohesion_label", + "value": "动画衔接" + }, + { + "name": "cohesion_temp_label1", + "value": "示例1(动画衔接)" + }, + { + "name": "cohesion_temp_label2", + "value": "示例2(手势与动画的衔接)" + }, + { + "name": "keyframeAnimateTo_label", + "value": "关键帧动画" + }, + { + "name": "pageTransition_label", + "value": "页面间转场" + }, + { + "name": "pageTransition_temp_label1", + "value": "示例1(设置退入场动画)" + }, + { + "name": "pageTransition_temp_label2", + "value": "示例2(设置退入场平移效果)" + }, + { + "name": "pageTransition_temp_label3", + "value": "示例3(不推荐)(利用pushUrl跳转能力)" + }, + { + "name": "pageTransition_temp_label4", + "value": "示例4(不推荐)(type为None的页面转场)" + }, + { + "name": "pageTransition_temp_label5", + "value": "示例5(不推荐)(type配置为RouteType.None)" + }, + { + "name": "pageTransition_temp_label6", + "value": "示例6(不推荐)(type配置为RouteType.Push或RouteType.Pop)" + }, + { + "name": "compTransition_label", + "value": "组件内转场" + }, + { + "name": "compTransition_temp_label1", + "value": "示例1(使用同一接口实现图片出现消失)" + }, + { + "name": "compTransition_temp_label2", + "value": "示例2(使用不同接口实现图片出现消失)" + }, + { + "name": "compTransition_temp_label3", + "value": "示例3(设置父子组件为transition)" + }, + { + "name": "compTransition_temp_label4", + "value": "示例4(出现/消失转场)" + }, + { + "name": "compTransition_temp_label5", + "value": "示例5(多个组件渐次出现消失)" + }, + { + "name": "compTransition_temp_label6", + "value": "示例6(旋转转场效果出现/消失)" + }, + { + "name": "shareTransition_label", + "value": "共享元素转场" + }, + { + "name": "motionPath_label", + "value": "路径动画" + }, + { + "name": "particle_label", + "value": "粒子动画" + }, + { + "name": "particle_temp_label1", + "value": "示例1(圆形初始化粒子)" + }, + { + "name": "particle_temp_label2", + "value": "示例2(图片初始化粒子)" + }, + { + "name": "particle_temp_label3", + "value": "示例3(粒子扰动场的干扰下运动轨迹发生变化)" + }, + { + "name": "particle_temp_label4", + "value": "示例4(调整粒子发射器位置)" + }, + { + "name": "particle_temp_label5", + "value": "示例5(环形发射器创建)" + }, + { + "name": "particle_temp_label6", + "value": "示例6(环形发射器更新)" + }, + { + "name": "animator_label", + "value": "帧动画" + }, + { + "name": "animator_temp_label1", + "value": "示例1(基于ArkTS扩展的声明式开发范式)" + }, + { + "name": "animator_temp_label2", + "value": "示例2(位移动画示例)" + }, + { + "name": "animator_temp_label3", + "value": "示例3(使用帧动画实现小球抛物运动)" + }, + { + "name": "animator_temp_label4", + "value": "示例4(使用帧动画实现小球抛物运动)" + }, + { + "name": "animateToImmediately_label", + "value": "显式动画立即下发" + }, + { + "name": "rotation_label", + "value": "旋转屏动画" + }, + { + "name": "rotation_temp_label1", + "value": "示例1(布局切换的旋转屏动画)" + }, + { + "name": "rotation_temp_label2", + "value": "示例2(透明度变化的旋转屏动画)" + }, + { + "name": "component_label", + "value": "组件动画" + }, + { + "name": "component_temp_label1", + "value": "示例1(Scroll组件滑动动效)" + }, + { + "name": "component_temp_label2", + "value": "示例2(List组件动态替换动效)" + }, + { + "name": "animatableProperty_label", + "value": "自定义属性动画" + }, + { + "name": "animatableProperty_temp_label1", + "value": "示例1(改变Text组件宽度)" + }, + { + "name": "animatableProperty_temp_label2", + "value": "示例2(改变图形形状)" + }, + { + "name": "animatableProperty_AnimatableProperty", + "value": "AnimatableProperty" + }, + { + "name": "animatableProperty_Play", + "value": "Play" + }, + { + "name": "AnimateIndex", + "value": "AnimateIndex" + }, + { + "name": "animation_blur_label", + "value": "背景模糊" + }, + { + "name": "animation_blur_label1", + "value": "示例1(使用backdropBlur为组件添加背景模糊)" + }, + { + "name": "animation_blur_label2", + "value": "示例2(使用blur为组件添加内容模糊)" + }, + { + "name": "animation_blur_label3", + "value": "示例3(使用backgroundBlurStyle为组件添加背景模糊效果)" + }, + { + "name": "animation_blur_label4", + "value": "示例4(使用foregroundBlurStyle为组件添加内容模糊效果)" + }, + { + "name": "animation_blur_label5", + "value": "示例5(使用motionBlur为组件添加运动模糊效果)" + } + ] +} \ No newline at end of file diff --git a/ArkUIKit/Animation/entry/src/main/resources/base/media/background.png b/ArkUIKit/Animation/entry/src/main/resources/base/media/background.png new file mode 100644 index 0000000000000000000000000000000000000000..923f2b3f27e915d6871871deea0420eb45ce102f Binary files /dev/null and b/ArkUIKit/Animation/entry/src/main/resources/base/media/background.png differ diff --git a/ArkUIKit/Animation/entry/src/main/resources/base/media/bg.JPG b/ArkUIKit/Animation/entry/src/main/resources/base/media/bg.JPG new file mode 100644 index 0000000000000000000000000000000000000000..77d1db9c5ae70097ed69f7c9d2fcae8a751e8fff Binary files /dev/null and b/ArkUIKit/Animation/entry/src/main/resources/base/media/bg.JPG differ diff --git a/ArkUIKit/Animation/entry/src/main/resources/base/media/book.JPG b/ArkUIKit/Animation/entry/src/main/resources/base/media/book.JPG new file mode 100644 index 0000000000000000000000000000000000000000..c2ad0955113af2e2ad0228837c86427b3022bd86 Binary files /dev/null and b/ArkUIKit/Animation/entry/src/main/resources/base/media/book.JPG differ diff --git a/ArkUIKit/Animation/entry/src/main/resources/base/media/drawer.png b/ArkUIKit/Animation/entry/src/main/resources/base/media/drawer.png new file mode 100644 index 0000000000000000000000000000000000000000..97014d3e10e5ff511409c378cd4255713aecd85f Binary files /dev/null and b/ArkUIKit/Animation/entry/src/main/resources/base/media/drawer.png differ diff --git a/ArkUIKit/Animation/entry/src/main/resources/base/media/foreground.png b/ArkUIKit/Animation/entry/src/main/resources/base/media/foreground.png new file mode 100644 index 0000000000000000000000000000000000000000..97014d3e10e5ff511409c378cd4255713aecd85f Binary files /dev/null and b/ArkUIKit/Animation/entry/src/main/resources/base/media/foreground.png differ diff --git a/ArkUIKit/Animation/entry/src/main/resources/base/media/forest.png b/ArkUIKit/Animation/entry/src/main/resources/base/media/forest.png new file mode 100644 index 0000000000000000000000000000000000000000..25165d3dac9606d9078b49a9853c66c9cb77320a Binary files /dev/null and b/ArkUIKit/Animation/entry/src/main/resources/base/media/forest.png differ diff --git a/ArkUIKit/Animation/entry/src/main/resources/base/media/heart.JPG b/ArkUIKit/Animation/entry/src/main/resources/base/media/heart.JPG new file mode 100644 index 0000000000000000000000000000000000000000..c2ad0955113af2e2ad0228837c86427b3022bd86 Binary files /dev/null and b/ArkUIKit/Animation/entry/src/main/resources/base/media/heart.JPG differ diff --git a/ArkUIKit/Animation/entry/src/main/resources/base/media/ic_health_heart.JPG b/ArkUIKit/Animation/entry/src/main/resources/base/media/ic_health_heart.JPG new file mode 100644 index 0000000000000000000000000000000000000000..c0843441f0fa499317d594a0f81a0f169ac4cad9 Binary files /dev/null and b/ArkUIKit/Animation/entry/src/main/resources/base/media/ic_health_heart.JPG differ diff --git a/ArkUIKit/Animation/entry/src/main/resources/base/media/ic_public_highlights.svg b/ArkUIKit/Animation/entry/src/main/resources/base/media/ic_public_highlights.svg new file mode 100644 index 0000000000000000000000000000000000000000..7f0c77423290d138e1c06b9de163af52d0ba0195 --- /dev/null +++ b/ArkUIKit/Animation/entry/src/main/resources/base/media/ic_public_highlights.svg @@ -0,0 +1,13 @@ + + + Public/ic_public_collect + + + + + + + + + + \ No newline at end of file diff --git a/ArkUIKit/Animation/entry/src/main/resources/base/media/ic_public_highlightsed.svg b/ArkUIKit/Animation/entry/src/main/resources/base/media/ic_public_highlightsed.svg new file mode 100644 index 0000000000000000000000000000000000000000..bda82973349ceba0d7de8e9f85d704844cb31318 --- /dev/null +++ b/ArkUIKit/Animation/entry/src/main/resources/base/media/ic_public_highlightsed.svg @@ -0,0 +1,13 @@ + + + Public/ic_public_collected + + + + + + + + + + \ No newline at end of file diff --git a/ArkUIKit/Animation/entry/src/main/resources/base/media/icon.png b/ArkUIKit/Animation/entry/src/main/resources/base/media/icon.png new file mode 100644 index 0000000000000000000000000000000000000000..205ad8b5a8a42e8762fbe4899b8e5e31ce822b8b Binary files /dev/null and b/ArkUIKit/Animation/entry/src/main/resources/base/media/icon.png differ diff --git a/ArkUIKit/Animation/entry/src/main/resources/base/media/icon_2.png b/ArkUIKit/Animation/entry/src/main/resources/base/media/icon_2.png new file mode 100644 index 0000000000000000000000000000000000000000..923f2b3f27e915d6871871deea0420eb45ce102f Binary files /dev/null and b/ArkUIKit/Animation/entry/src/main/resources/base/media/icon_2.png differ diff --git a/ArkUIKit/Animation/entry/src/main/resources/base/media/image.JPG b/ArkUIKit/Animation/entry/src/main/resources/base/media/image.JPG new file mode 100644 index 0000000000000000000000000000000000000000..29bd746fee2f280b5a97640c3c91125bb0934ca1 Binary files /dev/null and b/ArkUIKit/Animation/entry/src/main/resources/base/media/image.JPG differ diff --git a/ArkUIKit/Animation/entry/src/main/resources/base/media/image_1.png b/ArkUIKit/Animation/entry/src/main/resources/base/media/image_1.png new file mode 100644 index 0000000000000000000000000000000000000000..8b474587838c8cc696fc7747dfe9b1c70f80dc2d Binary files /dev/null and b/ArkUIKit/Animation/entry/src/main/resources/base/media/image_1.png differ diff --git a/ArkUIKit/Animation/entry/src/main/resources/base/media/img_1.JPG b/ArkUIKit/Animation/entry/src/main/resources/base/media/img_1.JPG new file mode 100644 index 0000000000000000000000000000000000000000..461eda6a6847cb09d9d6569a4258009d414610e8 Binary files /dev/null and b/ArkUIKit/Animation/entry/src/main/resources/base/media/img_1.JPG differ diff --git a/ArkUIKit/Animation/entry/src/main/resources/base/media/layered_image.json b/ArkUIKit/Animation/entry/src/main/resources/base/media/layered_image.json new file mode 100644 index 0000000000000000000000000000000000000000..fb49920440fb4d246c82f9ada275e26123a2136a --- /dev/null +++ b/ArkUIKit/Animation/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/Animation/entry/src/main/resources/base/media/mountain.jpg b/ArkUIKit/Animation/entry/src/main/resources/base/media/mountain.jpg new file mode 100644 index 0000000000000000000000000000000000000000..3c244ab4218031e18dd0069e240e558622924668 Binary files /dev/null and b/ArkUIKit/Animation/entry/src/main/resources/base/media/mountain.jpg differ diff --git a/ArkUIKit/Animation/entry/src/main/resources/base/media/r.JPG b/ArkUIKit/Animation/entry/src/main/resources/base/media/r.JPG new file mode 100644 index 0000000000000000000000000000000000000000..cd3fef02a58cabe165cb12fde35cb4c249afa5a4 Binary files /dev/null and b/ArkUIKit/Animation/entry/src/main/resources/base/media/r.JPG differ diff --git a/ArkUIKit/Animation/entry/src/main/resources/base/media/sky.JPG b/ArkUIKit/Animation/entry/src/main/resources/base/media/sky.JPG new file mode 100644 index 0000000000000000000000000000000000000000..c2ad0955113af2e2ad0228837c86427b3022bd86 Binary files /dev/null and b/ArkUIKit/Animation/entry/src/main/resources/base/media/sky.JPG differ diff --git a/ArkUIKit/Animation/entry/src/main/resources/base/media/startIcon.png b/ArkUIKit/Animation/entry/src/main/resources/base/media/startIcon.png new file mode 100644 index 0000000000000000000000000000000000000000..205ad8b5a8a42e8762fbe4899b8e5e31ce822b8b Binary files /dev/null and b/ArkUIKit/Animation/entry/src/main/resources/base/media/startIcon.png differ diff --git a/ArkUIKit/Animation/entry/src/main/resources/base/media/sun.jpg b/ArkUIKit/Animation/entry/src/main/resources/base/media/sun.jpg new file mode 100644 index 0000000000000000000000000000000000000000..c2ad0955113af2e2ad0228837c86427b3022bd86 Binary files /dev/null and b/ArkUIKit/Animation/entry/src/main/resources/base/media/sun.jpg differ diff --git a/ArkUIKit/Animation/entry/src/main/resources/base/media/test.JPG b/ArkUIKit/Animation/entry/src/main/resources/base/media/test.JPG new file mode 100644 index 0000000000000000000000000000000000000000..cc6a0782c6ff9609f0f790c6562b7ab9c549830e Binary files /dev/null and b/ArkUIKit/Animation/entry/src/main/resources/base/media/test.JPG differ diff --git a/ArkUIKit/Animation/entry/src/main/resources/base/media/testImage.JPG b/ArkUIKit/Animation/entry/src/main/resources/base/media/testImage.JPG new file mode 100644 index 0000000000000000000000000000000000000000..cc6a0782c6ff9609f0f790c6562b7ab9c549830e Binary files /dev/null and b/ArkUIKit/Animation/entry/src/main/resources/base/media/testImage.JPG differ diff --git a/ArkUIKit/Animation/entry/src/main/resources/base/media/testImg.jpg b/ArkUIKit/Animation/entry/src/main/resources/base/media/testImg.jpg new file mode 100644 index 0000000000000000000000000000000000000000..9fb37bd1079db72818f5e375973c80fb670c7a70 Binary files /dev/null and b/ArkUIKit/Animation/entry/src/main/resources/base/media/testImg.jpg differ diff --git a/ArkUIKit/Animation/entry/src/main/resources/base/media/testlinearGradientBlurOrigin.JPG b/ArkUIKit/Animation/entry/src/main/resources/base/media/testlinearGradientBlurOrigin.JPG new file mode 100644 index 0000000000000000000000000000000000000000..e2e542fcde54adf541a680c384bf8477b41548eb Binary files /dev/null and b/ArkUIKit/Animation/entry/src/main/resources/base/media/testlinearGradientBlurOrigin.JPG differ diff --git a/ArkUIKit/Animation/entry/src/main/resources/base/media/transition_image1.jpg b/ArkUIKit/Animation/entry/src/main/resources/base/media/transition_image1.jpg new file mode 100644 index 0000000000000000000000000000000000000000..9fb37bd1079db72818f5e375973c80fb670c7a70 Binary files /dev/null and b/ArkUIKit/Animation/entry/src/main/resources/base/media/transition_image1.jpg differ diff --git a/ArkUIKit/Animation/entry/src/main/resources/base/media/transition_image2.png b/ArkUIKit/Animation/entry/src/main/resources/base/media/transition_image2.png new file mode 100644 index 0000000000000000000000000000000000000000..af8d4c98a86f23a41841d07b74636926a17d1c89 Binary files /dev/null and b/ArkUIKit/Animation/entry/src/main/resources/base/media/transition_image2.png differ diff --git a/ArkUIKit/Animation/entry/src/main/resources/base/media/tree.JPG b/ArkUIKit/Animation/entry/src/main/resources/base/media/tree.JPG new file mode 100644 index 0000000000000000000000000000000000000000..bdad6db5558c4190bccb951489e8bc67fc0ababe Binary files /dev/null and b/ArkUIKit/Animation/entry/src/main/resources/base/media/tree.JPG differ diff --git a/ArkUIKit/Animation/entry/src/main/resources/base/profile/backup_config.json b/ArkUIKit/Animation/entry/src/main/resources/base/profile/backup_config.json new file mode 100644 index 0000000000000000000000000000000000000000..78f40ae7c494d71e2482278f359ec790ca73471a --- /dev/null +++ b/ArkUIKit/Animation/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/Animation/entry/src/main/resources/base/profile/main_pages.json b/ArkUIKit/Animation/entry/src/main/resources/base/profile/main_pages.json new file mode 100644 index 0000000000000000000000000000000000000000..4e87fb1383a571552cc66eada16f5e567525200c --- /dev/null +++ b/ArkUIKit/Animation/entry/src/main/resources/base/profile/main_pages.json @@ -0,0 +1,53 @@ +{ + "src": [ + "pages/Index", + "pages/animateTo/template1/Index", + "pages/animateTo/template2/Index", + "pages/animateTo/template3/Index", + "pages/animation/template1/Index", + "pages/animation/template2/Index", + "pages/animation/template3/Index", + "pages/animation/template4/Index", + "pages/animator/template1/Index", + "pages/animator/template2/Index", + "pages/animator/template3/Index", + "pages/animator/template4/Index", + "pages/particle/template1/Index", + "pages/particle/template2/Index", + "pages/particle/template3/Index", + "pages/particle/template4/Index", + "pages/particle/template5/Index", + "pages/particle/template6/Index", + "pages/keyframeAnimateTo/template1/Index", + "pages/pageTransition/template1/Index", + "pages/pageTransition/template1/Page1", + "pages/pageTransition/template2/Index", + "pages/pageTransition/template2/Page1", + "pages/pageTransition/template3/pageTransitionDst1", + "pages/pageTransition/template3/pageTransitionSrc1", + "pages/pageTransition/template4/pageTransitionDst2", + "pages/pageTransition/template4/pageTransitionSrc2", + "pages/pageTransition/template5/PageTransitionSrc3", + "pages/pageTransition/template5/PageTransitionDst3", + "pages/pageTransition/template6/PageTransitionSrc4", + "pages/pageTransition/template6/PageTransitionDst4", + "pages/compTransition/template1/Index", + "pages/compTransition/template2/Index", + "pages/compTransition/template3/Index", + "pages/compTransition/template4/Index", + "pages/compTransition/template5/Index", + "pages/compTransition/template6/Index", + "pages/shareTransition/template1/Index", + "pages/shareTransition/template1/PageB", + "pages/motionPath/template1/Index", + "pages/animateToImmediately/template1/Index", + "pages/rotation/template1/Index", + "pages/rotation/template2/Index", + "pages/cohesion/template1/Index", + "pages/cohesion/template2/Index", + "pages/animatableProperty/template1/Index", + "pages/animatableProperty/template2/Index", + "pages/component/template1/Index", + "pages/component/template2/Index" + ] +} diff --git a/ArkUIKit/Animation/entry/src/main/resources/dark/element/color.json b/ArkUIKit/Animation/entry/src/main/resources/dark/element/color.json new file mode 100644 index 0000000000000000000000000000000000000000..79b11c2747aec33e710fd3a7b2b3c94dd9965499 --- /dev/null +++ b/ArkUIKit/Animation/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/Animation/entry/src/main/syscap.json b/ArkUIKit/Animation/entry/src/main/syscap.json new file mode 100644 index 0000000000000000000000000000000000000000..2ad5ecf67d33285b846db67b6bcd695d31ceeaaf --- /dev/null +++ b/ArkUIKit/Animation/entry/src/main/syscap.json @@ -0,0 +1,25 @@ +{ + "devices": { + "general": [ + "default" + ], + "custom": [ + { + "xts": [ + "SystemCapability.Multimedia.Media.AVTranscoder", + "SystemCapability.Telephony.CellularData", + "SystemCapability.Communication.Bluetooth.Core", + "SystemCapability.Telephony.CoreService", + "SystemCapability.Telephony.StateRegistry", + "SystemCapability.Telephony.SmsMms", + "SystemCapability.Telephony.CallManager", + "SystemCapability.DistributedHardware.DeviceManager", + "SystemCapability.Multimedia.Drm.Core", + "SystemCapability.Advertising.Ads", + "SystemCapability.BundleManager.AppDomainVerify", + "SystemCapability.Customization.EnterpriseDeviceManager" + ] + } + ] + } +} \ No newline at end of file diff --git a/ArkUIKit/Animation/entry/src/mock/mock-config.json5 b/ArkUIKit/Animation/entry/src/mock/mock-config.json5 new file mode 100644 index 0000000000000000000000000000000000000000..7a73a41bfdf76d6f793007240d80983a52f15f97 --- /dev/null +++ b/ArkUIKit/Animation/entry/src/mock/mock-config.json5 @@ -0,0 +1,2 @@ +{ +} \ No newline at end of file diff --git a/ArkUIKit/Animation/entry/src/ohosTest/ets/test/Ability.test.ets b/ArkUIKit/Animation/entry/src/ohosTest/ets/test/Ability.test.ets new file mode 100644 index 0000000000000000000000000000000000000000..aed4de76e80ab8b0faebfb534695eec8911ad966 --- /dev/null +++ b/ArkUIKit/Animation/entry/src/ohosTest/ets/test/Ability.test.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. + */ +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. + }) + /* + * @tc.number: Animation_assertContain + * @tc.name: Test ability + * @tc.desc: Test ability + * @tc.size: MediumTest + * @tc.type: Function + * @tc.level Level 1 + */ + 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); + hilog.info(0x0000, 'testTag', '%{public}s', 'it end'); + }) + }) +} \ No newline at end of file diff --git a/ArkUIKit/Animation/entry/src/ohosTest/ets/test/AnimatableProperty.test.ets b/ArkUIKit/Animation/entry/src/ohosTest/ets/test/AnimatableProperty.test.ets new file mode 100644 index 0000000000000000000000000000000000000000..7100f61c4508b6a8f25f76d7b8515cabd2a6dacd --- /dev/null +++ b/ArkUIKit/Animation/entry/src/ohosTest/ets/test/AnimatableProperty.test.ets @@ -0,0 +1,117 @@ +/* + * 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, Component, Driver } from '@kit.TestKit'; +import { afterEach, beforeAll, describe, expect, it } from '@ohos/hypium'; +import { ON } from '@ohos.UiTest'; +import resource from '../../../main/ets/common/resource'; +import { hilog } from '@kit.PerformanceAnalysisKit'; + +const delegator: abilityDelegatorRegistry.AbilityDelegator = abilityDelegatorRegistry.getAbilityDelegator(); + +const driver = Driver.create(); +const BUNDLE = 'Animation_'; +const TAG = '[Sample_Animation]'; +const DOMAIN = 0xF811; + +let aimComponent: Component; + +export function AnimatablePropertyTest() { + describe('Animation_AnimatablePropertyTest', () => { + + beforeAll(async () => { + await delegator.startAbility({ + bundleName: 'com.samples.animation', + abilityName: 'EntryAbility' + }); + await driver.delayMs(3000); + + aimComponent = await driver.findComponent(ON.text(resource.resourceToString($r('app.string.animatableProperty_label')))); + await aimComponent.click(); + await driver.delayMs(1000); + }); + + afterEach(async () => { + aimComponent = await driver.findComponent(ON.text('AnimateIndex')); + do { + await driver.pressBack(); + aimComponent = await driver.findComponent(ON.text('AnimateIndex')); + } while (aimComponent == null); + }); + + /* + * @tc.number: Animation_AnimatablePropertyTest_001 + * @tc.name: Set animate (AnimatablePropertyExample) + * @tc.desc: Set animate (AnimatablePropertyExample) + * @tc.size: MediumTest + * @tc.type: Function + * @tc.level Level 1 + */ + it(BUNDLE + 'AnimatablePropertyTest_001', 0, async () => { + hilog.info(DOMAIN, TAG, 'Animation_AnimatablePropertyTest_001_begin'); + + aimComponent = await driver.findComponent(ON.text(resource.resourceToString($r('app.string.animatableProperty_temp_label1')))); + if (!aimComponent) { + return; + } + await aimComponent.click(); + await driver.delayMs(1000); + + const playBtn = await driver.findComponent(ON.text(resource.resourceToString($r('app.string.animatableProperty_Play')))); + if (!playBtn) { + return; + } + + for (let i = 0; i < 2; i++) { + await playBtn.click(); + await driver.delayMs(2500); + } + + hilog.info(DOMAIN, TAG, 'Animation_AnimatablePropertyTest_001_end'); + }); + + /* + * @tc.number: Animation_AnimatablePropertyTest_002 + * @tc.name: component disappear in animate (AnimatedShape) + * @tc.desc: component disappear in animate (AnimatedShape) + * @tc.size: MediumTest + * @tc.type: Function + * @tc.level Level 1 + */ + it(BUNDLE + 'AnimatablePropertyTest_002', 0, async () => { + hilog.info(DOMAIN, TAG, 'Animation_AnimatablePropertyTest_002_begin'); + + aimComponent = await driver.findComponent(ON.text(resource.resourceToString($r('app.string.animatableProperty_temp_label2')))); + if (!aimComponent) { + return; + } + await aimComponent.click(); + await driver.delayMs(1000); + + const polylineList = await driver.findComponents(ON.type('Polyline')); + if (polylineList.length === 0) { + return; + } + const targetPolyline = polylineList[0]; + + for (let i = 0; i < 2; i++) { + await targetPolyline.click(); + await driver.delayMs(2500); + } + + hilog.info(DOMAIN, TAG, 'Animation_AnimatablePropertyTest_002_end'); + }); + + }); +} \ No newline at end of file diff --git a/ArkUIKit/Animation/entry/src/ohosTest/ets/test/AnimateTo.test.ets b/ArkUIKit/Animation/entry/src/ohosTest/ets/test/AnimateTo.test.ets new file mode 100644 index 0000000000000000000000000000000000000000..77b70639c521d91c92f3d33abd8469d0755dfc45 --- /dev/null +++ b/ArkUIKit/Animation/entry/src/ohosTest/ets/test/AnimateTo.test.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, Component, Driver } from '@kit.TestKit'; +import { afterEach, beforeAll, describe, expect, it } from '@ohos/hypium'; +import { ON } from '@ohos.UiTest'; +import resource from '../../../main/ets/common/resource'; +import { hilog } from '@kit.PerformanceAnalysisKit'; + +const delegator: abilityDelegatorRegistry.AbilityDelegator = abilityDelegatorRegistry.getAbilityDelegator() + +const driver = Driver.create(); +const BUNDLE = 'Animation_' +const TAG = '[Sample_Animation]'; +const DOMAIN = 0xF811 + +let aimComponent : Component + +export function AnimateToTest() { + describe('Animation_AnimateToTest', () => { + + beforeAll(async () => { + await delegator.startAbility({ + bundleName: 'com.samples.animation', + abilityName: 'EntryAbility' + }); + await driver.delayMs(3000); + + aimComponent = await driver.findComponent(ON.text(resource.resourceToString($r('app.string.animate_to_label')))); + await aimComponent.click(); + await driver.delayMs(1000); + }) + + afterEach(async () => { + aimComponent = await driver.findComponent(ON.text('AnimateIndex')); + do { + await driver.pressBack(); + aimComponent = await driver.findComponent(ON.text('AnimateIndex')); + } while (aimComponent == null) + }) + + /* + * @tc.number: Animation_AnimateToTest_001 + * @tc.name: Set animate + * @tc.desc: Set animate + * @tc.size: MediumTest + * @tc.type: Function + * @tc.level Level 1 + */ + it(BUNDLE + 'AnimateToTest_001', 0, async () => { + hilog.info(DOMAIN, TAG, 'Animation_AnimateToTest_001_begin'); + aimComponent = await driver.findComponent(ON.text(resource.resourceToString($r('app.string.animate_to_temp_label1')))); + await aimComponent.click(); + await driver.delayMs(1000); + + aimComponent = await driver.findComponent(ON.text('change size')) + await aimComponent.click(); + await driver.delayMs(5000); + hilog.info(DOMAIN, TAG, 'Animation_AnimateToTest_001_end'); + }) + + /* + * @tc.number: Animation_AnimateToTest_002 + * @tc.name: component disappear in animate + * @tc.desc: component disappear in animate + * @tc.size: MediumTest + * @tc.type: Function + * @tc.level Level 1 + */ + it(BUNDLE + 'AnimateToTest_002', 0, async () => { + hilog.info(DOMAIN, TAG, 'Animation_AnimateToTest_002_begin'); + aimComponent = await driver.findComponent(ON.text(resource.resourceToString($r('app.string.animate_to_temp_label2')))); + await aimComponent.click(); + await driver.delayMs(1000); + + let columns = await driver.findComponents(ON.type('Column')) + await columns[1].click(); + await driver.delayMs(5000); + hilog.info(DOMAIN, TAG, 'Animation_AnimateToTest_002_end'); + }) + + /* + * @tc.number: Animation_AnimateToTest_003 + * @tc.name: Set animate in componentV2 + * @tc.desc: Set animate in componentV2 + * @tc.size: MediumTest + * @tc.type: Function + * @tc.level Level 1 + */ + it(BUNDLE + 'AnimateToTest_003', 0, async () => { + hilog.info(DOMAIN, TAG, 'Animation_AnimateToTest_003_begin'); + aimComponent = await driver.findComponent(ON.text(resource.resourceToString($r('app.string.animate_to_temp_label3')))); + await aimComponent.click(); + await driver.delayMs(1000); + + aimComponent = await driver.findComponent(ON.text('change size')) + await aimComponent.click(); + await driver.delayMs(5000); + hilog.info(DOMAIN, TAG, 'Animation_AnimateToTest_003_end'); + }) + + }) +} \ No newline at end of file diff --git a/ArkUIKit/Animation/entry/src/ohosTest/ets/test/AnimateToImmediately.test.ets b/ArkUIKit/Animation/entry/src/ohosTest/ets/test/AnimateToImmediately.test.ets new file mode 100644 index 0000000000000000000000000000000000000000..c96cf0018a67be47b7659442c3cd2844ddd7551d --- /dev/null +++ b/ArkUIKit/Animation/entry/src/ohosTest/ets/test/AnimateToImmediately.test.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. + */ +import { abilityDelegatorRegistry, Component, Driver } from '@kit.TestKit'; +import { afterEach, beforeAll, describe, expect, it } from '@ohos/hypium'; +import { ON } from '@ohos.UiTest'; +import resource from '../../../main/ets/common/resource'; +import { hilog } from '@kit.PerformanceAnalysisKit'; + +const delegator: abilityDelegatorRegistry.AbilityDelegator = abilityDelegatorRegistry.getAbilityDelegator() + +const driver = Driver.create(); +const BUNDLE = 'Animation_' +const TAG = '[Sample_Animation]'; +const DOMAIN = 0xF811 + +let aimComponent : Component + +export function AnimateToImmediatelyTest() { + describe('Animation_AnimateToImmediatelyTest', () => { + + beforeAll(async () => { + await delegator.startAbility({ + bundleName: 'com.samples.animation', + abilityName: 'EntryAbility' + }); + await driver.delayMs(3000); + + aimComponent = await driver.findComponent(ON.text(resource.resourceToString($r("app.string.animateToImmediately_label")))); + await aimComponent.click(); + await driver.delayMs(1000); + }) + + afterEach(async () => { + aimComponent = await driver.findComponent(ON.text('AnimateIndex')); + do { + await driver.pressBack(); + aimComponent = await driver.findComponent(ON.text('AnimateIndex')); + } while (aimComponent == null) + }) + + /* + * @tc.number: Animation_AnimateToImmediatelyTest_001 + * @tc.name: Set animate Immediately + * @tc.desc: Set animate Immediately + * @tc.size: MediumTest + * @tc.type: Function + * @tc.level Level 1 + */ + it(BUNDLE + 'AnimateToImmediatelyTest_001', 0, async () => { + hilog.info(DOMAIN, TAG, 'Animation_AnimateToImmediatelyTest_001_begin'); + aimComponent = await driver.findComponent(ON.text(resource.resourceToString($r("app.string.temp1")))); + await aimComponent.click(); + await driver.delayMs(1000); + + aimComponent = await driver.findComponent(ON.text('change size')); + await aimComponent.click(); + await driver.delayMs(5000); + hilog.info(DOMAIN, TAG, 'Animation_AnimateToImmediatelyTest_001_end'); + }) + + }) +} \ No newline at end of file diff --git a/ArkUIKit/Animation/entry/src/ohosTest/ets/test/Animation.test.ets b/ArkUIKit/Animation/entry/src/ohosTest/ets/test/Animation.test.ets new file mode 100644 index 0000000000000000000000000000000000000000..2af2bf3a5b62377950038e0009781f2d683ef816 --- /dev/null +++ b/ArkUIKit/Animation/entry/src/ohosTest/ets/test/Animation.test.ets @@ -0,0 +1,138 @@ +/* + * 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, Component, Driver } from '@kit.TestKit'; +import { afterEach, beforeAll, describe, expect, it } from '@ohos/hypium'; +import { ON } from '@ohos.UiTest'; +import resource from '../../../main/ets/common/resource'; +import { hilog } from '@kit.PerformanceAnalysisKit'; + +const delegator: abilityDelegatorRegistry.AbilityDelegator = abilityDelegatorRegistry.getAbilityDelegator() + +const driver = Driver.create(); +const BUNDLE = 'Animation_' +const TAG = '[Sample_Animation]'; +const DOMAIN = 0xF811 + +let aimComponent : Component + +export function AnimationTest() { + describe('Animation_AnimationTest', () => { + + beforeAll(async () => { + await delegator.startAbility({ + bundleName: 'com.samples.animation', + abilityName: 'EntryAbility' + }); + await driver.delayMs(3000); + + aimComponent = await driver.findComponent(ON.text(resource.resourceToString($r("app.string.animation_label")))); + await aimComponent.click(); + await driver.delayMs(1000); + }) + + afterEach(async () => { + aimComponent = await driver.findComponent(ON.text('AnimateIndex')); + do { + await driver.pressBack(); + aimComponent = await driver.findComponent(ON.text('AnimateIndex')); + } while (aimComponent == null) + }) + + /* + * @tc.number: Animation_AnimationTest_001 + * @tc.name: Set attribute animate use animation + * @tc.desc: Set attribute animate use animation + * @tc.size: MediumTest + * @tc.type: Function + * @tc.level Level 1 + */ + it(BUNDLE + 'AnimationTest_001', 0, async () => { + hilog.info(DOMAIN, TAG, 'Animation_AnimationTest_001_begin'); + aimComponent = await driver.findComponent(ON.text(resource.resourceToString($r("app.string.temp1")))); + await aimComponent.click(); + await driver.delayMs(1000); + + aimComponent = await driver.findComponent(ON.text('change size')) + await aimComponent.click(); + await driver.delayMs(1000); + + aimComponent = await driver.findComponent(ON.text('change rotate angle')) + await aimComponent.click(); + await driver.delayMs(5000); + hilog.info(DOMAIN, TAG, 'Animation_AnimationTest_001_end'); + }) + + /* + * @tc.number: Animation_AnimationTest_002 + * @tc.name: Set attribute animate use animationTo + * @tc.desc: Set attribute animate use animationTo + * @tc.size: MediumTest + * @tc.type: Function + * @tc.level Level 1 + */ + it(BUNDLE + 'AnimationTest_002', 0, async () => { + hilog.info(DOMAIN, TAG, 'Animation_AnimationTest_002_begin'); + aimComponent = await driver.findComponent(ON.text(resource.resourceToString($r("app.string.animation_temp_label2")))); + await aimComponent.click(); + await driver.delayMs(1000); + + aimComponent = await driver.findComponent(ON.type('Column')) + await aimComponent.click(); + await driver.delayMs(5000); + hilog.info(DOMAIN, TAG, 'Animation_AnimationTest_002_end'); + }) + + /* + * @tc.number: Animation_AnimationTest_003 + * @tc.name: Set attribute animate use animation + * @tc.desc: Set attribute animate use animation + * @tc.size: MediumTest + * @tc.type: Function + * @tc.level Level 1 + */ + it(BUNDLE + 'AnimationTest_003', 0, async () => { + hilog.info(DOMAIN, TAG, 'Animation_AnimationTest_003_begin'); + aimComponent = await driver.findComponent(ON.text(resource.resourceToString($r("app.string.animation_temp_label3")))); + await aimComponent.click(); + await driver.delayMs(1000); + + aimComponent = await driver.findComponent(ON.type('Column')) + await aimComponent.click(); + await driver.delayMs(5000); + hilog.info(DOMAIN, TAG, 'Animation_AnimationTest_003_end'); + }) + + /* + * @tc.number: Animation_AnimationTest_004 + * @tc.name: Set attribute animate use keyframeAnimateTo + * @tc.desc: Set attribute animate use keyframeAnimateTo + * @tc.size: MediumTest + * @tc.type: Function + * @tc.level Level 1 + */ + it(BUNDLE + 'AnimationTest_004', 0, async () => { + hilog.info(DOMAIN, TAG, 'Animation_AnimationTest_004_begin'); + aimComponent = await driver.findComponent(ON.text(resource.resourceToString($r("app.string.animation_temp_label4")))); + await aimComponent.click(); + await driver.delayMs(1000); + + aimComponent = await driver.findComponent(ON.type('Column')) + await aimComponent.click(); + await driver.delayMs(5000); + hilog.info(DOMAIN, TAG, 'Animation_AnimationTest_004_end'); + }) + + }) +} \ No newline at end of file diff --git a/ArkUIKit/Animation/entry/src/ohosTest/ets/test/AnimationBlur.test.ets b/ArkUIKit/Animation/entry/src/ohosTest/ets/test/AnimationBlur.test.ets new file mode 100644 index 0000000000000000000000000000000000000000..e2f196b84d88b26bdf6db0c3fae1dd2f98f9017f --- /dev/null +++ b/ArkUIKit/Animation/entry/src/ohosTest/ets/test/AnimationBlur.test.ets @@ -0,0 +1,145 @@ +/* + * 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, Component, Driver } from '@kit.TestKit'; +import { afterEach, beforeAll, describe, expect, it } from '@ohos/hypium'; +import { ON } from '@ohos.UiTest'; +import resource from '../../../main/ets/common/resource'; +import { hilog } from '@kit.PerformanceAnalysisKit'; + +const delegator: abilityDelegatorRegistry.AbilityDelegator = abilityDelegatorRegistry.getAbilityDelegator() + +const driver = Driver.create(); +const BUNDLE = 'AnimationBlur_' +const TAG = '[Sample_AnimationBlur]'; +const DOMAIN = 0xF811 + +let aimComponent : Component + +export function AnimationBlurTest() { + describe('Animation_AnimationBlurTest', () => { + + beforeAll(async () => { + await delegator.startAbility({ + bundleName: 'com.samples.animation', + abilityName: 'EntryAbility' + }); + await driver.delayMs(3000); + + aimComponent = await driver.findComponent(ON.text(resource.resourceToString($r("app.string.animation_blur_label")))); + await aimComponent.click(); + await driver.delayMs(1000); + }) + + afterEach(async () => { + aimComponent = await driver.findComponent(ON.text('AnimateIndex')); + do { + await driver.pressBack(); + aimComponent = await driver.findComponent(ON.text('AnimateIndex')); + } while (aimComponent == null) + }) + + /* + * @tc.number: Animation_AnimationBlurTest_001 + * @tc.name: Add background blur to components using backdropBlur + * @tc.desc: Add background blur to components using backdropBlur + * @tc.size: MediumTest + * @tc.type: Function + * @tc.level Level 1 + */ + it(BUNDLE + 'AnimationBlurTest_001', 0, async () => { + hilog.info(DOMAIN, TAG, 'Animation_AnimationBlurTest_001_begin'); + aimComponent = await driver.findComponent(ON.text(resource.resourceToString($r("app.string.animation_blur_label1")))); + await aimComponent.click(); + await driver.delayMs(1000); + hilog.info(DOMAIN, TAG, 'Animation_AnimationBlurTest_001_end'); + }) + + /* + * @tc.number: Animation_AnimationBlurTest_002 + * @tc.name: Add content blur to components using blur + * @tc.desc: Add content blur to components using blur + * @tc.size: MediumTest + * @tc.type: Function + * @tc.level Level 1 + */ + it(BUNDLE + 'AnimationBlurTest_002', 0, async () => { + hilog.info(DOMAIN, TAG, 'Animation_AnimationBlurTest_002_begin'); + aimComponent = await driver.findComponent(ON.text(resource.resourceToString($r("app.string.animation_blur_label2")))); + await aimComponent.click(); + await driver.delayMs(1000); + + await driver.swipe(500, 200, 500, 500) + await driver.delayMs(1000); + await driver.swipe(500, 500, 500, 200) + await driver.delayMs(1000); + hilog.info(DOMAIN, TAG, 'Animation_AnimationBlurTest_002_end'); + }) + + /* + * @tc.number: Animation_AnimationBlurTest_003 + * @tc.name: Add background blur effect to components using backgroundBlurStyle + * @tc.desc: Add background blur effect to components using backgroundBlurStyle + * @tc.size: MediumTest + * @tc.type: Function + * @tc.level Level 1 + */ + it(BUNDLE + 'AnimationBlurTest_003', 0, async () => { + hilog.info(DOMAIN, TAG, 'Animation_AnimationBlurTest_003_begin'); + aimComponent = await driver.findComponent(ON.text(resource.resourceToString($r("app.string.animation_blur_label3")))); + await aimComponent.click(); + await driver.delayMs(1000); + hilog.info(DOMAIN, TAG, 'Animation_AnimationBlurTest_003_end'); + }) + + /* + * @tc.number: Animation_AnimationBlurTest_004 + * @tc.name: Add content blurring effect to components using foregroundBlurStyle + * @tc.desc: Add content blurring effect to components using foregroundBlurStyle + * @tc.size: MediumTest + * @tc.type: Function + * @tc.level Level 1 + */ + it(BUNDLE + 'AnimationBlurTest_004', 0, async () => { + hilog.info(DOMAIN, TAG, 'Animation_AnimationBlurTest_004_begin'); + aimComponent = await driver.findComponent(ON.text(resource.resourceToString($r("app.string.animation_blur_label4")))); + await aimComponent.click(); + await driver.delayMs(1000); + hilog.info(DOMAIN, TAG, 'Animation_AnimationBlurTest_004_end'); + }) + + /* + * @tc.number: Animation_AnimationBlurTest_005 + * @tc.name: Add motion blur effects to components using motionBlur + * @tc.desc: Add motion blur effects to components using motionBlur + * @tc.size: MediumTest + * @tc.type: Function + * @tc.level Level 1 + */ + it(BUNDLE + 'AnimationBlurTest_005', 0, async () => { + hilog.info(DOMAIN, TAG, 'Animation_AnimationBlurTest_005_begin'); + aimComponent = await driver.findComponent(ON.text(resource.resourceToString($r("app.string.animation_blur_label5")))); + await aimComponent.click(); + await driver.delayMs(1000); + + aimComponent = await driver.findComponent(ON.type('Image')); + await aimComponent.click(); + await driver.delayMs(1000); + await aimComponent.click(); + await driver.delayMs(5000); + hilog.info(DOMAIN, TAG, 'Animation_AnimationBlurTest_005_end'); + }) + + }) +} \ No newline at end of file diff --git a/ArkUIKit/Animation/entry/src/ohosTest/ets/test/Animator.test.ets b/ArkUIKit/Animation/entry/src/ohosTest/ets/test/Animator.test.ets new file mode 100644 index 0000000000000000000000000000000000000000..2c9c3933931ff9f164d63990a34479aa79cf2a79 --- /dev/null +++ b/ArkUIKit/Animation/entry/src/ohosTest/ets/test/Animator.test.ets @@ -0,0 +1,202 @@ +/* + * 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, Component, Driver } from '@kit.TestKit'; +import { afterEach, beforeAll, describe, expect, it } from '@ohos/hypium'; +import { ON } from '@ohos.UiTest'; +import resource from '../../../main/ets/common/resource'; +import { hilog } from '@kit.PerformanceAnalysisKit'; + +const delegator: abilityDelegatorRegistry.AbilityDelegator = abilityDelegatorRegistry.getAbilityDelegator() + +const driver = Driver.create(); +const BUNDLE = 'Animation_' +const TAG = '[Sample_Animation]'; +const DOMAIN = 0xF811 + +let aimComponent : Component + +export function AnimatorTest() { + describe('Animation_AnimatorTest', () => { + + beforeAll(async () => { + await delegator.startAbility({ + bundleName: 'com.samples.animation', + abilityName: 'EntryAbility' + }); + await driver.delayMs(3000); + + aimComponent = await driver.findComponent(ON.text(resource.resourceToString($r("app.string.animator_label")))); + await aimComponent.click(); + await driver.delayMs(1000); + }) + + afterEach(async () => { + aimComponent = await driver.findComponent(ON.text('AnimateIndex')); + do { + await driver.pressBack(); + aimComponent = await driver.findComponent(ON.text('AnimateIndex')); + } while (aimComponent == null) + }) + + /* + * @tc.number: Animation_AnimatorTest_001 + * @tc.name: Set frame animate in arkTs + * @tc.desc: Set frame animate in arkTs + * @tc.size: MediumTest + * @tc.type: Function + * @tc.level Level 1 + */ + it(BUNDLE + 'AnimatorTest_001', 0, async () => { + hilog.info(DOMAIN, TAG, 'Animation_AnimatorTest_001_begin'); + aimComponent = await driver.findComponent(ON.text(resource.resourceToString($r("app.string.animator_temp_label1")))); + await aimComponent.click(); + await driver.delayMs(1000); + + aimComponent = await driver.findComponent(ON.text('create')); + await aimComponent.click(); + await driver.delayMs(1000); + + aimComponent = await driver.findComponent(ON.text('play')); + await aimComponent.click(); + await driver.delayMs(1000); + + aimComponent = await driver.findComponent(ON.text('pause')); + await aimComponent.click(); + await driver.delayMs(1000); + + aimComponent = await driver.findComponent(ON.text('finish')); + await aimComponent.click(); + await driver.delayMs(1000); + + aimComponent = await driver.findComponent(ON.text('reverse')); + await aimComponent.click(); + await driver.delayMs(1000); + + aimComponent = await driver.findComponent(ON.text('play')); + await aimComponent.click(); + await driver.delayMs(1000); + + aimComponent = await driver.findComponent(ON.text('cancel')); + await aimComponent.click(); + await driver.delayMs(1000); + + aimComponent = await driver.findComponent(ON.text('reset')); + await aimComponent.click(); + await driver.delayMs(1000); + + aimComponent = await driver.findComponent(ON.text('play')); + await aimComponent.click(); + await driver.delayMs(3000); + hilog.info(DOMAIN, TAG, 'Animation_AnimatorTest_001_end'); + }) + + /* + * @tc.number: Animation_AnimatorTest_002 + * @tc.name: Set frame animate + * @tc.desc: Set frame animate + * @tc.size: MediumTest + * @tc.type: Function + * @tc.level Level 1 + */ + it(BUNDLE + 'AnimatorTest_002', 0, async () => { + hilog.info(DOMAIN, TAG, 'Animation_AnimatorTest_002_begin'); + aimComponent = await driver.findComponent(ON.text(resource.resourceToString($r("app.string.animator_temp_label2")))); + await aimComponent.click(); + await driver.delayMs(1000); + + aimComponent = await driver.findComponent(ON.text('create')); + await aimComponent.click(); + await driver.delayMs(1000); + + aimComponent = await driver.findComponent(ON.text('play')); + await aimComponent.click(); + await driver.delayMs(1000); + + aimComponent = await driver.findComponent(ON.text('reset')); + await aimComponent.click(); + await driver.delayMs(1000); + + aimComponent = await driver.findComponent(ON.text('play')); + await aimComponent.click(); + await driver.delayMs(3000); + hilog.info(DOMAIN, TAG, 'Animation_AnimatorTest_002_end'); + }) + + /* + * @tc.number: Animation_AnimatorTest_003 + * @tc.name: Show ball moving with frame animate + * @tc.desc: Show ball moving with frame animate + * @tc.size: MediumTest + * @tc.type: Function + * @tc.level Level 1 + */ + it(BUNDLE + 'AnimatorTest_003', 0, async () => { + hilog.info(DOMAIN, TAG, 'Animation_AnimatorTest_003_begin'); + aimComponent = await driver.findComponent(ON.text(resource.resourceToString($r("app.string.animator_temp_label3")))); + await aimComponent.click(); + await driver.delayMs(1000); + + aimComponent = await driver.findComponent(ON.text(resource.resourceToString($r('app.string.play')))); + await aimComponent.click(); + await driver.delayMs(5000); + + aimComponent = await driver.findComponent(ON.text(resource.resourceToString($r('app.string.reset')))); + await aimComponent.click(); + await driver.delayMs(1000); + + aimComponent = await driver.findComponent(ON.text(resource.resourceToString($r('app.string.play')))); + await aimComponent.click(); + await driver.delayMs(2000); + + aimComponent = await driver.findComponent(ON.text(resource.resourceToString($r('app.string.pause')))); + await aimComponent.click(); + await driver.delayMs(1000); + hilog.info(DOMAIN, TAG, 'Animation_AnimatorTest_003_end'); + }) + + /* + * @tc.number: Animation_AnimatorTest_004 + * @tc.name: Show ball moving with frame animate + * @tc.desc: Show ball moving with frame animate + * @tc.size: MediumTest + * @tc.type: Function + * @tc.level Level 1 + */ + it(BUNDLE + 'AnimatorTest_004', 0, async () => { + hilog.info(DOMAIN, TAG, 'Animation_AnimatorTest_004_begin'); + aimComponent = await driver.findComponent(ON.text(resource.resourceToString($r("app.string.animator_temp_label4")))); + await aimComponent.click(); + await driver.delayMs(1000); + + aimComponent = await driver.findComponent(ON.text(resource.resourceToString($r('app.string.play')))); + await aimComponent.click(); + await driver.delayMs(5000); + + aimComponent = await driver.findComponent(ON.text(resource.resourceToString($r('app.string.reset')))); + await aimComponent.click(); + await driver.delayMs(1000); + + aimComponent = await driver.findComponent(ON.text(resource.resourceToString($r('app.string.play')))); + await aimComponent.click(); + await driver.delayMs(2000); + + aimComponent = await driver.findComponent(ON.text(resource.resourceToString($r('app.string.pause')))); + await aimComponent.click(); + await driver.delayMs(1000); + hilog.info(DOMAIN, TAG, 'Animation_AnimatorTest_004_end'); + }) + + }) +} \ No newline at end of file diff --git a/ArkUIKit/Animation/entry/src/ohosTest/ets/test/Cohesion.test.ets b/ArkUIKit/Animation/entry/src/ohosTest/ets/test/Cohesion.test.ets new file mode 100644 index 0000000000000000000000000000000000000000..92f43ce2dd1aa18b0b5c8ac1af2a5008bcc3a630 --- /dev/null +++ b/ArkUIKit/Animation/entry/src/ohosTest/ets/test/Cohesion.test.ets @@ -0,0 +1,96 @@ +/* + * 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, Component, Driver } from '@kit.TestKit'; +import { afterEach, beforeAll, describe, expect, it } from '@ohos/hypium'; +import { ON } from '@ohos.UiTest'; +import resource from '../../../main/ets/common/resource'; +import { hilog } from '@kit.PerformanceAnalysisKit'; + +const delegator: abilityDelegatorRegistry.AbilityDelegator = abilityDelegatorRegistry.getAbilityDelegator() + +const driver = Driver.create(); +const BUNDLE = 'Animation_' +const TAG = '[Sample_Animation]'; +const DOMAIN = 0xF811 + +let aimComponent : Component + +export function CohesionTest() { + describe('Animation_CohesionTest', () => { + + beforeAll(async () => { + await delegator.startAbility({ + bundleName: 'com.samples.animation', + abilityName: 'EntryAbility' + }); + await driver.delayMs(3000); + + aimComponent = await driver.findComponent(ON.text(resource.resourceToString($r("app.string.cohesion_label")))); + await aimComponent.click(); + await driver.delayMs(1000); + }) + + afterEach(async () => { + aimComponent = await driver.findComponent(ON.text('AnimateIndex')); + do { + await driver.pressBack(); + aimComponent = await driver.findComponent(ON.text('AnimateIndex')); + } while (aimComponent == null) + }) + + /* + * @tc.number: Animation_CohesionTest_001 + * @tc.name: Set Cohesion animate + * @tc.desc: Set Cohesion animate + * @tc.size: MediumTest + * @tc.type: Function + * @tc.level Level 1 + */ + it(BUNDLE + 'CohesionTest_001', 0, async () => { + hilog.info(DOMAIN, TAG, 'Animation_CohesionTest_001_begin'); + aimComponent = await driver.findComponent(ON.text(resource.resourceToString($r("app.string.cohesion_temp_label1")))); + await aimComponent.click(); + await driver.delayMs(1000); + + aimComponent = await driver.findComponent(ON.text('Click')) + await aimComponent.click(); + await driver.delayMs(1000); + hilog.info(DOMAIN, TAG, 'Animation_CohesionTest_001_end'); + }) + + /* + * @tc.number: Animation_CohesionTest_002 + * @tc.name: Set Cohesion animate with gesture + * @tc.desc: Set Cohesion animate with gesture + * @tc.size: MediumTest + * @tc.type: Function + * @tc.level Level 1 + */ + it(BUNDLE + 'CohesionTest_002', 0, async () => { + hilog.info(DOMAIN, TAG, 'Animation_CohesionTest_002_begin'); + aimComponent = await driver.findComponent(ON.text(resource.resourceToString($r("app.string.cohesion_temp_label2")))); + await aimComponent.click(); + await driver.delayMs(1000); + + let size = await driver.getDisplaySize() + let x = Math.floor(size.x * 0.284) + + await driver.swipe(x, Math.floor(size.y * 0.2013), x, Math.floor(size.y * 0.5544)); + await driver.delayMs(1000); + hilog.info(DOMAIN, TAG, 'Animation_CohesionTest_002_end'); + }) + + }) +} \ No newline at end of file diff --git a/ArkUIKit/Animation/entry/src/ohosTest/ets/test/Component.test.ets b/ArkUIKit/Animation/entry/src/ohosTest/ets/test/Component.test.ets new file mode 100644 index 0000000000000000000000000000000000000000..0a34eb00f19ddef49bc7d6b0c7b58bcf8235cfba --- /dev/null +++ b/ArkUIKit/Animation/entry/src/ohosTest/ets/test/Component.test.ets @@ -0,0 +1,144 @@ +/* + * 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, Component, Driver } from '@kit.TestKit'; +import { afterEach, beforeAll, describe, expect, it } from '@ohos/hypium'; +import { ON } from '@ohos.UiTest'; +import resource from '../../../main/ets/common/resource'; +import { hilog } from '@kit.PerformanceAnalysisKit'; + +const delegator: abilityDelegatorRegistry.AbilityDelegator = abilityDelegatorRegistry.getAbilityDelegator(); + +const driver = Driver.create(); +const BUNDLE = 'Animation_'; +const TAG = '[Sample_Animation]'; +const DOMAIN = 0xF811; + +let aimComponent: Component; + +export function ComponentTest() { + describe('Animation_ComponentTest', () => { + + beforeAll(async () => { + await delegator.startAbility({ + bundleName: 'com.samples.animation', + abilityName: 'EntryAbility' + }); + await driver.delayMs(3000); + + aimComponent = await driver.findComponent(ON.text(resource.resourceToString($r("app.string.component_label")))); + await aimComponent.click(); + await driver.delayMs(1000); + }); + + afterEach(async () => { + aimComponent = await driver.findComponent(ON.text('AnimateIndex')); + do { + await driver.pressBack(); + aimComponent = await driver.findComponent(ON.text('AnimateIndex')); + } while (aimComponent == null); + await driver.delayMs(1000); + }); + + /* + * @tc.number: Animation_ComponentTest_001 + * @tc.name: Animation_ComponentTest_001 + * @tc.desc: Test TaskSwitchMainPage component animation + * @tc.size: MediumTest + * @tc.type: Function + * @tc.level Level 1 + */ + it(BUNDLE + 'ComponentTest_001', 0, async () => { + hilog.info(DOMAIN, TAG, 'Animation_ComponentTest_001_begin'); + + aimComponent = await driver.findComponent(ON.text(resource.resourceToString($r("app.string.component_temp_label1")))); + await aimComponent.click(); + await driver.delayMs(1000); + + const switchButton = await driver.findComponent(ON.text('Move to first/last')); + + await switchButton.click(); + await driver.delayMs(1500); + + await switchButton.click(); + await driver.delayMs(1500); + + const displaySize = await driver.getDisplaySize(); + const screenWidth = displaySize.x; + const centerY = Math.floor(displaySize.y * 0.5); + + await driver.swipe( + Math.floor(screenWidth * 0.7), + centerY, + Math.floor(screenWidth * 0.3), + centerY, + 500 + ); + await driver.delayMs(1000); + + await driver.swipe( + Math.floor(screenWidth * 0.3), + centerY, + Math.floor(screenWidth * 0.7), + centerY, + 500 + ); + await driver.delayMs(1000); + + hilog.info(DOMAIN, TAG, 'Animation_ComponentTest_001_end'); + }); + + /* + * @tc.number: Animation_ComponentTest_002 + * @tc.name: Animation_ComponentTest_002 + * @tc.desc: Test ListAutoSortExample component animation + * @tc.size: MediumTest + * @tc.type: Function + * @tc.level Level 1 + */ + it(BUNDLE + 'ComponentTest_002', 0, async () => { + hilog.info(DOMAIN, TAG, 'Animation_ComponentTest_002_begin'); + + aimComponent = await driver.findComponent(ON.text(resource.resourceToString($r("app.string.component")))); + await aimComponent.click(); + await driver.delayMs(1000); + + const firstGroup = await driver.findComponent(ON.text('first ListItemGroup')); + const secondGroup = await driver.findComponent(ON.text('second ListItemGroup')); + + const displaySize = await driver.getDisplaySize(); + const itemWidth = displaySize.x; + const itemHeight = 100; + const targetItemY = Math.floor(displaySize.y * 0.4); + + await driver.swipe( + Math.floor(itemWidth * 0.9), + targetItemY, + Math.floor(itemWidth * 0.1), + targetItemY, + 300 + ); + await driver.delayMs(500); + + const toTopButton = await driver.findComponent(ON.text('To TOP')); + await toTopButton.click(); + await driver.delayMs(1500); + + const firstItem = await driver.findComponent(ON.text('3')); + + hilog.info(DOMAIN, TAG, 'Animation_ComponentTest_002_end'); + }); + + }); +} \ No newline at end of file diff --git a/ArkUIKit/Animation/entry/src/ohosTest/ets/test/ComponentTransition.test.ets b/ArkUIKit/Animation/entry/src/ohosTest/ets/test/ComponentTransition.test.ets new file mode 100644 index 0000000000000000000000000000000000000000..715c571e442faad3e719e4e0c9c164555f854527 --- /dev/null +++ b/ArkUIKit/Animation/entry/src/ohosTest/ets/test/ComponentTransition.test.ets @@ -0,0 +1,225 @@ +/* + * 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, Component, Driver } from '@kit.TestKit'; +import { afterEach, beforeAll, describe, expect, it } from '@ohos/hypium'; +import { ON } from '@ohos.UiTest'; +import resource from '../../../main/ets/common/resource'; +import { hilog } from '@kit.PerformanceAnalysisKit'; + +const delegator: abilityDelegatorRegistry.AbilityDelegator = abilityDelegatorRegistry.getAbilityDelegator() + +const driver = Driver.create(); +const BUNDLE = 'Animation_' +const TAG = '[Sample_Animation]'; +const DOMAIN = 0xF811 + +let aimComponent : Component + +export function ComponentTransitionTest() { + describe('Animation_ComponentTransitionTest', () => { + + beforeAll(async () => { + await delegator.startAbility({ + bundleName: 'com.samples.animation', + abilityName: 'EntryAbility' + }); + await driver.delayMs(3000); + + aimComponent = await driver.findComponent(ON.text(resource.resourceToString($r("app.string.compTransition_label")))); + await aimComponent.click(); + await driver.delayMs(1000); + }) + + afterEach(async () => { + aimComponent = await driver.findComponent(ON.text('AnimateIndex')); + do { + await driver.pressBack(); + aimComponent = await driver.findComponent(ON.text('AnimateIndex')); + } while (aimComponent == null) + }) + + /* + * @tc.number: Animation_ComponentTransitionTest_001 + * @tc.name: Set image animate with one api + * @tc.desc: Set image animate with one api + * @tc.size: MediumTest + * @tc.type: Function + * @tc.level Level 1 + */ + it(BUNDLE + 'ComponentTransitionTest_001', 0, async () => { + hilog.info(DOMAIN, TAG, 'Animation_ComponentTransitionTest_001_begin'); + aimComponent = await driver.findComponent(ON.text(resource.resourceToString($r("app.string.compTransition_temp_label1")))); + await aimComponent.click(); + await driver.delayMs(3000); + + aimComponent = await driver.findComponent(ON.text('show')); + await aimComponent.click(); + await driver.delayMs(3000); + + aimComponent = await driver.findComponent(ON.text('hide')); + await aimComponent.click(); + await driver.delayMs(3000); + hilog.info(DOMAIN, TAG, 'Animation_ComponentTransitionTest_001_end'); + }) + + /* + * @tc.number: Animation_ComponentTransitionTest_002 + * @tc.name: Set image animate with different api + * @tc.desc: Set image animate with different api + * @tc.size: MediumTest + * @tc.type: Function + * @tc.level Level 1 + */ + it(BUNDLE + 'ComponentTransitionTest_002', 0, async () => { + hilog.info(DOMAIN, TAG, 'Animation_ComponentTransitionTest_002_begin'); + aimComponent = await driver.findComponent(ON.text(resource.resourceToString($r("app.string.compTransition_temp_label2")))); + await aimComponent.click(); + await driver.delayMs(3000); + + aimComponent = await driver.findComponent(ON.text('show')); + await aimComponent.click(); + await driver.delayMs(3000); + + aimComponent = await driver.findComponent(ON.text('hide')); + await aimComponent.click(); + await driver.delayMs(3000); + hilog.info(DOMAIN, TAG, 'Animation_ComponentTransitionTest_002_end'); + }) + + /* + * @tc.number: Animation_ComponentTransitionTest_003 + * @tc.name: Set Parent component transition + * @tc.desc: Set Parent component transition + * @tc.size: MediumTest + * @tc.type: Function + * @tc.level Level 1 + */ + it(BUNDLE + 'ComponentTransitionTest_003', 0, async () => { + hilog.info(DOMAIN, TAG, 'Animation_ComponentTransitionTest_003_begin'); + aimComponent = await driver.findComponent(ON.text(resource.resourceToString($r("app.string.compTransition_temp_label3")))); + await aimComponent.click(); + await driver.delayMs(3000); + + aimComponent = await driver.findComponent(ON.text('show')); + await aimComponent.click(); + await driver.delayMs(3000); + + aimComponent = await driver.findComponent(ON.text('hide')); + await aimComponent.click(); + await driver.delayMs(3000); + hilog.info(DOMAIN, TAG, 'Animation_ComponentTransitionTest_003_end'); + }) + + /* + * @tc.number: Animation_ComponentTransitionTest_004 + * @tc.name: Transition in show and disappear + * @tc.desc: Transition in show and disappear + * @tc.size: MediumTest + * @tc.type: Function + * @tc.level Level 1 + */ + it(BUNDLE + 'ComponentTransitionTest_004', 0, async () => { + hilog.info(DOMAIN, TAG, 'Animation_ComponentTransitionTest_004_begin'); + aimComponent = await driver.findComponent(ON.text(resource.resourceToString($r("app.string.compTransition_temp_label4")))); + await aimComponent.click(); + await driver.delayMs(3000); + + aimComponent = await driver.findComponent(ON.text('Click')); + await aimComponent.click(); + await driver.delayMs(3000); + + aimComponent = await driver.findComponent(ON.text('Click')); + await aimComponent.click(); + await driver.delayMs(3000); + hilog.info(DOMAIN, TAG, 'Animation_ComponentTransitionTest_004_end'); + }) + + /* + * @tc.number: Animation_ComponentTransitionTest_005 + * @tc.name: Show components and disappear + * @tc.desc: Show components and disappear + * @tc.size: MediumTest + * @tc.type: Function + * @tc.level Level 1 + */ + it(BUNDLE + 'ComponentTransitionTest_005', 0, async () => { + hilog.info(DOMAIN, TAG, 'Animation_ComponentTransitionTest_005_begin'); + aimComponent = await driver.findComponent(ON.text(resource.resourceToString($r("app.string.compTransition_temp_label5")))); + await aimComponent.click(); + await driver.delayMs(1000); + + aimComponent = await driver.findComponent(ON.type('root')); + await aimComponent.click(); + await driver.delayMs(3000); + + aimComponent = await driver.findComponent(ON.type('root')); + await aimComponent.click(); + await driver.delayMs(3000); + hilog.info(DOMAIN, TAG, 'Animation_ComponentTransitionTest_005_end'); + }) + + /* + * @tc.number: Animation_ComponentTransitionTest_006 + * @tc.name: Add or remove component trigger method + * @tc.desc: Add or remove component trigger method + * @tc.size: MediumTest + * @tc.type: Function + * @tc.level Level 1 + */ + it(BUNDLE + 'ComponentTransitionTest_006', 0, async () => { + hilog.info(DOMAIN, TAG, 'Animation_ComponentTransitionTest_006_begin'); + // Find and click the target component + aimComponent = await driver.findComponent(ON.text(resource.resourceToString($r("app.string.compTransition_temp_label6")))); + await aimComponent.click(); + await driver.delayMs(3000); + + // Find and click the component with the text 'Click1' + aimComponent = await driver.findComponent(ON.text('Click1')); + await aimComponent.click(); + await driver.delayMs(3000); + + aimComponent = await driver.findComponent(ON.text('Click1')); + await aimComponent.click(); + await driver.delayMs(3000); + hilog.info(DOMAIN, TAG, 'Animation_ComponentTransitionTest_006_end'); + }) + + /* + * @tc.number: Animation_ComponentTransitionTest_007 + * @tc.name: Add or remove component trigger method + * @tc.desc: Add or remove component trigger method + * @tc.size: MediumTest + * @tc.type: Function + * @tc.level Level 1 + */ + it(BUNDLE + 'ComponentTransitionTest_007', 0, async () => { + hilog.info(DOMAIN, TAG, 'Animation_ComponentTransitionTest_007_begin'); + // Find and click the target component + aimComponent = await driver.findComponent(ON.text(resource.resourceToString($r("app.string.compTransition_temp_label6")))); + await aimComponent.click(); + await driver.delayMs(3000); + + // Find and click the component with the text 'Click2' + aimComponent = await driver.findComponent(ON.text('Click2')); + await aimComponent.click(); + await driver.delayMs(3000); + + aimComponent = await driver.findComponent(ON.text('Click2')); + await aimComponent.click(); + await driver.delayMs(3000); + hilog.info(DOMAIN, TAG, 'Animation_ComponentTransitionTest_007_end'); + }) + }) +} \ No newline at end of file diff --git a/ArkUIKit/Animation/entry/src/ohosTest/ets/test/KeyFrameAnimateTo.test.ets b/ArkUIKit/Animation/entry/src/ohosTest/ets/test/KeyFrameAnimateTo.test.ets new file mode 100644 index 0000000000000000000000000000000000000000..21c1ff6bf3195aaa8a4bbb1d1c9532a2a1529e4c --- /dev/null +++ b/ArkUIKit/Animation/entry/src/ohosTest/ets/test/KeyFrameAnimateTo.test.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. + */ +import { abilityDelegatorRegistry, Component, Driver } from '@kit.TestKit'; +import { afterEach, beforeAll, describe, expect, it } from '@ohos/hypium'; +import { ON } from '@ohos.UiTest'; +import resource from '../../../main/ets/common/resource'; +import { hilog } from '@kit.PerformanceAnalysisKit'; + +const delegator: abilityDelegatorRegistry.AbilityDelegator = abilityDelegatorRegistry.getAbilityDelegator() + +const driver = Driver.create(); +const BUNDLE = 'Animation_' +const TAG = '[Sample_Animation]'; +const DOMAIN = 0xF811 + +let aimComponent : Component + +export function KeyFrameAnimateToTest() { + describe('Animation_KeyFrameAnimateToTest', () => { + + beforeAll(async () => { + await delegator.startAbility({ + bundleName: 'com.samples.animation', + abilityName: 'EntryAbility' + }); + await driver.delayMs(3000); + + aimComponent = await driver.findComponent(ON.text(resource.resourceToString($r("app.string.keyframeAnimateTo_label")))); + await aimComponent.click(); + await driver.delayMs(1000); + }) + + afterEach(async () => { + aimComponent = await driver.findComponent(ON.text('AnimateIndex')); + do { + await driver.pressBack(); + aimComponent = await driver.findComponent(ON.text('AnimateIndex')); + } while (aimComponent == null) + }) + + /* + * @tc.number: Animation_KeyFrameAnimateToTest_001 + * @tc.name: Set keyFrameAnimate + * @tc.desc: Set keyFrameAnimate + * @tc.size: MediumTest + * @tc.type: Function + * @tc.level Level 1 + */ + it(BUNDLE + 'KeyFrameAnimateToTest_001', 0, async () => { + hilog.info(DOMAIN, TAG, 'Animation_KeyFrameAnimateToTest_001_begin'); + aimComponent = await driver.findComponent(ON.text(resource.resourceToString($r("app.string.temp1")))); + await aimComponent.click(); + await driver.delayMs(1000); + + aimComponent = await driver.findComponent(ON.type('Circle')) + await aimComponent.click(); + await driver.delayMs(5000); + hilog.info(DOMAIN, TAG, 'Animation_KeyFrameAnimateToTest_001_end'); + }) + + }) +} \ No newline at end of file diff --git a/ArkUIKit/Animation/entry/src/ohosTest/ets/test/List.test.ets b/ArkUIKit/Animation/entry/src/ohosTest/ets/test/List.test.ets new file mode 100644 index 0000000000000000000000000000000000000000..c2c08d21df4eeb79b27cd658689ded15757a1798 --- /dev/null +++ b/ArkUIKit/Animation/entry/src/ohosTest/ets/test/List.test.ets @@ -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. + */ +import { AnimateToTest } from './AnimateTo.test'; +import { AnimationTest } from './Animation.test'; +import { CohesionTest } from './Cohesion.test'; +import { KeyFrameAnimateToTest } from './KeyFrameAnimateTo.test'; +import { PageTransitionTest } from './PageTransition.test'; +import { ComponentTransitionTest } from './ComponentTransition.test'; +import { ShareTransitionTest } from './ShareTransition.test'; +import { MotionPathTest } from './MotionPath.test'; +import { ParticleTest } from './Particle.test'; +import { AnimatorTest } from './Animator.test'; +import { AnimateToImmediatelyTest } from './AnimateToImmediately.test'; +import { RotationTest } from './Rotation.test'; +import { AnimatablePropertyTest } from './AnimatableProperty.test'; +import { ComponentTest } from './Component.test'; + + +export default function testsuite() { + AnimateToTest(); + AnimationTest(); + CohesionTest(); + KeyFrameAnimateToTest(); + PageTransitionTest(); + ComponentTransitionTest(); + ShareTransitionTest(); + MotionPathTest(); + ParticleTest(); + AnimatorTest(); + AnimateToImmediatelyTest(); + RotationTest(); + AnimatablePropertyTest(); + ComponentTest(); +} \ No newline at end of file diff --git a/ArkUIKit/Animation/entry/src/ohosTest/ets/test/MotionPath.test.ets b/ArkUIKit/Animation/entry/src/ohosTest/ets/test/MotionPath.test.ets new file mode 100644 index 0000000000000000000000000000000000000000..60eede8e336a3854be774d46ac5592f0173cc637 --- /dev/null +++ b/ArkUIKit/Animation/entry/src/ohosTest/ets/test/MotionPath.test.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. + */ +import { abilityDelegatorRegistry, Component, Driver } from '@kit.TestKit'; +import { afterEach, beforeAll, describe, expect, it } from '@ohos/hypium'; +import { ON } from '@ohos.UiTest'; +import resource from '../../../main/ets/common/resource'; +import { hilog } from '@kit.PerformanceAnalysisKit'; + +const delegator: abilityDelegatorRegistry.AbilityDelegator = abilityDelegatorRegistry.getAbilityDelegator() + +const driver = Driver.create(); +const BUNDLE = 'Animation_' +const TAG = '[Sample_Animation]'; +const DOMAIN = 0xF811 + +let aimComponent : Component + +export function MotionPathTest() { + describe('Animation_MotionPathTest', () => { + + beforeAll(async () => { + await delegator.startAbility({ + bundleName: 'com.samples.animation', + abilityName: 'EntryAbility' + }); + await driver.delayMs(3000); + + aimComponent = await driver.findComponent(ON.text(resource.resourceToString($r("app.string.motionPath_label")))); + await aimComponent.click(); + await driver.delayMs(1000); + }) + + afterEach(async () => { + aimComponent = await driver.findComponent(ON.text('AnimateIndex')); + do { + await driver.pressBack(); + aimComponent = await driver.findComponent(ON.text('AnimateIndex')); + } while (aimComponent == null) + }) + + /* + * @tc.number: Animation_MotionPathTest_001 + * @tc.name: Set motionPath + * @tc.desc: Set motionPath + * @tc.size: MediumTest + * @tc.type: Function + * @tc.level Level 1 + */ + it(BUNDLE + 'MotionPathTest_001', 0, async () => { + hilog.info(DOMAIN, TAG, 'Animation_MotionPathTest_001_begin'); + aimComponent = await driver.findComponent(ON.text(resource.resourceToString($r("app.string.temp1")))); + await aimComponent.click(); + await driver.delayMs(1000); + + aimComponent = await driver.findComponent(ON.text('click me')); + await aimComponent.click(); + await driver.delayMs(5000); + hilog.info(DOMAIN, TAG, 'Animation_MotionPathTest_001_end'); + }) + + }) +} \ No newline at end of file diff --git a/ArkUIKit/Animation/entry/src/ohosTest/ets/test/PageTransition.test.ets b/ArkUIKit/Animation/entry/src/ohosTest/ets/test/PageTransition.test.ets new file mode 100644 index 0000000000000000000000000000000000000000..9027381ca78bdb556c522deaf7ed7781deee04db --- /dev/null +++ b/ArkUIKit/Animation/entry/src/ohosTest/ets/test/PageTransition.test.ets @@ -0,0 +1,190 @@ +/* + * 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, Component, Driver } from '@kit.TestKit'; +import { afterEach, beforeAll, describe, expect, it } from '@ohos/hypium'; +import { ON } from '@ohos.UiTest'; +import resource from '../../../main/ets/common/resource'; +import { hilog } from '@kit.PerformanceAnalysisKit'; + +const delegator: abilityDelegatorRegistry.AbilityDelegator = abilityDelegatorRegistry.getAbilityDelegator() + +const driver = Driver.create(); +const BUNDLE = 'Animation_' +const TAG = '[Sample_Animation]'; +const DOMAIN = 0xF811 + +let aimComponent : Component + +export function PageTransitionTest() { + describe('Animation_PageTransitionTest', () => { + + beforeAll(async () => { + await delegator.startAbility({ + bundleName: 'com.samples.animation', + abilityName: 'EntryAbility' + }); + await driver.delayMs(3000); + + aimComponent = await driver.findComponent(ON.text(resource.resourceToString($r("app.string.pageTransition_label")))); + await aimComponent.click(); + await driver.delayMs(1000); + }) + + afterEach(async () => { + aimComponent = await driver.findComponent(ON.text('AnimateIndex')); + do { + await driver.pressBack(); + aimComponent = await driver.findComponent(ON.text('AnimateIndex')); + } while (aimComponent == null) + }) + + /* + * @tc.number: Animation_PageTransitionTest_001 + * @tc.name: Set pageTransition + * @tc.desc: Set pageTransition + * @tc.size: MediumTest + * @tc.type: Function + * @tc.level Level 1 + */ + it(BUNDLE + 'PageTransitionTest_001', 0, async () => { + hilog.info(DOMAIN, TAG, 'Animation_PageTransitionTest_001_begin'); + aimComponent = await driver.findComponent(ON.text(resource.resourceToString($r("app.string.pageTransition_temp_label1")))); + await aimComponent.click(); + await driver.delayMs(5000); + hilog.info(DOMAIN, TAG, 'Animation_PageTransitionTest_001_end'); + }) + + /* + * @tc.number: Animation_PageTransitionTest_002 + * @tc.name: Set move effect + * @tc.desc: Set move effect + * @tc.size: MediumTest + * @tc.type: Function + * @tc.level Level 1 + */ + it(BUNDLE + 'PageTransitionTest_002', 0, async () => { + hilog.info(DOMAIN, TAG, 'Animation_PageTransitionTest_002_begin'); + aimComponent = await driver.findComponent(ON.text(resource.resourceToString($r("app.string.pageTransition_temp_label2")))); + await aimComponent.click(); + await driver.delayMs(1000); + + aimComponent = await driver.findComponent(ON.text(resource.resourceToString($r('app.string.page1')))); + await aimComponent.click(); + await driver.delayMs(3000); + + aimComponent = await driver.findComponent(ON.text(resource.resourceToString($r('app.string.page2')))); + await aimComponent.click(); + await driver.delayMs(3000); + hilog.info(DOMAIN, TAG, 'Animation_PageTransitionTest_002_end'); + }) + + /* + * @tc.number: Animation_PageTransitionTest_003 + * @tc.name: Set pageTransition with pushUrl + * @tc.desc: Set pageTransition with pushUrl + * @tc.size: MediumTest + * @tc.type: Function + * @tc.level Level 1 + */ + it(BUNDLE + 'PageTransitionTest_003', 0, async () => { + hilog.info(DOMAIN, TAG, 'Animation_PageTransitionTest_003_begin'); + aimComponent = await driver.findComponent(ON.text(resource.resourceToString($r("app.string.pageTransition_temp_label3")))); + await aimComponent.click(); + await driver.delayMs(1000); + + aimComponent = await driver.findComponent(ON.text('pushUrl')); + await aimComponent.click(); + await driver.delayMs(3000); + + aimComponent = await driver.findComponent(ON.text('back')); + await aimComponent.click(); + await driver.delayMs(3000); + hilog.info(DOMAIN, TAG, 'Animation_PageTransitionTest_003_end'); + }) + + /* + * @tc.number: Animation_PageTransitionTest_004 + * @tc.name: Set none type pageTransition + * @tc.desc: Set none type pageTransition + * @tc.size: MediumTest + * @tc.type: Function + * @tc.level Level 1 + */ + it(BUNDLE + 'PageTransitionTest_004', 0, async () => { + hilog.info(DOMAIN, TAG, 'Animation_PageTransitionTest_004_begin'); + aimComponent = await driver.findComponent(ON.text(resource.resourceToString($r("app.string.pageTransition_temp_label4")))); + await aimComponent.click(); + await driver.delayMs(1000); + + aimComponent = await driver.findComponent(ON.text('pushUrl')); + await aimComponent.click(); + await driver.delayMs(3000); + + aimComponent = await driver.findComponent(ON.text('back')); + await aimComponent.click(); + await driver.delayMs(3000); + hilog.info(DOMAIN, TAG, 'Animation_PageTransitionTest_004_end'); + }) + + /* + * @tc.number: Animation_PageTransitionTest_005 + * @tc.name: Set pageTransition with pushUrl + * @tc.desc: Set pageTransition with pushUrl + * @tc.size: MediumTest + * @tc.type: Function + * @tc.level Level 1 + */ + it(BUNDLE + 'PageTransitionTest_005', 0, async () => { + hilog.info(DOMAIN, TAG, 'Animation_PageTransitionTest_005_begin'); + aimComponent = await driver.findComponent(ON.text(resource.resourceToString($r("app.string.pageTransition_temp_label5")))); + await aimComponent.click(); + await driver.delayMs(1000); + + aimComponent = await driver.findComponent(ON.text('pushUrl')); + await aimComponent.click(); + await driver.delayMs(3000); + + aimComponent = await driver.findComponent(ON.text('back')); + await aimComponent.click(); + await driver.delayMs(3000); + hilog.info(DOMAIN, TAG, 'Animation_PageTransitionTest_005_end'); + }) + + /* + * @tc.number: Animation_PageTransitionTest_006 + * @tc.name: Set none type pageTransition + * @tc.desc: Set none type pageTransition + * @tc.size: MediumTest + * @tc.type: Function + * @tc.level Level 1 + */ + it(BUNDLE + 'PageTransitionTest_006', 0, async () => { + hilog.info(DOMAIN, TAG, 'Animation_PageTransitionTest_006_begin'); + aimComponent = await driver.findComponent(ON.text(resource.resourceToString($r("app.string.pageTransition_temp_label6")))); + await aimComponent.click(); + await driver.delayMs(1000); + + aimComponent = await driver.findComponent(ON.text('pushUrl')); + await aimComponent.click(); + await driver.delayMs(3000); + + aimComponent = await driver.findComponent(ON.text('back')); + await aimComponent.click(); + await driver.delayMs(3000); + hilog.info(DOMAIN, TAG, 'Animation_PageTransitionTest_006_end'); + }) + + }) +} \ No newline at end of file diff --git a/ArkUIKit/Animation/entry/src/ohosTest/ets/test/Particle.test.ets b/ArkUIKit/Animation/entry/src/ohosTest/ets/test/Particle.test.ets new file mode 100644 index 0000000000000000000000000000000000000000..0234306984dcf8672dbeaaef77dd267f9a3af85f --- /dev/null +++ b/ArkUIKit/Animation/entry/src/ohosTest/ets/test/Particle.test.ets @@ -0,0 +1,186 @@ +/* + * 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, Component, Driver } from '@kit.TestKit'; +import { afterEach, beforeAll, describe, expect, it } from '@ohos/hypium'; +import { ON } from '@ohos.UiTest'; +import resource from '../../../main/ets/common/resource'; +import { hilog } from '@kit.PerformanceAnalysisKit'; + +const delegator: abilityDelegatorRegistry.AbilityDelegator = abilityDelegatorRegistry.getAbilityDelegator() + +const driver = Driver.create(); +const BUNDLE = 'Animation_' +const TAG = '[Sample_Animation]'; +const DOMAIN = 0xF811 + +let aimComponent : Component + +export function ParticleTest() { + describe('Animation_ParticleTest', () => { + + beforeAll(async () => { + await delegator.startAbility({ + bundleName: 'com.samples.animation', + abilityName: 'EntryAbility' + }); + await driver.delayMs(3000); + + aimComponent = await driver.findComponent(ON.text(resource.resourceToString($r("app.string.particle_label")))); + await aimComponent.click(); + await driver.delayMs(1000); + }) + + afterEach(async () => { + aimComponent = await driver.findComponent(ON.text('AnimateIndex')); + do { + await driver.pressBack(); + aimComponent = await driver.findComponent(ON.text('AnimateIndex')); + } while (aimComponent == null) + }) + + /* + * @tc.number: Animation_ParticleTest_001 + * @tc.name: Set circle particle + * @tc.desc: Set circle particle + * @tc.size: MediumTest + * @tc.type: Function + * @tc.level Level 1 + */ + it(BUNDLE + 'ParticleTest_001', 0, async () => { + hilog.info(DOMAIN, TAG, 'Animation_ParticleTest_001_begin'); + aimComponent = await driver.findComponent(ON.text(resource.resourceToString($r("app.string.particle_temp_label1")))); + await aimComponent.click(); + await driver.delayMs(1000); + + aimComponent = await driver.findComponent(ON.type('root')); + for (let index = 0; index < 20; index++) { + await aimComponent.click(); + await driver.delayMs(100); + } + hilog.info(DOMAIN, TAG, 'Animation_ParticleTest_001_end'); + }) + + /* + * @tc.number: Animation_ParticleTest_002 + * @tc.name: Set image particle + * @tc.desc: Set image particle + * @tc.size: MediumTest + * @tc.type: Function + * @tc.level Level 1 + */ + it(BUNDLE + 'ParticleTest_002', 0, async () => { + hilog.info(DOMAIN, TAG, 'Animation_ParticleTest_002_begin'); + aimComponent = await driver.findComponent(ON.text(resource.resourceToString($r("app.string.particle_temp_label2")))); + await aimComponent.click(); + await driver.delayMs(1000); + + aimComponent = await driver.findComponent(ON.type('root')); + for (let index = 0; index < 20; index++) { + await aimComponent.click(); + await driver.delayMs(100); + } + hilog.info(DOMAIN, TAG, 'Animation_ParticleTest_002_end'); + }) + + /* + * @tc.number: Animation_ParticleTest_003 + * @tc.name: Set particle animate + * @tc.desc: Set particle animate + * @tc.size: MediumTest + * @tc.type: Function + * @tc.level Level 1 + */ + it(BUNDLE + 'ParticleTest_003', 0, async () => { + hilog.info(DOMAIN, TAG, 'Animation_ParticleTest_003_begin'); + aimComponent = await driver.findComponent(ON.text(resource.resourceToString($r("app.string.particle_temp_label3")))); + await aimComponent.click(); + await driver.delayMs(1000); + + aimComponent = await driver.findComponent(ON.type('root')); + for (let index = 0; index < 20; index++) { + await aimComponent.click(); + await driver.delayMs(100); + } + hilog.info(DOMAIN, TAG, 'Animation_ParticleTest_003_end'); + }) + + /* + * @tc.number: Animation_ParticleTest_004 + * @tc.name: Set particle position + * @tc.desc: Set particle position + * @tc.size: MediumTest + * @tc.type: Function + * @tc.level Level 1 + */ + it(BUNDLE + 'ParticleTest_004', 0, async () => { + hilog.info(DOMAIN, TAG, 'Animation_ParticleTest_004_begin'); + aimComponent = await driver.findComponent(ON.text(resource.resourceToString($r("app.string.particle_temp_label4")))); + await aimComponent.click(); + await driver.delayMs(1000); + + aimComponent = await driver.findComponent(ON.type('root')); + for (let index = 0; index < 10; index++) { + await aimComponent.click(); + await driver.delayMs(100); + } + hilog.info(DOMAIN, TAG, 'Animation_ParticleTest_004_end'); + }) + + /* + * @tc.number: Animation_ParticleTest_005 + * @tc.name: Create circle launcher + * @tc.desc: Create circle launcher + * @tc.size: MediumTest + * @tc.type: Function + * @tc.level Level 1 + */ + it(BUNDLE + 'ParticleTest_005', 0, async () => { + hilog.info(DOMAIN, TAG, 'Animation_ParticleTest_005_begin'); + aimComponent = await driver.findComponent(ON.text(resource.resourceToString($r("app.string.particle_temp_label5")))); + await aimComponent.click(); + await driver.delayMs(1000); + + aimComponent = await driver.findComponent(ON.type('root')); + for (let index = 0; index < 10; index++) { + await aimComponent.click(); + await driver.delayMs(100); + } + hilog.info(DOMAIN, TAG, 'Animation_ParticleTest_005_end'); + }) + + /* + * @tc.number: Animation_ParticleTest_006 + * @tc.name: Update circle launcher + * @tc.desc: Update circle launcher + * @tc.size: MediumTest + * @tc.type: Function + * @tc.level Level 1 + */ + it(BUNDLE + 'ParticleTest_006', 0, async () => { + hilog.info(DOMAIN, TAG, 'Animation_ParticleTest_006_begin'); + aimComponent = await driver.findComponent(ON.text(resource.resourceToString($r("app.string.particle_temp_label6")))); + await aimComponent.click(); + await driver.delayMs(1000); + + aimComponent = await driver.findComponent(ON.type('root')); + for (let index = 0; index < 10; index++) { + await aimComponent.click(); + await driver.delayMs(100); + } + hilog.info(DOMAIN, TAG, 'Animation_ParticleTest_006_end'); + }) + + }) +} \ No newline at end of file diff --git a/ArkUIKit/Animation/entry/src/ohosTest/ets/test/Rotation.test.ets b/ArkUIKit/Animation/entry/src/ohosTest/ets/test/Rotation.test.ets new file mode 100644 index 0000000000000000000000000000000000000000..d0dfda62ca99569dc819c8652eef5580b9b5b2f5 --- /dev/null +++ b/ArkUIKit/Animation/entry/src/ohosTest/ets/test/Rotation.test.ets @@ -0,0 +1,96 @@ +/* + * 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, Component, DisplayRotation, Driver } from '@kit.TestKit'; +import { afterEach, beforeAll, describe, expect, it } from '@ohos/hypium'; +import { ON } from '@ohos.UiTest'; +import resource from '../../../main/ets/common/resource'; +import { hilog } from '@kit.PerformanceAnalysisKit'; + +const delegator: abilityDelegatorRegistry.AbilityDelegator = abilityDelegatorRegistry.getAbilityDelegator() + +const driver = Driver.create(); +const BUNDLE = 'Animation_' +const TAG = '[Sample_Animation]'; +const DOMAIN = 0xF811 + +let aimComponent : Component + +export function RotationTest() { + describe('Animation_RotationTest', () => { + + beforeAll(async () => { + await delegator.startAbility({ + bundleName: 'com.samples.animation', + abilityName: 'EntryAbility' + }); + await driver.delayMs(3000); + + aimComponent = await driver.findComponent(ON.text(resource.resourceToString($r("app.string.rotation_label")))); + await aimComponent.click(); + await driver.delayMs(1000); + }) + + afterEach(async () => { + aimComponent = await driver.findComponent(ON.text('AnimateIndex')); + do { + await driver.pressBack(); + aimComponent = await driver.findComponent(ON.text('AnimateIndex')); + } while (aimComponent == null) + }) + + /* + * @tc.number: Animation_RotationTest_001 + * @tc.name: Set rotate animate + * @tc.desc: Set rotate animate + * @tc.size: MediumTest + * @tc.type: Function + * @tc.level Level 1 + */ + it(BUNDLE + 'RotationTest_001', 0, async () => { + hilog.info(DOMAIN, TAG, 'Animation_RotationTest_001_begin'); + aimComponent = await driver.findComponent(ON.text(resource.resourceToString($r("app.string.rotation_temp_label1")))); + await aimComponent.click(); + await driver.delayMs(1000); + + await driver.setDisplayRotation(DisplayRotation.ROTATION_90) + await driver.delayMs(1000); + await driver.setDisplayRotation(DisplayRotation.ROTATION_0) + await driver.delayMs(1000); + hilog.info(DOMAIN, TAG, 'Animation_RotationTest_001_end'); + }) + + /* + * @tc.number: Animation_RotationTest_002 + * @tc.name: Set rotate animate with opacity + * @tc.desc: Set rotate animate with opacity + * @tc.size: MediumTest + * @tc.type: Function + * @tc.level Level 1 + */ + it(BUNDLE + 'RotationTest_002', 0, async () => { + hilog.info(DOMAIN, TAG, 'Animation_RotationTest_002_begin'); + aimComponent = await driver.findComponent(ON.text(resource.resourceToString($r("app.string.rotation_temp_label2")))); + await aimComponent.click(); + await driver.delayMs(1000); + + await driver.setDisplayRotation(DisplayRotation.ROTATION_90) + await driver.delayMs(1000); + await driver.setDisplayRotation(DisplayRotation.ROTATION_0) + await driver.delayMs(1000); + hilog.info(DOMAIN, TAG, 'Animation_RotationTest_002_end'); + }) + + }) +} \ No newline at end of file diff --git a/ArkUIKit/Animation/entry/src/ohosTest/ets/test/ShareTransition.test.ets b/ArkUIKit/Animation/entry/src/ohosTest/ets/test/ShareTransition.test.ets new file mode 100644 index 0000000000000000000000000000000000000000..ee41e1c9de7eb37557a0f418eb5c3f07fdb5b251 --- /dev/null +++ b/ArkUIKit/Animation/entry/src/ohosTest/ets/test/ShareTransition.test.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. + */ +import { abilityDelegatorRegistry, Component, Driver } from '@kit.TestKit'; +import { afterEach, beforeAll, describe, expect, it } from '@ohos/hypium'; +import { ON } from '@ohos.UiTest'; +import resource from '../../../main/ets/common/resource'; +import { hilog } from '@kit.PerformanceAnalysisKit'; + +const delegator: abilityDelegatorRegistry.AbilityDelegator = abilityDelegatorRegistry.getAbilityDelegator() + +const driver = Driver.create(); +const BUNDLE = 'Animation_' +const TAG = '[Sample_Animation]'; +const DOMAIN = 0xF811 + +let aimComponent : Component + +export function ShareTransitionTest() { + describe('Animation_ShareTransitionTest', () => { + + beforeAll(async () => { + await delegator.startAbility({ + bundleName: 'com.samples.animation', + abilityName: 'EntryAbility' + }); + await driver.delayMs(3000); + + aimComponent = await driver.findComponent(ON.text(resource.resourceToString($r("app.string.shareTransition_label")))); + await aimComponent.click(); + await driver.delayMs(1000); + }) + + afterEach(async () => { + aimComponent = await driver.findComponent(ON.text('AnimateIndex')); + do { + await driver.pressBack(); + aimComponent = await driver.findComponent(ON.text('AnimateIndex')); + } while (aimComponent == null) + }) + + /* + * @tc.number: Animation_ShareTransitionTest_001 + * @tc.name: Set share transition animate + * @tc.desc: Set share transition animate + * @tc.size: MediumTest + * @tc.type: Function + * @tc.level Level 1 + */ + it(BUNDLE + 'ShareTransitionTest_001', 0, async () => { + hilog.info(DOMAIN, TAG, 'Animation_ShareTransitionTest_001_begin'); + aimComponent = await driver.findComponent(ON.text(resource.resourceToString($r("app.string.temp1")))); + await aimComponent.click(); + await driver.delayMs(1000); + + aimComponent = await driver.findComponent(ON.type('root')); + await aimComponent.click(); + await driver.delayMs(3000); + hilog.info(DOMAIN, TAG, 'Animation_ShareTransitionTest_001_end'); + }) + + }) +} \ No newline at end of file diff --git a/ArkUIKit/Animation/entry/src/ohosTest/module.json5 b/ArkUIKit/Animation/entry/src/ohosTest/module.json5 new file mode 100644 index 0000000000000000000000000000000000000000..59667117c86b64ab9863f7b382c435ae4a3c32fa --- /dev/null +++ b/ArkUIKit/Animation/entry/src/ohosTest/module.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. + */ +{ + "module": { + "name": "entry_test", + "type": "feature", + "deviceTypes": [ + "default" + ], + "deliveryWithInstall": true, + "installationFree": false + } +} diff --git a/ArkUIKit/Animation/entry/src/test/List.test.ets b/ArkUIKit/Animation/entry/src/test/List.test.ets new file mode 100644 index 0000000000000000000000000000000000000000..a60c87c5cbb0badf7c3fd8975034590e6fafa992 --- /dev/null +++ b/ArkUIKit/Animation/entry/src/test/List.test.ets @@ -0,0 +1,19 @@ +/* + * 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/Animation/entry/src/test/LocalUnit.test.ets b/ArkUIKit/Animation/entry/src/test/LocalUnit.test.ets new file mode 100644 index 0000000000000000000000000000000000000000..841bfd77e56060e50ec0924302a5ae624e76e3aa --- /dev/null +++ b/ArkUIKit/Animation/entry/src/test/LocalUnit.test.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. + */ +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/Animation/hvigor/hvigor-config.json5 b/ArkUIKit/Animation/hvigor/hvigor-config.json5 new file mode 100644 index 0000000000000000000000000000000000000000..4d435603637cbbfe92ac9865537a0c1051810bb1 --- /dev/null +++ b/ArkUIKit/Animation/hvigor/hvigor-config.json5 @@ -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. + */ +{ + "modelVersion": "5.0.5", + "dependencies": { + }, + "execution": { + // "analyze": "normal", /* Define the build analyze mode. Value: [ "normal" | "advanced" | 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 */ + }, + "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/Animation/hvigorfile.ts b/ArkUIKit/Animation/hvigorfile.ts new file mode 100644 index 0000000000000000000000000000000000000000..6b365cacd0191d3b1178eb6b9807b1ae0add6271 --- /dev/null +++ b/ArkUIKit/Animation/hvigorfile.ts @@ -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 { 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. */ +} diff --git a/ArkUIKit/Animation/oh-package.json5 b/ArkUIKit/Animation/oh-package.json5 new file mode 100644 index 0000000000000000000000000000000000000000..38abfd099681aeb547cf83a4966111dd5f4f6d13 --- /dev/null +++ b/ArkUIKit/Animation/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. + */ +{ + "modelVersion": "5.0.5", + "description": "Please describe the basic information.", + "dependencies": { + }, + "devDependencies": { + "@ohos/hypium": "1.0.21", + "@ohos/hamock": "1.0.0" + } +} diff --git a/ArkUIKit/Animation/ohosTest.md b/ArkUIKit/Animation/ohosTest.md new file mode 100644 index 0000000000000000000000000000000000000000..68a1aebc1a071af713210d4039367f2e136e912c --- /dev/null +++ b/ArkUIKit/Animation/ohosTest.md @@ -0,0 +1,20 @@ +# Animation 测试用例归档 + +## 用例表 + +| 测试功能 | 预置条件 | 输入 | 预期输出 | 是否自动 | 测试结果 | +|-------------------------| -------------- |----------------------| ------------------------------------------------------------ | :------- | -------- | +| 显示动画示例代码验证 | 设备正常运行 | 进入各个示例代码页面,触发不同的动画效果 | 动画效果正常 | 是 | Pass | +| 显式动画立即下发示例代码验证 | 设备正常运行 | 点击各种动画按钮,触发不同的动画效果 | 动画效果正常 | 是 | Pass | +| 属性动画(animation)示例代码测试代码 | 设备正常运行 | 点击页面,触发属性动画效果 | 动画效果正常 | 是 | Pass | +| 帧动画示例代码验证 | 设备正常运行 | 点击目标组件,触发动画效果 | 动画效果正常 | 是 | Pass | +| 动画衔接示例代码验证 | 设备正常运行 | 点击Click按钮 | 控件缩放的动画效果正常 | 是 | Pass | +| 组件内转场示例代码验证 | 设备正常运行 | 点击show按钮 | 动画效果正常 | 是 | Pass | +| 关键帧动画示例代码测试代码 | 设备正常运行 | 点击目标组件,触发动画效果 | 动画效果正常 | 是 | Pass | +| 路径动画示例代码测试代码 | 设备正常运行 | 点击目标组件,触发路径动画效果 | 动画效果正常 | 是 | Pass | +| 页面间转场示例代码测试代码 | 设备正常运行 | 点击目标组件,触发页面转场动画效果 | 动画效果正常 | 是 | Pass | +| 粒子动画示例代码验证 | 设备正常运行 | 点击各种动画按钮,触发不同的动画效果 | 动画效果正常 | 是 | Pass | +| 旋转屏动画示例代码验证 | 设备正常运行 | 旋转屏幕 | 目标控件的动画效果正常 | 否 | Pass | +| 共享元素转场示例代码验证 | 设备正常运行 | 点击页面触发动画 | 动画效果正常 | 是 | Pass | +| 自定义属性动画示例代码验证 | 设备正常运行 | 点击目标触发动画 | 动画效果正常 | 是 | Pass | +| 组件动画示例代码验证 | 设备正常运行 | 点击目标触发动画 | 动画效果正常 | 是 | Pass | diff --git a/ArkUIKit/Animation/screenshots/device/image1.png b/ArkUIKit/Animation/screenshots/device/image1.png new file mode 100644 index 0000000000000000000000000000000000000000..21beca22c8e570fa4534a29e9b60402c53adf0b6 Binary files /dev/null and b/ArkUIKit/Animation/screenshots/device/image1.png differ diff --git a/ArkUIKit/Animation/screenshots/device/image2.png b/ArkUIKit/Animation/screenshots/device/image2.png new file mode 100644 index 0000000000000000000000000000000000000000..dcff60b0b4fb19e991d1cf4ca9080782ff7b445e Binary files /dev/null and b/ArkUIKit/Animation/screenshots/device/image2.png differ diff --git a/ArkUIKit/NdkAddInteractionEvent/AppScope/app.json5 b/ArkUIKit/NdkAddInteractionEvent/AppScope/app.json5 new file mode 100644 index 0000000000000000000000000000000000000000..3bcb5e53df55afccbe8f68f99db37cc59e12d492 --- /dev/null +++ b/ArkUIKit/NdkAddInteractionEvent/AppScope/app.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. + */ + +{ + "app": { + "bundleName": "com.samples.NdkAddInteractionEvent", + "vendor": "samples", + "versionCode": 1000000, + "versionName": "1.0.0", + "icon": "$media:layered_image", + "label": "$string:app_name" + } +} diff --git a/ArkUIKit/NdkAddInteractionEvent/AppScope/resources/base/element/string.json b/ArkUIKit/NdkAddInteractionEvent/AppScope/resources/base/element/string.json new file mode 100644 index 0000000000000000000000000000000000000000..b9c2a8cc1a9f328ad95c1ec971fe07a5f756dcb9 --- /dev/null +++ b/ArkUIKit/NdkAddInteractionEvent/AppScope/resources/base/element/string.json @@ -0,0 +1,8 @@ +{ + "string": [ + { + "name": "app_name", + "value": "NdkAddInteractionEvent" + } + ] +} diff --git a/ArkUIKit/NdkAddInteractionEvent/AppScope/resources/base/media/background.png b/ArkUIKit/NdkAddInteractionEvent/AppScope/resources/base/media/background.png new file mode 100644 index 0000000000000000000000000000000000000000..923f2b3f27e915d6871871deea0420eb45ce102f Binary files /dev/null and b/ArkUIKit/NdkAddInteractionEvent/AppScope/resources/base/media/background.png differ diff --git a/ArkUIKit/NdkAddInteractionEvent/AppScope/resources/base/media/foreground.png b/ArkUIKit/NdkAddInteractionEvent/AppScope/resources/base/media/foreground.png new file mode 100644 index 0000000000000000000000000000000000000000..eb9427585b36d14b12477435b6419d1f07b3e0bb Binary files /dev/null and b/ArkUIKit/NdkAddInteractionEvent/AppScope/resources/base/media/foreground.png differ diff --git a/ArkUIKit/NdkAddInteractionEvent/AppScope/resources/base/media/layered_image.json b/ArkUIKit/NdkAddInteractionEvent/AppScope/resources/base/media/layered_image.json new file mode 100644 index 0000000000000000000000000000000000000000..fb49920440fb4d246c82f9ada275e26123a2136a --- /dev/null +++ b/ArkUIKit/NdkAddInteractionEvent/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/NdkAddInteractionEvent/README_zh.md b/ArkUIKit/NdkAddInteractionEvent/README_zh.md new file mode 100644 index 0000000000000000000000000000000000000000..281945c52d95a31771be2a469a906c175755ac26 --- /dev/null +++ b/ArkUIKit/NdkAddInteractionEvent/README_zh.md @@ -0,0 +1,137 @@ +# ArkUI指南文档示例 + +### 介绍 + +ArkUI开发框架对UI组件的事件,提供了监听函数的方式。首先,可使用addNodeEventReceiver函数添加组件事件的监听器,该监听器会监听该组件上发生的所有事件,例如:点击事件、焦点事件。然后,可使用registerNodeEvent函数声明组件的哪些事件需要监听。 + +ArkUI开发框架主要提供点击手势、滑动手势、快滑手势、长按手势、捏合手势和旋转手势,通过给指定的组件绑定不同的手势并设置相应的回调,实现期望的手势交互能力。 + +该工程中展示的代码详细描述可查如下链接: + +1. [监听组件事件](https://gitcode.com/openharmony/docs/blob/master/zh-cn/application-dev/ui/ndk-listen-to-component-events.md)。 + +2. [绑定手势事件](https://gitcode.com/openharmony/docs/blob/master/zh-cn/application-dev/ui/ndk-bind-gesture-events.md)。 + + +### 效果预览 + +| 给点击添加相关事件 | +|--------------------------------------------------| +| ![](screenshots/pic1.jpg) | + +|自定义手势判定回调 | +|--------------------------------------------------------| +| ![](screenshots/pic2.jpg) | + +| 按钮点击监听事件 | +|---------------------------------------------------------------------------| +| ![](screenshots/pic3.jpg) | + +| 顺序识别长按和滑动手势| +|--------------------------------------------------------| +| ![](screenshots/pic4.jpg)| + +| 并行识别长按和快滑手势 | +|------------------------------------------| +| ![](screenshots/pic5.jpg) | + +| 互斥识别滑动手势和捏合手势 | +|---------------------------------------------------| +| ![](screenshots/pic6.jpg) | + + +### 使用说明 + +1. 在首页选择对应的测试界面。 + +2. 在对应的测试界面点击或滑动,观察日志。 + +### 工程目录 +``` +entry/ +└── src + ├── main + │   ├── cpp + │   │   ├── ArkUIBaseNode.h + │   │   ├── ArkUIListItemNode.h + │   │   ├── ArkUIListNode.h + │   │   ├── ArkUINode.h + │   │   ├── ArkUITextNode.h + │   │   ├── CMakeLists.txt + │   │   ├── Common.h + │   │   ├── Function.h + │   │   ├── LongPressAndFlickGesture.h + │   │   ├── LongPressAndSwipeGesture.h + │   │   ├── NativeEntry.cpp + │   │   ├── NativeEntry.h + │   │   ├── NativeModule.h + │   │   ├── NormalTextListExample.h + │   │   ├── SwipeAndPinchExclusiveGesture.h + │   │   ├── napi_init.cpp + │   │   └── types + │   │   └── libentry + │   │   ├── Index.d.ts + │   │   └── oh-package.json5 + │   ├── ets + │   │   ├── entryability + │   │   │   └── EntryAbility.ets + │   │   ├── entrybackupability + │   │   │   └── EntryBackupAbility.ets + │   │   └── pages + │   │   ├── BindGestureEvent.ets + │   │   ├── ComponentListenEvent.ets + │   │   ├── Index.ets + │   │   ├── LongPressAndFlick.ets + │   │   ├── LongPressAndSwipe.ets + │   │   ├── NormalTextList.ets + │   │   └── SwipeAndPinchExclusive.ets +``` + +### 具体实现 + +1. 事件注册和事件解注册,通过addNodeEventReceiver对节点绑定事件处理函数,接着通过调用registerNodeEvent注册对应的事件。源码参考:[NormalTextListExample.h](https://gitcode.com/openharmony/applications_app_samples/blob/master/code/DocsSample/ArkUISample/NdkAddInteractionEvent/entry/src/main/cpp/NormalTextListExample.h) + + * 事件监听函数的入参ArkUI_NodeEvent* event的生命周期只在函数回调周期内生效,不推荐对该指针进行缓存或者进行异步处理 + + * 通过unregisterNodeEvent解注册对应的事件类型,再通过removeNodeEventReceiver卸载事件处理函数 + + * 使用registerNodeEventReceiver注册全局的事件处理函数,对事件进行统一的处理,结束后可使用unregisterNodeEventReceiver进行释放 + + * ArkUI框架提供了OH_ArkUI_NodeEvent_GetInputEvent()接口,用于从输入交互相关的组件事件(如NODE_ON_CLICK_EVENT、NODE_TOUCH_EVENT等,具体可参见每个枚举定义的说明)中获取基础事件对象。然后,可通过调用OH_ArkUI_PointerEvent_GetDisplayX()、OH_ArkUI_PointerEvent_GetDisplayXByIndex()、OH_ArkUI_UIInputEvent_GetAction()和OH_ArkUI_UIInputEvent_GetEventTime()等接口,从基础事件中获取更多信息。应用根据获取的事件信息,在事件执行过程中实现差异化交互逻辑 + +2. 手势绑定。源码参考:[LongPressAndSwipeGesture.h](https://gitcode.com/openharmony/applications_app_samples/blob/master/code/DocsSample/ArkUISample/NdkAddInteractionEvent/entry/src/main/cpp/LongPressAndSwipeGesture.h) + + * 创建一个Column节点,用于绑定手势 + + * 创建一个单指长按1秒并持续响应的长按手势 + + * 将创建的手势和步骤一中创建的Column节点绑定 + + +### 相关权限 + +不涉及。 + +### 依赖 + +不涉及。 + +### 约束与限制 + +1.本示例仅支持标准系统上运行, 支持设备:RK3568。 + +2.本示例为Stage模型,支持API20版本SDK,版本号:6.0.0.41,镜像版本号:OpenHarmony_6.0.0.41。 + +3.本示例需要使用DevEco Studio 5.0.5 Release (Build Version: 5.0.13.200, built on May 13, 2025)及以上版本才可编译运行。 + +### 下载 + +如需单独下载本工程,执行如下命令: + +```` +git init +git config core.sparsecheckout true +echo code/DocsSample/ArkUISample/NdkAddInteractionEvent > .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/NdkAddInteractionEvent/build-profile.json5 b/ArkUIKit/NdkAddInteractionEvent/build-profile.json5 new file mode 100644 index 0000000000000000000000000000000000000000..724b825f1ee429691a14b6b6d138c70fd7c56db9 --- /dev/null +++ b/ArkUIKit/NdkAddInteractionEvent/build-profile.json5 @@ -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. + */ + +{ + "app": { + "signingConfigs": [], + "products": [ + { + "name": "default", + "signingConfig": "default", + "compileSdkVersion": "6.0.0(20)", + "compatibleSdkVersion": "6.0.0(20)", + "targetSdkVersion": "6.0.0(20)", + "runtimeOS": "HarmonyOS", + "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/NdkAddInteractionEvent/code-linter.json5 b/ArkUIKit/NdkAddInteractionEvent/code-linter.json5 new file mode 100644 index 0000000000000000000000000000000000000000..ed05653cca31b61d64cf6471529eaf50d4f70709 --- /dev/null +++ b/ArkUIKit/NdkAddInteractionEvent/code-linter.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. + */ + +{ + "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/NdkAddInteractionEvent/entry/build-profile.json5 b/ArkUIKit/NdkAddInteractionEvent/entry/build-profile.json5 new file mode 100644 index 0000000000000000000000000000000000000000..f16a69b6cabee8faa9f51173548df942097f6fe2 --- /dev/null +++ b/ArkUIKit/NdkAddInteractionEvent/entry/build-profile.json5 @@ -0,0 +1,60 @@ +/* + * 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 + } + }, + "externalNativeOptions": { + "path": "./src/main/cpp/CMakeLists.txt", + "arguments": "", + "cppFlags": "", + "abiFilters": ["arm64-v8a","x86_64"] + } + }, + "buildOptionSet": [ + { + "name": "release", + "arkOptions": { + "obfuscation": { + "ruleOptions": { + "enable": false, + "files": [ + "./obfuscation-rules.txt" + ] + } + } + }, + "nativeLib": { + "debugSymbol": { + "strip": true, + "exclude": [] + } + } + }, + ], + "targets": [ + { + "name": "default" + }, + { + "name": "ohosTest", + } + ] +} \ No newline at end of file diff --git a/ArkUIKit/NdkAddInteractionEvent/entry/hvigorfile.ts b/ArkUIKit/NdkAddInteractionEvent/entry/hvigorfile.ts new file mode 100644 index 0000000000000000000000000000000000000000..cfa8a00f74f409d9647f55cdf270ab6aec69fe41 --- /dev/null +++ b/ArkUIKit/NdkAddInteractionEvent/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/NdkAddInteractionEvent/entry/oh-package.json5 b/ArkUIKit/NdkAddInteractionEvent/entry/oh-package.json5 new file mode 100644 index 0000000000000000000000000000000000000000..118bdd4fe7699368a010e04c24f5bfc887cf1298 --- /dev/null +++ b/ArkUIKit/NdkAddInteractionEvent/entry/oh-package.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. + */ + +{ + "name": "entry", + "version": "1.0.0", + "description": "Please describe the basic information.", + "main": "", + "author": "", + "license": "", + "dependencies": { + "libentry.so": "file:./src/main/cpp/types/libentry" + } +} \ No newline at end of file diff --git a/ArkUIKit/NdkAddInteractionEvent/entry/src/main/cpp/ArkUIBaseNode.h b/ArkUIKit/NdkAddInteractionEvent/entry/src/main/cpp/ArkUIBaseNode.h new file mode 100644 index 0000000000000000000000000000000000000000..2da68a4e0715f79530e70ddf81267c88ff89cf86 --- /dev/null +++ b/ArkUIKit/NdkAddInteractionEvent/entry/src/main/cpp/ArkUIBaseNode.h @@ -0,0 +1,85 @@ +/* + * 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. + */ + +// ArkUIBaseNode.h +// 提供组件树操作的基类。 + +#ifndef MYAPPLICATION_ARKUIBASENODE_H +#define MYAPPLICATION_ARKUIBASENODE_H + +#include +#include +#include + +#include "NativeModule.h" + +namespace NativeModule { + +class ArkUIBaseNode { +public: + explicit ArkUIBaseNode(ArkUI_NodeHandle handle) + : handle_(handle), nativeModule_(NativeModuleInstance::GetInstance()->GetNativeNodeAPI()) {} + + virtual ~ArkUIBaseNode() + { + if (!children_.empty()) { + for (const auto& child : children_) { + nativeModule_->removeChild(handle_, child->GetHandle()); + } + children_.clear(); + } + nativeModule_->disposeNode(handle_); + } + + void AddChild(const std::shared_ptr &child) + { + children_.emplace_back(child); + OnAddChild(child); + } + + void RemoveChild(const std::shared_ptr &child) + { + children_.remove(child); + OnRemoveChild(child); + } + + void InsertChild(const std::shared_ptr &child, int32_t index) + { + if (index >= children_.size()) { + AddChild(child); + } else { + auto iter = children_.begin(); + std::advance(iter, index); + children_.insert(iter, child); + OnInsertChild(child, index); + } + } + + ArkUI_NodeHandle GetHandle() const { return handle_; } + +protected: + virtual void OnAddChild(const std::shared_ptr &child) {} + virtual void OnRemoveChild(const std::shared_ptr &child) {} + virtual void OnInsertChild(const std::shared_ptr &child, int32_t index) {} + + ArkUI_NodeHandle handle_; + ArkUI_NativeNodeAPI_1 *nativeModule_ = nullptr; + +private: + std::list> children_; +}; +} // namespace NativeModule + +#endif // MYAPPLICATION_ARKUIBASENODE_H \ No newline at end of file diff --git a/ArkUIKit/NdkAddInteractionEvent/entry/src/main/cpp/ArkUIListItemNode.h b/ArkUIKit/NdkAddInteractionEvent/entry/src/main/cpp/ArkUIListItemNode.h new file mode 100644 index 0000000000000000000000000000000000000000..1731a29c4b6876d5254ee2645db390b5fe2880fd --- /dev/null +++ b/ArkUIKit/NdkAddInteractionEvent/entry/src/main/cpp/ArkUIListItemNode.h @@ -0,0 +1,32 @@ +/* + * 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. + */ + +// ArkUIListItemNode.h +// 提供列表项的封装类。 + +#ifndef MYAPPLICATION_ARKUISTACKNODE_H +#define MYAPPLICATION_ARKUISTACKNODE_H + +#include "ArkUINode.h" + +namespace NativeModule { +class ArkUIListItemNode : public ArkUINode { +public: + ArkUIListItemNode() + : ArkUINode((NativeModuleInstance::GetInstance()->GetNativeNodeAPI())->createNode(ARKUI_NODE_LIST_ITEM)) {} +}; +} // namespace NativeModule + +#endif // MYAPPLICATION_ARKUISTACKNODE_H \ No newline at end of file diff --git a/ArkUIKit/NdkAddInteractionEvent/entry/src/main/cpp/ArkUIListNode.h b/ArkUIKit/NdkAddInteractionEvent/entry/src/main/cpp/ArkUIListNode.h new file mode 100644 index 0000000000000000000000000000000000000000..d47c1415f1589e5c0ab1a728bf567ffb0dcda3c4 --- /dev/null +++ b/ArkUIKit/NdkAddInteractionEvent/entry/src/main/cpp/ArkUIListNode.h @@ -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. + */ + +// [Start arkui_list_node] +// ArkUIListNode.h +// 列表封装类对象 + +#ifndef MYAPPLICATION_ARKUILISTNODE_H +#define MYAPPLICATION_ARKUILISTNODE_H + +#include "ArkUINode.h" +#include + +namespace NativeModule { +class ArkUIListNode : public ArkUINode { +public: + ArkUIListNode() + : ArkUINode((NativeModuleInstance::GetInstance()->GetNativeNodeAPI())->createNode(ARKUI_NODE_LIST)) {} + + ~ArkUIListNode() override { nativeModule_->unregisterNodeEvent(handle_, NODE_LIST_ON_SCROLL_INDEX); } + + void SetScrollBarState(bool isShow) + { + if (!handle_) { + return; + } + ArkUI_ScrollBarDisplayMode displayMode = + isShow ? ARKUI_SCROLL_BAR_DISPLAY_MODE_ON : ARKUI_SCROLL_BAR_DISPLAY_MODE_OFF; + ArkUI_NumberValue value[] = {{.i32 = displayMode}}; + ArkUI_AttributeItem item = {value, 1}; + nativeModule_->setAttribute(handle_, NODE_SCROLL_BAR_DISPLAY_MODE, &item); + } + + // 注册列表相关事件。 + void RegisterOnScrollIndex(const std::function &onScrollIndex) + { + if (!handle_) { + return; + } + onScrollIndex_ = onScrollIndex; + nativeModule_->registerNodeEvent(handle_, NODE_LIST_ON_SCROLL_INDEX, 0, nullptr); + } + +protected: + // 处理List相关事件。 + void OnNodeEvent(ArkUI_NodeEvent *event) override + { + auto eventType = OH_ArkUI_NodeEvent_GetEventType(event); + switch (eventType) { + case NODE_LIST_ON_SCROLL_INDEX: { + auto index = OH_ArkUI_NodeEvent_GetNodeComponentEvent(event)->data[0]; + if (onScrollIndex_) { + onScrollIndex_(index.i32); + } + } + default: { + } + } + } + +private: + std::function onScrollIndex_; +}; +} // namespace NativeModule + +#endif // MYAPPLICATION_ARKUILISTNODE_H +// [End arkui_list_node] \ No newline at end of file diff --git a/ArkUIKit/NdkAddInteractionEvent/entry/src/main/cpp/ArkUINode.h b/ArkUIKit/NdkAddInteractionEvent/entry/src/main/cpp/ArkUINode.h new file mode 100644 index 0000000000000000000000000000000000000000..ca11ae470d96d1d2a37cd5a85738aad81363ee04 --- /dev/null +++ b/ArkUIKit/NdkAddInteractionEvent/entry/src/main/cpp/ArkUINode.h @@ -0,0 +1,221 @@ +/* + * 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 arkui_node] +// ArkUINode.h +// 提供通用属性和事件的封装。 + +#ifndef MYAPPLICATION_ARKUINODE_H +#define MYAPPLICATION_ARKUINODE_H + +#include "ArkUIBaseNode.h" +#include "NativeModule.h" + +#include +#include + +namespace NativeModule { + +class ArkUINode : public ArkUIBaseNode { +public: + explicit ArkUINode(ArkUI_NodeHandle handle) : ArkUIBaseNode(handle) + { + nativeModule_ = NativeModuleInstance::GetInstance()->GetNativeNodeAPI(); + // 事件触发时需要通过函数获取对应的事件对象,这边通过设置节点自定义数据将封装类指针保持在组件上,方便后续事件分发。 + nativeModule_->setUserData(handle_, this); + // 注册节点监听事件接受器。 + nativeModule_->addNodeEventReceiver(handle_, ArkUINode::NodeEventReceiver); + } + + ~ArkUINode() override + { + if (onClick_) { + nativeModule_->unregisterNodeEvent(handle_, NODE_ON_CLICK_EVENT); + } + if (onTouch_) { + nativeModule_->unregisterNodeEvent(handle_, NODE_TOUCH_EVENT); + } + if (onDisappear_) { + nativeModule_->unregisterNodeEvent(handle_, NODE_EVENT_ON_DISAPPEAR); + } + if (onAppear_) { + nativeModule_->unregisterNodeEvent(handle_, NODE_EVENT_ON_APPEAR); + } + nativeModule_->removeNodeEventReceiver(handle_, ArkUINode::NodeEventReceiver); + } + + void SetWidth(float width) + { + if (!handle_) { + return; + } + ArkUI_NumberValue value[] = {{.f32 = width}}; + ArkUI_AttributeItem item = {value, 1}; + nativeModule_->setAttribute(handle_, NODE_WIDTH, &item); + } + void SetPercentWidth(float percent) + { + if (!handle_) { + return; + } + ArkUI_NumberValue value[] = {{.f32 = percent}}; + ArkUI_AttributeItem item = {value, 1}; + nativeModule_->setAttribute(handle_, NODE_WIDTH_PERCENT, &item); + } + void SetHeight(float height) + { + if (!handle_) { + return; + } + ArkUI_NumberValue value[] = {{.f32 = height}}; + ArkUI_AttributeItem item = {value, 1}; + nativeModule_->setAttribute(handle_, NODE_HEIGHT, &item); + } + void SetPercentHeight(float percent) + { + if (!handle_) { + return; + } + ArkUI_NumberValue value[] = {{.f32 = percent}}; + ArkUI_AttributeItem item = {value, 1}; + nativeModule_->setAttribute(handle_, NODE_HEIGHT_PERCENT, &item); + } + void SetBackgroundColor(uint32_t color) + { + if (!handle_) { + return; + } + ArkUI_NumberValue value[] = {{.u32 = color}}; + ArkUI_AttributeItem item = {value, 1}; + nativeModule_->setAttribute(handle_, NODE_BACKGROUND_COLOR, &item); + } + // 处理通用事件。 + void RegisterOnClick(const std::function &onClick) + { + if (!handle_) { + return; + } + onClick_ = onClick; + // 注册点击事件。 + nativeModule_->registerNodeEvent(handle_, NODE_ON_CLICK_EVENT, 0, nullptr); + } + + void RegisterOnTouch(const std::function &onTouch) + { + if (!handle_) { + return; + } + onTouch_ = onTouch; + // 注册触碰事件。 + nativeModule_->registerNodeEvent(handle_, NODE_TOUCH_EVENT, 0, nullptr); + } + + void RegisterOnDisappear(const std::function &onDisappear) + { + if (!handle_) { + return; + } + onDisappear_ = onDisappear; + // 注册卸载事件。 + nativeModule_->registerNodeEvent(handle_, NODE_EVENT_ON_DISAPPEAR, 0, nullptr); + } + + void RegisterOnAppear(const std::function &onAppear) + { + if (!handle_) { + return; + } + onAppear_ = onAppear; + // 注册挂载事件。 + nativeModule_->registerNodeEvent(handle_, NODE_EVENT_ON_APPEAR, 0, nullptr); + } + +protected: + // 事件监听器函数指针。 + static void NodeEventReceiver(ArkUI_NodeEvent *event) + { + // 获取事件发生的UI组件对象。 + auto nodeHandle = OH_ArkUI_NodeEvent_GetNodeHandle(event); + // 获取保持在UI组件对象中的自定义数据,返回封装类指针。 + auto *node = reinterpret_cast( + NativeModuleInstance::GetInstance()->GetNativeNodeAPI()->getUserData(nodeHandle)); + // 基于封装类实例对象处理事件。 + node->ProcessNodeEvent(event); + } + void ProcessNodeEvent(ArkUI_NodeEvent *event) + { + auto eventType = OH_ArkUI_NodeEvent_GetEventType(event); + switch (eventType) { + case NODE_ON_CLICK_EVENT: { + if (onClick_) { + onClick_(event); + } + break; + } + case NODE_TOUCH_EVENT: { + if (onTouch_) { + auto *uiInputEvent = OH_ArkUI_NodeEvent_GetInputEvent(event); + float x = OH_ArkUI_PointerEvent_GetX(uiInputEvent); + float y = OH_ArkUI_PointerEvent_GetY(uiInputEvent); + auto type = OH_ArkUI_UIInputEvent_GetAction(uiInputEvent); + onTouch_(type, x, y); + } + } + case NODE_EVENT_ON_DISAPPEAR: { + if (onDisappear_) { + onDisappear_(); + } + break; + } + case NODE_EVENT_ON_APPEAR: { + if (onAppear_) { + onAppear_(); + } + break; + } + default: { + // 组件特有事件交给子类处理 + OnNodeEvent(event); + } + } + } + + virtual void OnNodeEvent(ArkUI_NodeEvent *event) {} + + void OnAddChild(const std::shared_ptr &child) override + { + nativeModule_->addChild(handle_, child->GetHandle()); + } + + void OnRemoveChild(const std::shared_ptr &child) override + { + nativeModule_->removeChild(handle_, child->GetHandle()); + } + + void OnInsertChild(const std::shared_ptr &child, int32_t index) override + { + nativeModule_->insertChildAt(handle_, child->GetHandle(), index); + } + +private: + std::function onClick_; + std::function onDisappear_; + std::function onAppear_; + std::function onTouch_; +}; +} // namespace NativeModule + +#endif // MYAPPLICATION_ARKUINODE_H +// [End arkui_node] \ No newline at end of file diff --git a/ArkUIKit/NdkAddInteractionEvent/entry/src/main/cpp/ArkUITextNode.h b/ArkUIKit/NdkAddInteractionEvent/entry/src/main/cpp/ArkUITextNode.h new file mode 100644 index 0000000000000000000000000000000000000000..26b7e92c4d395ca9c63a465732d44225304abb35 --- /dev/null +++ b/ArkUIKit/NdkAddInteractionEvent/entry/src/main/cpp/ArkUITextNode.h @@ -0,0 +1,69 @@ +/* + * 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. + */ + +// ArkUITextNode.h +// 实现文本组件的封装类。 + +#ifndef MYAPPLICATION_ARKUITEXTNODE_H +#define MYAPPLICATION_ARKUITEXTNODE_H + +#include "ArkUINode.h" + +#include + +namespace NativeModule { +class ArkUITextNode : public ArkUINode { +public: + ArkUITextNode() + : ArkUINode((NativeModuleInstance::GetInstance()->GetNativeNodeAPI())->createNode(ARKUI_NODE_TEXT)) {} + void SetFontSize(float fontSize) + { + if (!handle_) { + return; + } + ArkUI_NumberValue value[] = {{.f32 = fontSize}}; + ArkUI_AttributeItem item = {value, 1}; + nativeModule_->setAttribute(handle_, NODE_FONT_SIZE, &item); + } + void SetFontColor(uint32_t color) + { + if (!handle_) { + return; + } + ArkUI_NumberValue value[] = {{.u32 = color}}; + ArkUI_AttributeItem item = {value, 1}; + nativeModule_->setAttribute(handle_, NODE_FONT_COLOR, &item); + } + void SetTextContent(const std::string &content) + { + if (!handle_) { + return; + } + ArkUI_AttributeItem item = {nullptr, 0, content.c_str()}; + nativeModule_->setAttribute(handle_, NODE_TEXT_CONTENT, &item); + } + void SetTextAlign(ArkUI_TextAlignment align) + { + if (!handle_) { + return; + } + ArkUI_NumberValue value[] = {{.i32 = align}}; + ArkUI_AttributeItem item = {value, 1}; + nativeModule_->setAttribute(handle_, NODE_TEXT_ALIGN, &item); + } +}; +} // namespace NativeModule + +#endif // MYAPPLICATION_ARKUITEXTNODE_H \ No newline at end of file diff --git a/ArkUIKit/NdkAddInteractionEvent/entry/src/main/cpp/CMakeLists.txt b/ArkUIKit/NdkAddInteractionEvent/entry/src/main/cpp/CMakeLists.txt new file mode 100644 index 0000000000000000000000000000000000000000..4d5474baab9369b2c87217bb3928a1d7efd3a32a --- /dev/null +++ b/ArkUIKit/NdkAddInteractionEvent/entry/src/main/cpp/CMakeLists.txt @@ -0,0 +1,15 @@ +# the minimum version of CMake. +cmake_minimum_required(VERSION 3.5.0) +project(MyNDKDemo) + +set(NATIVERENDER_ROOT_PATH ${CMAKE_CURRENT_SOURCE_DIR}) + +if(DEFINED PACKAGE_FIND_FILE) + include(${PACKAGE_FIND_FILE}) +endif() + +include_directories(${NATIVERENDER_ROOT_PATH} + ${NATIVERENDER_ROOT_PATH}/include) + +add_library(entry SHARED napi_init.cpp NativeEntry.cpp) +target_link_libraries(entry PUBLIC libace_napi.z.so libace_ndk.z.so libhilog_ndk.z.so) \ No newline at end of file diff --git a/ArkUIKit/NdkAddInteractionEvent/entry/src/main/cpp/Common.h b/ArkUIKit/NdkAddInteractionEvent/entry/src/main/cpp/Common.h new file mode 100644 index 0000000000000000000000000000000000000000..e9489ee90e351651a76650f3351fc025c02c3a35 --- /dev/null +++ b/ArkUIKit/NdkAddInteractionEvent/entry/src/main/cpp/Common.h @@ -0,0 +1,142 @@ +/* + * 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. + */ + +#ifndef DRAGANDDROP_COMMON_H +#define DRAGANDDROP_COMMON_H + +#include +#include +#include +#include + +#define DEFAULT_WIDTH 200.0 +#define DEFAULT_HEIGHT 200.0 +#define DEFAULT_BG_COLOR 0xFFFFFFFF +#define DEFAULT_BORDER_WIDTH 0.0 +#define BORDER_WIDTH_1 1.0 +#define DEFAULT_MARGIN 5.0 +#define DEFAULT_BORDER_COLOR 0xFF000000 +#define DEFAULT_RADIUS 10.0 + +#define SIZE_100 100 +#define SIZE_300 300 +#define BLANK_10 10.0 +#define BLANK_20 20.0 +#define BLANK_30 30.0 + +#define DEFAULT_TEXT_FONT_SIZE 12 +#define TEXT_FONT_SIZE_15 15 +#define TEXT_FONT_SIZE_20 20 + +#define BUTTON_LENGTH 10 +#define MAX_LENGTH 128 + +namespace NativeModule { +// [Start define_node] +ArkUI_NativeNodeAPI_1 *nodeAPI = nullptr; +// [End define_node] +std::stringstream g_ss; + +void SetWidthPercent(ArkUI_NodeHandle &node, float width = 1) +{ + if (!nodeAPI) { + return; + } + ArkUI_NumberValue widthValue[] = {width}; + ArkUI_AttributeItem widthItem = {widthValue, 1}; + nodeAPI->setAttribute(node, NODE_WIDTH_PERCENT, &widthItem); +} + +void SetHeight(ArkUI_NodeHandle &node, float height = DEFAULT_HEIGHT) +{ + if (!nodeAPI) { + return; + } + ArkUI_NumberValue heightValue[] = {height}; + ArkUI_AttributeItem heightItem = {heightValue, 1}; + nodeAPI->setAttribute(node, NODE_HEIGHT, &heightItem); +} + +void SetHeightPercent(ArkUI_NodeHandle &node, float height = 1) +{ + if (!nodeAPI) { + return; + } + ArkUI_NumberValue heightValue[] = {height}; + ArkUI_AttributeItem heightItem = {heightValue, 1}; + nodeAPI->setAttribute(node, NODE_HEIGHT_PERCENT, &heightItem); +} + +void SetPadding(ArkUI_NodeHandle &node, float padding) +{ + if (!nodeAPI) { + return; + } + ArkUI_NumberValue paddingValue[] = {padding}; + ArkUI_AttributeItem paddingItem = {paddingValue, 1}; + nodeAPI->setAttribute(node, NODE_PADDING, &paddingItem); +} + +void SetBorderWidth(ArkUI_NodeHandle &node, float width = DEFAULT_BORDER_WIDTH) +{ + if (!nodeAPI) { + return; + } + ArkUI_NumberValue borderWidthValue[] = {width}; + ArkUI_AttributeItem borderWidthItem = {borderWidthValue, 1}; + nodeAPI->setAttribute(node, NODE_BORDER_WIDTH, &borderWidthItem); +} + +void SetColumnJustifyContent(ArkUI_NodeHandle &node, int32_t alignment) +{ + if (!nodeAPI) { + return; + } + ArkUI_NumberValue justifyValue[] = {{.i32 = alignment}}; + ArkUI_AttributeItem justifyItem = {justifyValue, 1}; + nodeAPI->setAttribute(node, NODE_COLUMN_JUSTIFY_CONTENT, &justifyItem); +} + +void SetColumnAlignItem(ArkUI_NodeHandle &node, int32_t alignment) +{ + if (!nodeAPI) { + return; + } + ArkUI_NumberValue alignValue[] = {{.i32 = alignment}}; + ArkUI_AttributeItem alignItem = {alignValue, 1}; + nodeAPI->setAttribute(node, NODE_COLUMN_ALIGN_ITEMS, &alignItem); +} + +void SetButtonLabel(ArkUI_NodeHandle &node, const char *label) +{ + if (!nodeAPI) { + return; + } + ArkUI_AttributeItem NODE_Button_SRC_Item = {.string = label}; + nodeAPI->setAttribute(node, NODE_BUTTON_LABEL, &NODE_Button_SRC_Item); +} + +void SetId(ArkUI_NodeHandle &node, const char *id) +{ + if (!nodeAPI) { + return; + } + ArkUI_AttributeItem idItem = {.string = id}; + nodeAPI->setAttribute(node, NODE_ID, &idItem); +} + +} // namespace NativeXComponentSample + +#endif // DRAGANDDROP_COMMON_H \ No newline at end of file diff --git a/ArkUIKit/NdkAddInteractionEvent/entry/src/main/cpp/Function.h b/ArkUIKit/NdkAddInteractionEvent/entry/src/main/cpp/Function.h new file mode 100644 index 0000000000000000000000000000000000000000..64a56ea05b7b616d4629234c4e94da3080df97a3 --- /dev/null +++ b/ArkUIKit/NdkAddInteractionEvent/entry/src/main/cpp/Function.h @@ -0,0 +1,447 @@ +/* + * 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. + */ + +#ifndef NDKCOMPONENTLISTEN_FUNCTION_H +#define NDKCOMPONENTLISTEN_FUNCTION_H + +#include "Common.h" + +#include +#include +#include +#include +#include +#include +#include + +namespace NativeModule { + +const unsigned int WIDTH_SIZE = 200; +const unsigned int GINGERS_NUM_1 = 1; +const unsigned int DURATION_NUM_100 = 100; +const unsigned int DURATION_NUM_1000 = 1000; +const unsigned int HEIGHT_50 = 50; +const unsigned int HEIGHT_70 = 70; +const float PERCENT_WIDTH = 0.3f; +const float PERCENT_HEIGHT = 0.3f; +const float PERCENT_HEIGHT_5 = 0.5f; +const unsigned int COUNT_NUM_1 = 1; +const unsigned int DISTANCE_NUM_1 = 1; +const unsigned int SPEED_NUM_50 = 50; +const unsigned int LOG_PRINT_DOMAIN = 0xF811; +const unsigned int ITEM_SIZE_ONE = 1; +const unsigned int ITEM_SIZE_TWO = 2; +const unsigned int HEIGHT_SIZE = 200; +const unsigned int GINGERS_NUM = 1; +const unsigned int DURATION_NUM = 5; +const unsigned int ITEM_SIZE_FIVE = 5; +const unsigned int DURATION_NUM_500 = 500; +const unsigned int LOOP_SIZE = 30; +const unsigned int FONT_SIZE = 16; +const float PERCENT_WIDTH_1 = 1; +const float PERCENT_HEIGHT_1 = 1; + +// [Start shade_change_event] +struct ColorModeInfo { + const char* lightMsg; + const char* darkMsg; +}; + +//注册回调函数 +void onColorModeChange(ArkUI_SystemColorMode colorMode, void *userData) +{ + ColorModeInfo* info = static_cast(userData); + if (colorMode == ARKUI_SYSTEM_COLOR_MODE_LIGHT) { + OH_LOG_Print(LOG_APP, LOG_ERROR, LOG_PRINT_DOMAIN, "[Sample_NdkAddInteractionEvent]", + "NdkAddInteractionEvent_Light mode: ", info->lightMsg); + } else if (colorMode == ARKUI_SYSTEM_COLOR_MODE_DARK) { + OH_LOG_Print(LOG_APP, LOG_ERROR, LOG_PRINT_DOMAIN, "[Sample_NdkAddInteractionEvent]", + "NdkAddInteractionEvent_Dark mode: ", info->darkMsg); + } +} + +ArkUI_NodeHandle testColorModeChange(ArkUI_NativeNodeAPI_1 *nodeAPI) { + ArkUI_NodeHandle text = nodeAPI->createNode(ARKUI_NODE_TEXT); + static ColorModeInfo info = {"Light mode", "Dark mode"}; + OH_ArkUI_RegisterSystemColorModeChangeEvent(text, &info, onColorModeChange); + + ArkUI_AttributeItem itemstring = {nullptr, 0, ("test_light_dark")}; + nodeAPI->setAttribute(text, NODE_TEXT_CONTENT, &itemstring); + + return text; +} +// [End shade_change_event] +// [Start node_event_receiver] +void NodeEventReceiver(ArkUI_NodeEvent *event) { + // 设置对应的事件类型触发时进行的操作,如NODE_ON_CLICK_EVENT +}; +// [End node_event_receiver] +void FirstModule(ArkUI_NodeHandle &root) +{ + auto column = nodeAPI->createNode(ARKUI_NODE_COLUMN); + SetId(column, "bg"); + SetWidthPercent(column, PERCENT_WIDTH); + SetHeightPercent(column, PERCENT_HEIGHT); + // [Start create_and_register_node] + auto button = nodeAPI->createNode(ARKUI_NODE_BUTTON); + nodeAPI->addNodeEventReceiver(button, NodeEventReceiver); + nodeAPI->registerNodeEvent(button, NODE_ON_CLICK_EVENT, 0, nullptr); + // [End create_and_register_node] + SetWidthPercent(button, BORDER_WIDTH_1); + SetHeight(button, HEIGHT_50); + SetButtonLabel(button, "test"); + nodeAPI->addChild(column, button); + + // [Start get_event_information] + // 注册click事件 + nodeAPI->registerNodeEvent(button, NODE_ON_CLICK_EVENT, 0, nullptr); + // 设置组件事件的全局监听 + // [Start register_global_event] + nodeAPI->registerNodeEventReceiver([](ArkUI_NodeEvent *event) { + // 从组件事件中获取基础事件对象 + auto *inputEvent = OH_ArkUI_NodeEvent_GetInputEvent(event); + // 从组件事件获取事件类型 + auto eventType = OH_ArkUI_NodeEvent_GetEventType(event); + // [StartExclude register_global_event] + OH_LOG_Print(LOG_APP, LOG_INFO, LOG_PRINT_DOMAIN, "[Sample_NdkAddInteractionEvent]", + "NdkAddInteractionEvent_eventInfo inputEvent = %{public}p", inputEvent); + OH_LOG_Print(LOG_APP, LOG_INFO, LOG_PRINT_DOMAIN, "[Sample_NdkAddInteractionEvent]", + "NdkAddInteractionEvent_eventInfo eventType = %{public}d", eventType); + auto componentEvent = OH_ArkUI_NodeEvent_GetNodeComponentEvent(event); + // 获取组件事件中的数字类型数据 + OH_LOG_Print(LOG_APP, LOG_INFO, LOG_PRINT_DOMAIN, "[Sample_NdkAddInteractionEvent]", + "NdkAddInteractionEvent_eventInfo componentEvent = %{public}p", componentEvent); + // 获取触发该事件的组件对象 + auto nodeHandle = OH_ArkUI_NodeEvent_GetNodeHandle(event); + OH_LOG_Print(LOG_APP, LOG_INFO, LOG_PRINT_DOMAIN, "[Sample_NdkAddInteractionEvent]", + "NdkAddInteractionEvent_eventInfo nodeHandle = %{public}p", nodeHandle); + // 根据eventType来区分事件类型,进行差异化处理,其他获取事件信息的接口也可类似方式来进行差异化的处理 + // [EndExclude register_global_event] + switch (eventType) { + case NODE_ON_CLICK_EVENT: { + // 触发点击事件所进行的操作,从基础事件获取事件信息 + // [StartExclude register_global_event] + auto x = OH_ArkUI_PointerEvent_GetX(inputEvent); + auto y = OH_ArkUI_PointerEvent_GetY(inputEvent); + auto displayX = OH_ArkUI_PointerEvent_GetDisplayX(inputEvent); + auto displayY = OH_ArkUI_PointerEvent_GetDisplayY(inputEvent); + auto windowX = OH_ArkUI_PointerEvent_GetWindowX(inputEvent); + auto windowY = OH_ArkUI_PointerEvent_GetWindowY(inputEvent); + auto pointerCount = OH_ArkUI_PointerEvent_GetPointerCount(inputEvent); + auto xByIndex = OH_ArkUI_PointerEvent_GetXByIndex(inputEvent, 0); + auto yByIndex = OH_ArkUI_PointerEvent_GetYByIndex(inputEvent, 0); + auto displayXByIndex = OH_ArkUI_PointerEvent_GetDisplayXByIndex(inputEvent, 0); + auto displayYByIndex = OH_ArkUI_PointerEvent_GetDisplayYByIndex(inputEvent, 0); + auto windowXByIndex = OH_ArkUI_PointerEvent_GetWindowXByIndex(inputEvent, 0); + auto windowYByIndex = OH_ArkUI_PointerEvent_GetWindowYByIndex(inputEvent, 0); + auto pointerId = OH_ArkUI_PointerEvent_GetPointerId(inputEvent, 0); + auto pressure = OH_ArkUI_PointerEvent_GetPressure(inputEvent, 0); + auto action = OH_ArkUI_UIInputEvent_GetAction(inputEvent); + auto eventTime = OH_ArkUI_UIInputEvent_GetEventTime(inputEvent); + auto sourceType = OH_ArkUI_UIInputEvent_GetSourceType(inputEvent); + auto type = OH_ArkUI_UIInputEvent_GetType(inputEvent); + std::string eventInfo = + "x: " + std::to_string(x) + ", y: " + std::to_string(y) + + ", displayX: " + std::to_string(displayX) + ", displayY: " + std::to_string(displayY) + + ", windowX: " + std::to_string(windowX) + ", windowY: " + std::to_string(windowY) + + ", pointerCount: " + std::to_string(pointerCount) + ", xByIndex: " + std::to_string(xByIndex) + + ", yByIndex: " + std::to_string(yByIndex) + + ", displayXByIndex: " + std::to_string(displayXByIndex) + + ", displayYByIndex: " + std::to_string(displayYByIndex) + + ", windowXByIndex: " + std::to_string(windowXByIndex) + + ", windowYByIndex: " + std::to_string(windowYByIndex) + + ", pointerId: " + std::to_string(pointerId) + ", pressure: " + std::to_string(pressure) + + ", action: " + std::to_string(action) + ", eventTime: " + std::to_string(eventTime) + + ", sourceType: " + std::to_string(sourceType) + ", type: " + std::to_string(type); + OH_LOG_Print(LOG_APP, LOG_INFO, LOG_PRINT_DOMAIN, "[Sample_NdkAddInteractionEvent]", + "NdkAddInteractionEvent_eventInfoOfCommonEvent eventInfo = %{public}s", + eventInfo.c_str()); + break; + // [EndExclude register_global_event] + } + default: { + break; + } + } + }); + // [End register_global_event] + // [End get_event_information] + nodeAPI->addChild(root, column); +} + +void SecondModule(ArkUI_NodeHandle &root) +{ + auto column = nodeAPI->createNode(ARKUI_NODE_COLUMN); + SetId(column, "bg1"); + SetWidthPercent(column, PERCENT_WIDTH); + SetHeightPercent(column, PERCENT_HEIGHT); + + auto text = testColorModeChange(nodeAPI); + nodeAPI->addChild(column, text); + nodeAPI->addChild(root, column); +} + +void ThirdModule(ArkUI_NodeHandle &root) +{ + auto column = nodeAPI->createNode(ARKUI_NODE_COLUMN); + SetId(column, "bg2"); + SetWidthPercent(column, PERCENT_WIDTH); + SetHeightPercent(column, PERCENT_HEIGHT_5); + + auto button = nodeAPI->createNode(ARKUI_NODE_BUTTON); + SetWidthPercent(button, BORDER_WIDTH_1); + SetHeight(button, HEIGHT_70); + SetButtonLabel(button, "test_unregister"); + + // [Start unregister_node_event_receicer] + nodeAPI->unregisterNodeEventReceiver(); + // [End unregister_node_event_receicer] + // [Start unregister_node_event] + nodeAPI->unregisterNodeEvent(button, NODE_ON_CLICK_EVENT); + // [End unregister_node_event] + // [Start remove_node_evect_receiver] + nodeAPI->removeNodeEventReceiver(button, NodeEventReceiver); + // [End remove_node_evect_receiver] + nodeAPI->addChild(column, button); + nodeAPI->addChild(root, column); +} + +ArkUI_GestureRecognizer* CreateTapGesture() +{ + // [Start create_tap_gesture] + // 获取手势Native接口集合 + auto gestureApi = reinterpret_cast( + OH_ArkUI_QueryModuleInterfaceByName(ARKUI_NATIVE_GESTURE, "ArkUI_NativeGestureAPI_1")); + // 创建点击手势 + auto tapGesture = gestureApi->createTapGesture(COUNT_NUM_1, GINGERS_NUM_1); + // [End create_tap_gesture] + return tapGesture; +} + +ArkUI_GestureRecognizer* CreatePanGesture() +{ + // [Start create_pan_gesture] + // 获取手势Native接口集合 + auto gestureApi = reinterpret_cast( + OH_ArkUI_QueryModuleInterfaceByName(ARKUI_NATIVE_GESTURE, "ArkUI_NativeGestureAPI_1")); + // 创建滑动手势 + auto panGesture = gestureApi->createPanGesture(COUNT_NUM_1, GESTURE_DIRECTION_ALL, GINGERS_NUM_1); + // [End create_pan_gesture] + return panGesture; +} + +ArkUI_GestureRecognizer* CreateLongPressGesture() +{ + // [Start create_long_press_gesture] + // 获取手势Native接口集合 + auto gestureApi = reinterpret_cast( + OH_ArkUI_QueryModuleInterfaceByName(ARKUI_NATIVE_GESTURE, "ArkUI_NativeGestureAPI_1")); + // 创建长按手势 + auto longPressGesture = gestureApi->createLongPressGesture(GINGERS_NUM_1, true, DURATION_NUM_1000); + // [End create_long_press_gesture] + return longPressGesture; +} + +ArkUI_GestureRecognizer* CreatePinchGesture() +{ + // [Start create_pinch_gesture] + // 获取手势Native接口集合 + auto gestureApi = reinterpret_cast( + OH_ArkUI_QueryModuleInterfaceByName(ARKUI_NATIVE_GESTURE, "ArkUI_NativeGestureAPI_1")); + // 创建捏合手势 + auto pinchGesture = gestureApi->createPinchGesture(1, DISTANCE_NUM_1); + // [End create_pinch_gesture] + return pinchGesture; +} + +ArkUI_GestureRecognizer* CreateRotationGesture() +{ + // [Start create_rotation_gesture] + // 获取手势Native接口集合 + auto gestureApi = reinterpret_cast( + OH_ArkUI_QueryModuleInterfaceByName(ARKUI_NATIVE_GESTURE, "ArkUI_NativeGestureAPI_1")); + // 创建旋转手势 + auto rotationGesture = gestureApi->createRotationGesture(1, DISTANCE_NUM_1); + // [End create_rotation_gesture] + return rotationGesture; +} + +ArkUI_GestureRecognizer* CreateSwiperGesture() +{ + // [Start create_swiper_gesture] + // 获取手势Native接口集合 + auto gestureApi = reinterpret_cast( + OH_ArkUI_QueryModuleInterfaceByName(ARKUI_NATIVE_GESTURE, "ArkUI_NativeGestureAPI_1")); + // 创建快滑手势 + auto swipeGesture = gestureApi->createSwipeGesture(GINGERS_NUM_1, GESTURE_DIRECTION_ALL, SPEED_NUM_50); + // [End create_swiper_gesture] + return swipeGesture; +} + +void GetEventsForGesture(ArkUI_NodeHandle &columnNode) +{ + auto column = nodeAPI->createNode(ARKUI_NODE_COLUMN); + // 设置背景色 + ArkUI_NumberValue value[] = {{.u32 = 0xff445566}}; + ArkUI_AttributeItem item = {value, 1}; + nodeAPI->setAttribute(column, NODE_BACKGROUND_COLOR, &item); + // 设置宽度 + ArkUI_NumberValue widthValue[] = {{DURATION_NUM_100}}; + ArkUI_AttributeItem width = {widthValue, 1}; + nodeAPI->setAttribute(column, NODE_WIDTH, &width); + // 设置高度 + ArkUI_NumberValue heightValue[] = {{DURATION_NUM_100}}; + ArkUI_AttributeItem height = {heightValue, 1}; + nodeAPI->setAttribute(column, NODE_HEIGHT, &height); + nodeAPI->addChild(columnNode, column); + + auto gestureApi = reinterpret_cast( + OH_ArkUI_QueryModuleInterfaceByName(ARKUI_NATIVE_GESTURE, "ArkUI_NativeGestureAPI_1")); + // [Start gesture_callback] + // 设置回调,在触发手势事件时执行回调处理手势事件 + auto onActionCallback = [](ArkUI_GestureEvent *event, void *extraParams) { + // 从手势事件获取基础事件对象 + auto *inputEvent = OH_ArkUI_GestureEvent_GetRawInputEvent(event); + // 从基础事件获取事件信息 + auto x = OH_ArkUI_PointerEvent_GetX(inputEvent); + auto y = OH_ArkUI_PointerEvent_GetY(inputEvent); + auto displayX = OH_ArkUI_PointerEvent_GetDisplayX(inputEvent); + auto displayY = OH_ArkUI_PointerEvent_GetDisplayY(inputEvent); + auto windowX = OH_ArkUI_PointerEvent_GetWindowX(inputEvent); + auto windowY = OH_ArkUI_PointerEvent_GetWindowY(inputEvent); + auto pointerCount = OH_ArkUI_PointerEvent_GetPointerCount(inputEvent); + auto xByIndex = OH_ArkUI_PointerEvent_GetXByIndex(inputEvent, 0); + auto yByIndex = OH_ArkUI_PointerEvent_GetYByIndex(inputEvent, 0); + auto displayXByIndex = OH_ArkUI_PointerEvent_GetDisplayXByIndex(inputEvent, 0); + auto displayYByIndex = OH_ArkUI_PointerEvent_GetDisplayYByIndex(inputEvent, 0); + auto windowXByIndex = OH_ArkUI_PointerEvent_GetWindowXByIndex(inputEvent, 0); + auto windowYByIndex = OH_ArkUI_PointerEvent_GetWindowYByIndex(inputEvent, 0); + auto pointerId = OH_ArkUI_PointerEvent_GetPointerId(inputEvent, 0); + auto pressure = OH_ArkUI_PointerEvent_GetPressure(inputEvent, 0); + auto action = OH_ArkUI_UIInputEvent_GetAction(inputEvent); + auto eventTime = OH_ArkUI_UIInputEvent_GetEventTime(inputEvent); + auto sourceType = OH_ArkUI_UIInputEvent_GetSourceType(inputEvent); + auto type = OH_ArkUI_UIInputEvent_GetType(inputEvent); + std::string eventInfo = + "x: " + std::to_string(x) + ", y: " + std::to_string(y) + + ", displayX: " + std::to_string(displayX) + ", displayY: " + std::to_string(displayY) + + ", windowX: " + std::to_string(windowX) + ", windowY: " + std::to_string(windowY) + "\n" + + ", pointerCount: " + std::to_string(pointerCount) + ", xByIndex: " + std::to_string(xByIndex) + + ", yByIndex: " + std::to_string(yByIndex) + + ", displayXByIndex: " + std::to_string(displayXByIndex) + + ", displayYByIndex: " + std::to_string(displayYByIndex) + + ", windowXByIndex: " + std::to_string(windowXByIndex) + + ", windowYByIndex: " + std::to_string(windowYByIndex) + "\n" + + ", pointerId: " + std::to_string(pointerId) + ", pressure: " + std::to_string(pressure) + + ", action: " + std::to_string(action) + ", eventTime: " + std::to_string(eventTime) + + ", sourceType: " + std::to_string(sourceType) + ", type: " + std::to_string(type); + OH_LOG_Print(LOG_APP, LOG_INFO, LOG_PRINT_DOMAIN, "[Sample_NdkAddInteractionEvent]", + "NdkAddInteractionEvent_eventInfoOfCommonEvent eventInfo = %{public}s", eventInfo.c_str()); + }; + // 创建一个单指点击手势 + auto TapGesture = gestureApi->createTapGesture(COUNT_NUM_1, GINGERS_NUM_1); + // 将事件回调绑定到TapGesture上,触发手势后,通过回调函数处理手势事件 + gestureApi->setGestureEventTarget(TapGesture, + GESTURE_EVENT_ACTION_ACCEPT | GESTURE_EVENT_ACTION_UPDATE | + GESTURE_EVENT_ACTION_END | GESTURE_EVENT_ACTION_CANCEL, + column, onActionCallback); + // 将手势添加到column组件上,使column组件可以触发单指点击手势 + gestureApi->addGestureToNode(column, TapGesture, ArkUI_GesturePriority::PARALLEL, + ArkUI_GestureMask::NORMAL_GESTURE_MASK); + // [End gesture_callback] + nodeAPI->addChild(columnNode, column); +} + +void FirstModuleForGesture(ArkUI_NodeHandle &root) +{ + auto columnNode = nodeAPI->createNode(ARKUI_NODE_COLUMN); + SetId(columnNode, "bg"); + SetWidthPercent(columnNode, GINGERS_NUM_1); + SetHeightPercent(columnNode, GINGERS_NUM_1); + + // [Start create_column] + // 创建Column节点 + auto column = nodeAPI->createNode(ARKUI_NODE_COLUMN); + // 设置背景色 + ArkUI_NumberValue value[] = {{.u32 = 0xff112233}}; + ArkUI_AttributeItem item = {value, GINGERS_NUM_1}; + nodeAPI->setAttribute(column, NODE_BACKGROUND_COLOR, &item); + // 设置宽度 + ArkUI_NumberValue widthValue[] = {{400}}; + ArkUI_AttributeItem width = {widthValue, GINGERS_NUM_1}; + nodeAPI->setAttribute(column, NODE_WIDTH, &width); + // 设置高度 + ArkUI_NumberValue heightValue[] = {{400}}; + ArkUI_AttributeItem height = {heightValue, GINGERS_NUM_1}; + nodeAPI->setAttribute(column, NODE_HEIGHT, &height); + // [End create_column] + // [Start create_long_press] + // 获取手势Native接口集合 + auto gestureApi = reinterpret_cast( + OH_ArkUI_QueryModuleInterfaceByName(ARKUI_NATIVE_GESTURE, "ArkUI_NativeGestureAPI_1")); + // 创建长按手势 + auto longPressGesture = gestureApi->createLongPressGesture(GINGERS_NUM_1, true, DURATION_NUM_1000); + // [End create_long_press] + // [Start bind_event] + auto onActionCallBack = [](ArkUI_GestureEvent *event, void *extraParam) { + // 回调内容 + // [StartExclude bind_event] + OH_LOG_Print(LOG_APP, LOG_INFO, LOG_PRINT_DOMAIN, "[Sample_NdkAddInteractionEvent]", + "NdkAddInteractionEvent_eventInfo componentEvent longPressGesture"); + // [EndExclude bind_event] + }; + + // 将手势设置到组件上 + gestureApi->setGestureEventTarget( + longPressGesture, GESTURE_EVENT_ACTION_ACCEPT | GESTURE_EVENT_ACTION_UPDATE | GESTURE_EVENT_ACTION_END, column, + onActionCallBack); + + gestureApi->addGestureToNode(column, longPressGesture, PARALLEL, NORMAL_GESTURE_MASK); + // [End bind_event] + // [Start create_custom_gestures] + auto onInterruptCallback = [](ArkUI_GestureInterruptInfo *info) -> ArkUI_GestureInterruptResult { + // 获取是否系统手势 + auto sysTag = OH_ArkUI_GestureInterruptInfo_GetSystemFlag(info); + // 获取拦截的手势指针 + auto recognizer = OH_ArkUI_GestureInterruptInfo_GetRecognizer(info); + // 获取系统手势类型 + auto systemRecognizerType = OH_ArkUI_GestureInterruptInfo_GetSystemRecognizerType(info); + // 获取手势事件 + auto gestureEvent = OH_ArkUI_GestureInterruptInfo_GetGestureEvent(info); + auto inputEvent = OH_ArkUI_GestureEvent_GetRawInputEvent(gestureEvent); + OH_LOG_Print(LOG_APP, LOG_INFO, LOG_PRINT_DOMAIN, "[Sample_NdkAddInteractionEvent]", + "NdkAddInteractionEvent_eventInfo longPressGesture"); + if (sysTag) { + // 如果是系统手势则不拦截 + return GESTURE_INTERRUPT_RESULT_CONTINUE; + } else { + // 不是系统手势则拒绝 + return GESTURE_INTERRUPT_RESULT_REJECT; + } + }; + // [End create_custom_gestures] + // [Start bind_gestures] + gestureApi->setGestureInterrupterToNode(column, onInterruptCallback); + // [End bind_gestures] + nodeAPI->addChild(columnNode, column); + + GetEventsForGesture(columnNode); + + nodeAPI->addChild(root, columnNode); +} + +} // namespace NativeXComponentSample + +#endif // NDKCOMPONENTLISTEN_FUNCTION_H diff --git a/ArkUIKit/NdkAddInteractionEvent/entry/src/main/cpp/LongPressAndFlickGesture.h b/ArkUIKit/NdkAddInteractionEvent/entry/src/main/cpp/LongPressAndFlickGesture.h new file mode 100644 index 0000000000000000000000000000000000000000..12f7b9dbba398d61a192539894c11ec5b05f0ada --- /dev/null +++ b/ArkUIKit/NdkAddInteractionEvent/entry/src/main/cpp/LongPressAndFlickGesture.h @@ -0,0 +1,165 @@ +/* + * 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. + */ + +#ifndef LONG_PRESS_AND_FLICK_GESTURE_H +#define LONG_PRESS_AND_FLICK_GESTURE_H +// [Start long_press_and_flick_gesture] +#include +#include +#include +#include +#include +#include +#include +#include "Common.h" +#include "Function.h" +// [StartExclude long_press_and_flick_gesture] +namespace NativeModule { +// [EndExclude long_press_and_flick_gesture] + +ArkUI_NodeHandle LongPressAndFlickGesture() +{ + auto column = nodeAPI->createNode(ARKUI_NODE_COLUMN); + + // 创建节点 + ArkUI_NumberValue value[] = {{.u32 = 0xff112233}}; + ArkUI_AttributeItem item = {value, ITEM_SIZE_ONE}; + nodeAPI->setAttribute(column, NODE_BACKGROUND_COLOR, &item); + ArkUI_NumberValue widthValue[] = {{WIDTH_SIZE}}; + ArkUI_AttributeItem width = {widthValue, ITEM_SIZE_ONE}; + nodeAPI->setAttribute(column, NODE_WIDTH, &width); + ArkUI_NumberValue heightValue[] = {{HEIGHT_SIZE}}; + ArkUI_AttributeItem height = {heightValue, ITEM_SIZE_ONE}; + nodeAPI->setAttribute(column, NODE_HEIGHT, &height); + + // 判断是否支持创建手势 + auto gestureApi = reinterpret_cast( + OH_ArkUI_QueryModuleInterfaceByName(ARKUI_NATIVE_GESTURE, "ArkUI_NativeGestureAPI_1")); + if (gestureApi->createGroupGesture) { + OH_LOG_Print(LOG_APP, LOG_INFO, LOG_PRINT_DOMAIN, "[Sample_NdkAddInteractionEvent]", + "NdkAddInteractionEvent_GestureSampleLog, createGroupGesture api exist"); + } else { + OH_LOG_Print(LOG_APP, LOG_INFO, LOG_PRINT_DOMAIN, "[Sample_NdkAddInteractionEvent]", + "NdkAddInteractionEvent_GestureSampleLog, createGroupGesture api not exist"); + } + + // 创建手势组 + auto groupGesture = gestureApi->createGroupGesture(ArkUI_GroupGestureMode::PARALLEL_GROUP); + + // 创建长按手势 + auto longPressGesture = gestureApi->createLongPressGesture(GINGERS_NUM, true, DURATION_NUM_500); + if (gestureApi->getGestureType) { + ArkUI_GestureRecognizerType type = gestureApi->getGestureType(longPressGesture); + OH_LOG_Print(LOG_APP, LOG_INFO, LOG_PRINT_DOMAIN, "[Sample_NdkAddInteractionEvent]", + "NdkAddInteractionEvent_GestureSampleLog,ArkUI_GestureRecognizerType%{public}d", type); + } + // 给长按手势定回调 + auto onActionCallBackPanLongPress = [](ArkUI_GestureEvent *event, void *extraParam) { + ArkUI_GestureEventActionType actionType = OH_ArkUI_GestureEvent_GetActionType(event); + + float velocity = OH_ArkUI_PanGesture_GetVelocity(event); + float velocityX = OH_ArkUI_PanGesture_GetVelocityX(event); + float velocityY = OH_ArkUI_PanGesture_GetVelocityY(event); + float offsetX = OH_ArkUI_PanGesture_GetOffsetX(event); + float offsetY = OH_ArkUI_PanGesture_GetOffsetY(event); + float scale = OH_ArkUI_PinchGesture_GetScale(event); + float centerX = OH_ArkUI_PinchGesture_GetCenterX(event); + float centerY = OH_ArkUI_PinchGesture_GetCenterY(event); + float angle = OH_ArkUI_SwipeGesture_GetAngle(event); + float velocityS = OH_ArkUI_SwipeGesture_GetVelocity(event); + float angleR = OH_ArkUI_RotationGesture_GetAngle(event); + float repeat = OH_ArkUI_LongPress_GetRepeatCount(event); + + OH_LOG_Print( + LOG_APP, LOG_INFO, LOG_PRINT_DOMAIN, "[Sample_NdkAddInteractionEvent]", + "NdkAddInteractionEvent_GestureSampleLog,longPressGesturecallback actionType:%{public}d," + "velocity%{public}f,velocityX%{public}f;" + "velocityY%{public}f,offsetX%{public}f,offsetY%{public}f,scale%{public}f, centerX " + "%{public}fcenterY" + "%{public}fangle%{public}fvelocityS%{public}fangleR%{public}frepeat%{public}f", + actionType, velocity, velocityX, velocityY, offsetX, offsetY, scale, centerX, centerY, angle, velocityS, + angleR, repeat); + }; + gestureApi->setGestureEventTarget(longPressGesture, + GESTURE_EVENT_ACTION_ACCEPT | GESTURE_EVENT_ACTION_UPDATE | + GESTURE_EVENT_ACTION_CANCEL, + column, onActionCallBackPanLongPress); + + // 将长按手势添加到手势组 + if (gestureApi->addChildGesture) { + gestureApi->addChildGesture(groupGesture, longPressGesture); + OH_LOG_Print(LOG_APP, LOG_INFO, LOG_PRINT_DOMAIN, "[Sample_NdkAddInteractionEvent]", + "NdkAddInteractionEvent_GestureSampleLog, addChildGesture longPressGesture"); + } + // 创建快滑手势 swipe + auto swipeGesture = gestureApi->createSwipeGesture(GINGERS_NUM, GESTURE_DIRECTION_ALL, DURATION_NUM_100); + if (gestureApi->getGestureType) { + ArkUI_GestureRecognizerType type = gestureApi->getGestureType(swipeGesture); + OH_LOG_Print(LOG_APP, LOG_INFO, LOG_PRINT_DOMAIN, "[Sample_NdkAddInteractionEvent]", + "NdkAddInteractionEvent_GestureSampleLog, ArkUI_GestureRecognizerType %{public}d", + type); + } + // 给快滑手势绑定回调 + auto onActionCallBack = [](ArkUI_GestureEvent *event, void *extraParam) { + ArkUI_GestureEventActionType actionType = OH_ArkUI_GestureEvent_GetActionType(event); + + float velocity = OH_ArkUI_PanGesture_GetVelocity(event); + float velocityX = OH_ArkUI_PanGesture_GetVelocityX(event); + float velocityY = OH_ArkUI_PanGesture_GetVelocityY(event); + float offsetX = OH_ArkUI_PanGesture_GetOffsetX(event); + float offsetY = OH_ArkUI_PanGesture_GetOffsetY(event); + float scale = OH_ArkUI_PinchGesture_GetScale(event); + float centerX = OH_ArkUI_PinchGesture_GetCenterX(event); + float centerY = OH_ArkUI_PinchGesture_GetCenterY(event); + float angle = OH_ArkUI_SwipeGesture_GetAngle(event); + float velocityS = OH_ArkUI_SwipeGesture_GetVelocity(event); + float angleR = OH_ArkUI_RotationGesture_GetAngle(event); + float repeat = OH_ArkUI_LongPress_GetRepeatCount(event); + + // 通过日志查看 + OH_LOG_Print(LOG_APP, LOG_INFO, LOG_PRINT_DOMAIN, "[Sample_NdkAddInteractionEvent]", + "NdkAddInteractionEvent_GestureSampleLog, swipeGesture " + "callback actionType: %{public}d, velocity%{public}f,velocityX " + "%{public}f; " + "velocityY %{public}f, offsetX %{public}f, offsetY %{public}f, scale %{public}f, centerX " + "%{public}f centerY" + " %{public}f angle %{public}f velocityS %{public}f angleR %{public}f repeat %{public}f", + actionType, velocity, velocityX, velocityY, offsetX, offsetY, scale, centerX, centerY, angle, + velocityS, angleR, repeat); + + ArkUI_NumberValue value[] = {{.f32 = 0}, {.f32 = 0}, {.f32 = 0}, {.f32 = angleR}, {.f32 = 0}}; + ArkUI_AttributeItem item = {value, ITEM_SIZE_FIVE}; + auto column = reinterpret_cast(extraParam); + nodeAPI->setAttribute(column, NODE_ROTATE, &item); + }; + + gestureApi->setGestureEventTarget( + swipeGesture, GESTURE_EVENT_ACTION_ACCEPT | GESTURE_EVENT_ACTION_UPDATE | GESTURE_EVENT_ACTION_END, column, + onActionCallBack); + + // 将快滑手势添加到手势组 + if (gestureApi->addChildGesture) { + gestureApi->addChildGesture(groupGesture, swipeGesture); + OH_LOG_Print(LOG_APP, LOG_INFO, LOG_PRINT_DOMAIN, "[Sample_NdkAddInteractionEvent]", + "NdkAddInteractionEvent_GestureSampleLog, addChildGesture swipeGesture"); + } + // 将手势组设置到组件上 + gestureApi->addGestureToNode(column, groupGesture, PRIORITY, NORMAL_GESTURE_MASK); + return column; +} +// [End long_press_and_flick_gesture] +} // namespace NativeXComponentSample + +#endif // LONG_PRESS_AND_FLICK_GESTURE_H \ No newline at end of file diff --git a/ArkUIKit/NdkAddInteractionEvent/entry/src/main/cpp/LongPressAndSwipeGesture.h b/ArkUIKit/NdkAddInteractionEvent/entry/src/main/cpp/LongPressAndSwipeGesture.h new file mode 100644 index 0000000000000000000000000000000000000000..a318c141fbc629ee246c37b87a9a9cf7f216c5da --- /dev/null +++ b/ArkUIKit/NdkAddInteractionEvent/entry/src/main/cpp/LongPressAndSwipeGesture.h @@ -0,0 +1,161 @@ +/* + * 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. + */ + +#ifndef LONG_PRESS_AND_SWIPE_GESTURE_H +#define LONG_PRESS_AND_SWIPE_GESTURE_H +// [Start long_press_and_swipe_gesture] +#include +#include +#include +#include +#include +#include +#include +#include "Common.h" +#include "Function.h" +// [StartExclude long_press_and_swipe_gesture] +namespace NativeModule { +// [EndExclude long_press_and_swipe_gesture] +ArkUI_NodeHandle LongPressAndSwipeGesture() +{ + auto column = nodeAPI->createNode(ARKUI_NODE_COLUMN); + + // 创建节点 + ArkUI_NumberValue value[] = {{.u32 = 0xff112233}}; + ArkUI_AttributeItem item = {value, ITEM_SIZE_ONE}; + nodeAPI->setAttribute(column, NODE_BACKGROUND_COLOR, &item); + ArkUI_NumberValue widthValue[] = {{WIDTH_SIZE}}; + ArkUI_AttributeItem width = {widthValue, ITEM_SIZE_ONE}; + nodeAPI->setAttribute(column, NODE_WIDTH, &width); + ArkUI_NumberValue heightValue[] = {{HEIGHT_SIZE}}; + ArkUI_AttributeItem height = {heightValue, ITEM_SIZE_ONE}; + nodeAPI->setAttribute(column, NODE_HEIGHT, &height); + + // 判断是否支持创建手势 + auto gestureApi = reinterpret_cast( + OH_ArkUI_QueryModuleInterfaceByName(ARKUI_NATIVE_GESTURE, "ArkUI_NativeGestureAPI_1")); + if (gestureApi->createGroupGesture) { + OH_LOG_Print(LOG_APP, LOG_INFO, LOG_PRINT_DOMAIN, "[Sample_NdkAddInteractionEvent]", + "NdkAddInteractionEvent_GestureSampleLog, createGroupGesture api exist"); + } else { + OH_LOG_Print(LOG_APP, LOG_INFO, LOG_PRINT_DOMAIN, "[Sample_NdkAddInteractionEvent]", + "NdkAddInteractionEvent_GestureSampleLog, createGroupGesture api not exist"); + } + auto groupGesture = gestureApi->createGroupGesture(ArkUI_GroupGestureMode::SEQUENTIAL_GROUP); + + // 创建长按手势 + auto longPressGesture = gestureApi->createLongPressGesture(GINGERS_NUM, true, DURATION_NUM); + if (gestureApi->getGestureType) { + ArkUI_GestureRecognizerType type = gestureApi->getGestureType(longPressGesture); + OH_LOG_Print(LOG_APP, LOG_INFO, LOG_PRINT_DOMAIN, "[Sample_NdkAddInteractionEvent]", + "NdkAddInteractionEvent_GestureSampleLog longPressGesture," + "ArkUI_GestureRecognizerType%{public}d", type); + } + // 给长按手势定回调 + auto onActionCallBackPanLongPress = [](ArkUI_GestureEvent *event, void *extraParam) { + ArkUI_GestureEventActionType actionType = OH_ArkUI_GestureEvent_GetActionType(event); + + float velocity = OH_ArkUI_PanGesture_GetVelocity(event); + float velocityX = OH_ArkUI_PanGesture_GetVelocityX(event); + float velocityY = OH_ArkUI_PanGesture_GetVelocityY(event); + float offsetX = OH_ArkUI_PanGesture_GetOffsetX(event); + float offsetY = OH_ArkUI_PanGesture_GetOffsetY(event); + float scale = OH_ArkUI_PinchGesture_GetScale(event); + float centerX = OH_ArkUI_PinchGesture_GetCenterX(event); + float centerY = OH_ArkUI_PinchGesture_GetCenterY(event); + float angle = OH_ArkUI_SwipeGesture_GetAngle(event); + float velocityS = OH_ArkUI_SwipeGesture_GetVelocity(event); + float angleR = OH_ArkUI_RotationGesture_GetAngle(event); + float repeat = OH_ArkUI_LongPress_GetRepeatCount(event); + + OH_LOG_Print( + LOG_APP, LOG_INFO, LOG_PRINT_DOMAIN, "[Sample_NdkAddInteractionEvent]", + "NdkAddInteractionEvent_GestureSampleLog,longPressGesturecallback actionType:%{public}d," + "velocity%{public}f,velocityX%{public}f;" + "velocityY%{public}f,offsetX%{public}f,offsetY%{public}f,scale%{public}fcenterX" + "%{public}fcenterY" + "%{public}fangle%{public}fvelocityS%{public}fangleR%{public}frepeat%{public}f", + actionType, velocity, velocityX, velocityY, offsetX, offsetY, scale, centerX, centerY, angle, velocityS, + angleR, repeat); + }; + gestureApi->setGestureEventTarget(longPressGesture, + GESTURE_EVENT_ACTION_ACCEPT | GESTURE_EVENT_ACTION_UPDATE | + GESTURE_EVENT_ACTION_CANCEL, column, onActionCallBackPanLongPress); + + // 将长按手势添加到手势组 + if (gestureApi->addChildGesture) { + gestureApi->addChildGesture(groupGesture, longPressGesture); + OH_LOG_Print(LOG_APP, LOG_INFO, LOG_PRINT_DOMAIN, "[Sample_NdkAddInteractionEvent]", + "NdkAddInteractionEvent_GestureSampleLog, addChildGesture longPressGesture"); + } + // 创建快滑手势 swipe + auto swipeGesture = gestureApi->createSwipeGesture(1, GESTURE_DIRECTION_ALL, 100); + if (gestureApi->getGestureType) { + ArkUI_GestureRecognizerType type = gestureApi->getGestureType(swipeGesture); + OH_LOG_Print(LOG_APP, LOG_INFO, LOG_PRINT_DOMAIN, "[Sample_NdkAddInteractionEvent]", + "NdkAddInteractionEvent_GestureSampleLog, ArkUI_GestureRecognizerType %{public}d", + type); + } + // 给快滑手势绑定回调 + auto onActionCallBack = [](ArkUI_GestureEvent *event, void *extraParam) { + ArkUI_GestureEventActionType actionType = OH_ArkUI_GestureEvent_GetActionType(event); + + float velocity = OH_ArkUI_PanGesture_GetVelocity(event); + float velocityX = OH_ArkUI_PanGesture_GetVelocityX(event); + float velocityY = OH_ArkUI_PanGesture_GetVelocityY(event); + float offsetX = OH_ArkUI_PanGesture_GetOffsetX(event); + float offsetY = OH_ArkUI_PanGesture_GetOffsetY(event); + float scale = OH_ArkUI_PinchGesture_GetScale(event); + float centerX = OH_ArkUI_PinchGesture_GetCenterX(event); + float centerY = OH_ArkUI_PinchGesture_GetCenterY(event); + float angle = OH_ArkUI_SwipeGesture_GetAngle(event); + float velocityS = OH_ArkUI_SwipeGesture_GetVelocity(event); + float angleR = OH_ArkUI_RotationGesture_GetAngle(event); + float repeat = OH_ArkUI_LongPress_GetRepeatCount(event); + + // 通过日志查看 + OH_LOG_Print(LOG_APP, LOG_INFO, LOG_PRINT_DOMAIN, "[Sample_NdkAddInteractionEvent]", + "NdkAddInteractionEvent_GestureSampleLog, swipeGesture " + "callback actionType: %{public}d, velocity %{public}f,velocityX " + "%{public}f; " + "velocityY %{public}f, offsetX %{public}f, offsetY %{public}f, scale %{public}fcenterX " + "%{public}f centerY" + " %{public}f angle %{public}f velocityS %{public}f angleR %{public}f repeat %{public}f", + actionType, velocity, velocityX, velocityY, offsetX, offsetY, scale, centerX, centerY, angle, + velocityS, angleR, repeat); + + ArkUI_NumberValue value[] = {{.f32 = 0}, {.f32 = 0}, {.f32 = 0}, {.f32 = angleR}, {.f32 = 0}}; + ArkUI_AttributeItem item = {value, ITEM_SIZE_FIVE}; + auto column = reinterpret_cast(extraParam); + nodeAPI->setAttribute(column, NODE_ROTATE, &item); + }; + + gestureApi->setGestureEventTarget( + swipeGesture, GESTURE_EVENT_ACTION_ACCEPT | GESTURE_EVENT_ACTION_UPDATE | GESTURE_EVENT_ACTION_END, column, + onActionCallBack); + + // 将快滑手势添加到手势组 + if (gestureApi->addChildGesture) { + gestureApi->addChildGesture(groupGesture, swipeGesture); + OH_LOG_Print(LOG_APP, LOG_INFO, LOG_PRINT_DOMAIN, "[Sample_NdkAddInteractionEvent]", + "NdkAddInteractionEvent_GestureSampleLog, addChildGesture swipeGesture"); + } + // 将手势组设置到组件上 + gestureApi->addGestureToNode(column, groupGesture, PRIORITY, NORMAL_GESTURE_MASK); + return column; +} +// [End long_press_and_swipe_gesture] +} // namespace NativeXComponentSample +#endif // LONG_PRESS_AND_SWIPE_GESTURE_H \ No newline at end of file diff --git a/ArkUIKit/NdkAddInteractionEvent/entry/src/main/cpp/NativeEntry.cpp b/ArkUIKit/NdkAddInteractionEvent/entry/src/main/cpp/NativeEntry.cpp new file mode 100644 index 0000000000000000000000000000000000000000..95a33d4e71d877e387517964677faabfb6ce67ba --- /dev/null +++ b/ArkUIKit/NdkAddInteractionEvent/entry/src/main/cpp/NativeEntry.cpp @@ -0,0 +1,161 @@ +/* + * 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. + */ + +// NativeEntry.cpp + +#include +#include +#include +#include "Common.h" +#include "Function.h" +#include "LongPressAndSwipeGesture.h" +#include "LongPressAndFlickGesture.h" +#include "NativeEntry.h" +#include "NormalTextListExample.h" +#include "SwipeAndPinchExclusiveGesture.h" + + +namespace NativeModule { + +napi_value CreateNativeNode(napi_env env, napi_callback_info info) +{ + size_t argc = 1; + napi_value args[1] = {nullptr}; + + napi_get_cb_info(env, info, &argc, args, nullptr, nullptr); + + // 获取NodeContent + ArkUI_NodeContentHandle contentHandle; + OH_ArkUI_GetNodeContentFromNapiValue(env, args[0], &contentHandle); + + OH_ArkUI_GetModuleInterface(ARKUI_NATIVE_NODE, ArkUI_NativeNodeAPI_1, nodeAPI); + auto column = nodeAPI->createNode(ARKUI_NODE_COLUMN); + SetBorderWidth(column, DEFAULT_BORDER_WIDTH); + SetColumnJustifyContent(column, ARKUI_FLEX_ALIGNMENT_START); + SetColumnAlignItem(column, ARKUI_HORIZONTAL_ALIGNMENT_START); + SetPadding(column, BLANK_10); + + FirstModule(column); + + auto blank1 = nodeAPI->createNode(ARKUI_NODE_COLUMN); + SetHeight(blank1, BLANK_20); + nodeAPI->addChild(column, blank1); + SecondModule(column); + OH_ArkUI_NodeContent_AddNode(contentHandle, column); + return nullptr; +} + +napi_value CreateNativeNodeForGesture(napi_env env, napi_callback_info info) +{ + size_t argc = 1; + napi_value args[1] = {nullptr}; + + napi_get_cb_info(env, info, &argc, args, nullptr, nullptr); + + // 获取NodeContent + ArkUI_NodeContentHandle contentHandle; + OH_ArkUI_GetNodeContentFromNapiValue(env, args[0], &contentHandle); + // [Start get_module_interface] + OH_ArkUI_GetModuleInterface(ARKUI_NATIVE_NODE, ArkUI_NativeNodeAPI_1, nodeAPI); + // [End get_module_interface] + + auto column = nodeAPI->createNode(ARKUI_NODE_COLUMN); + + SetBorderWidth(column, DEFAULT_BORDER_WIDTH); + SetColumnJustifyContent(column, ARKUI_FLEX_ALIGNMENT_START); + SetColumnAlignItem(column, ARKUI_HORIZONTAL_ALIGNMENT_START); + SetPadding(column, BLANK_10); + + FirstModuleForGesture(column); + OH_ArkUI_NodeContent_AddNode(contentHandle, column); + return nullptr; +} + +napi_value CreateNativeNodeForLongPressAndSwipe(napi_env env, napi_callback_info info) +{ + size_t argc = 1; + napi_value args[1] = {nullptr}; + + napi_get_cb_info(env, info, &argc, args, nullptr, nullptr); + + // 获取NodeContent + ArkUI_NodeContentHandle contentHandle; + OH_ArkUI_GetNodeContentFromNapiValue(env, args[0], &contentHandle); + OH_ArkUI_GetModuleInterface(ARKUI_NATIVE_NODE, ArkUI_NativeNodeAPI_1, nodeAPI); + auto column = LongPressAndSwipeGesture(); + OH_ArkUI_NodeContent_AddNode(contentHandle, column); + return nullptr; +} + +napi_value CreateNativeNodeForLongPressAndFlick(napi_env env, napi_callback_info info) +{ + size_t argc = 1; + napi_value args[1] = {nullptr}; + + napi_get_cb_info(env, info, &argc, args, nullptr, nullptr); + + // 获取NodeContent + ArkUI_NodeContentHandle contentHandle; + OH_ArkUI_GetNodeContentFromNapiValue(env, args[0], &contentHandle); + OH_ArkUI_GetModuleInterface(ARKUI_NATIVE_NODE, ArkUI_NativeNodeAPI_1, nodeAPI); + auto column = LongPressAndFlickGesture(); + OH_ArkUI_NodeContent_AddNode(contentHandle, column); + return nullptr; +} + +napi_value CreateNativeNodeForSwipeAndPinchExclusive(napi_env env, napi_callback_info info) +{ + size_t argc = 1; + napi_value args[1] = {nullptr}; + + napi_get_cb_info(env, info, &argc, args, nullptr, nullptr); + + // 获取NodeContent + ArkUI_NodeContentHandle contentHandle; + OH_ArkUI_GetNodeContentFromNapiValue(env, args[0], &contentHandle); + + OH_ArkUI_GetModuleInterface(ARKUI_NATIVE_NODE, ArkUI_NativeNodeAPI_1, nodeAPI); + auto column = SwipeAndPinchExclusiveGesture(); + OH_ArkUI_NodeContent_AddNode(contentHandle, column); + return nullptr; +} + +napi_value CreateNativeRoot(napi_env env, napi_callback_info info) +{ + size_t argc = 1; + napi_value args[1] = {nullptr}; + + napi_get_cb_info(env, info, &argc, args, nullptr, nullptr); + + // 获取NodeContent + ArkUI_NodeContentHandle contentHandle; + OH_ArkUI_GetNodeContentFromNapiValue(env, args[0], &contentHandle); + NativeEntry::GetInstance()->SetContentHandle(contentHandle); + + // 创建文本列表 + auto list = CreateTextListExample(); + + // 保持Native侧对象到管理类中,维护生命周期。 + NativeEntry::GetInstance()->SetRootNode(list); + return nullptr; +} + +napi_value DestroyNativeRoot(napi_env env, napi_callback_info info) +{ + // 从管理类中释放Native侧对象。 + NativeEntry::GetInstance()->DisposeRootNode(); + return nullptr; +} +} // namespace NativeModule diff --git a/ArkUIKit/NdkAddInteractionEvent/entry/src/main/cpp/NativeEntry.h b/ArkUIKit/NdkAddInteractionEvent/entry/src/main/cpp/NativeEntry.h new file mode 100644 index 0000000000000000000000000000000000000000..5cea20cd620892916c4436ab4780568790d88933 --- /dev/null +++ b/ArkUIKit/NdkAddInteractionEvent/entry/src/main/cpp/NativeEntry.h @@ -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. + */ + +// NativeEntry.h + +#ifndef MYAPPLICATION_NATIVEENTRY_H +#define MYAPPLICATION_NATIVEENTRY_H + +#include +#include +#include + +namespace NativeModule { + +napi_value CreateNativeRoot(napi_env env, napi_callback_info info); + +napi_value DestroyNativeRoot(napi_env env, napi_callback_info info); + +napi_value CreateNativeNode(napi_env env, napi_callback_info info); + +napi_value CreateNativeNodeForGesture(napi_env env, napi_callback_info info); + +napi_value CreateNativeNodeForLongPressAndSwipe(napi_env env, napi_callback_info info); + +napi_value CreateNativeNodeForLongPressAndFlick(napi_env env, napi_callback_info info); + +napi_value CreateNativeNodeForSwipeAndPinchExclusive(napi_env env, napi_callback_info info); + +// 管理Native组件的生命周期和内存。 +class NativeEntry { +public: + static NativeEntry *GetInstance() + { + static NativeEntry nativeEntry; + return &nativeEntry; + } + + void SetContentHandle(ArkUI_NodeContentHandle handle) + { + handle_ = handle; + } + + void SetRootNode(const std::shared_ptr &baseNode) + { + root_ = baseNode; + // 添加Native组件到NodeContent上用于挂载显示。 + OH_ArkUI_NodeContent_AddNode(handle_, root_->GetHandle()); + } + + void DisposeRootNode() + { + // 从NodeContent上卸载组件并销毁Native组件。 + OH_ArkUI_NodeContent_RemoveNode(handle_, root_->GetHandle()); + root_.reset(); + } + +private: + std::shared_ptr root_; + ArkUI_NodeContentHandle handle_; +}; + +} // namespace NativeModule + +#endif // MYAPPLICATION_NATIVEENTRY_H \ No newline at end of file diff --git a/ArkUIKit/NdkAddInteractionEvent/entry/src/main/cpp/NativeModule.h b/ArkUIKit/NdkAddInteractionEvent/entry/src/main/cpp/NativeModule.h new file mode 100644 index 0000000000000000000000000000000000000000..c2ab7178a5666c80ec0b83f0f206143c55977e4b --- /dev/null +++ b/ArkUIKit/NdkAddInteractionEvent/entry/src/main/cpp/NativeModule.h @@ -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. + */ + +// NativeModule.h +// 提供获取ArkUI在Native侧模块的封装接口 + +#ifndef MYAPPLICATION_NATIVEMODULE_H +#define MYAPPLICATION_NATIVEMODULE_H + +#include "napi/native_api.h" +#include +#include + +#include + +namespace NativeModule { + +class NativeModuleInstance { +public: + static NativeModuleInstance *GetInstance() + { + static NativeModuleInstance instance; + return &instance; + } + + NativeModuleInstance() + { + OH_ArkUI_GetModuleInterface(ARKUI_NATIVE_NODE, ArkUI_NativeNodeAPI_1, arkUINativeNodeApi_); + } + // 暴露给其他模块使用。 + ArkUI_NativeNodeAPI_1 *GetNativeNodeAPI() { return arkUINativeNodeApi_; } + +private: + ArkUI_NativeNodeAPI_1 *arkUINativeNodeApi_ = nullptr; +}; + +} // namespace NativeModule + +#endif // MYAPPLICATION_NATIVEMODULE_H \ No newline at end of file diff --git a/ArkUIKit/NdkAddInteractionEvent/entry/src/main/cpp/NormalTextListExample.h b/ArkUIKit/NdkAddInteractionEvent/entry/src/main/cpp/NormalTextListExample.h new file mode 100644 index 0000000000000000000000000000000000000000..0607f7fb16109e6860164d737c4007807b4c6f9f --- /dev/null +++ b/ArkUIKit/NdkAddInteractionEvent/entry/src/main/cpp/NormalTextListExample.h @@ -0,0 +1,133 @@ +/* + * 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 normal_text_list_example] +// TextListExample.h +// 文本列表示例。 + +#ifndef MYAPPLICATION_NORMALTEXTLISTEXAMPLE_H +#define MYAPPLICATION_NORMALTEXTLISTEXAMPLE_H + +#include "ArkUIBaseNode.h" +#include "ArkUIListItemNode.h" +#include "ArkUIListNode.h" +#include "ArkUITextNode.h" +#include +#include "Function.h" + +namespace NativeModule { + +std::shared_ptr CreateTextListExample() +{ + // 创建组件并挂载 + // 1:创建List组件。 + auto list = std::make_shared(); + list->SetPercentWidth(PERCENT_WIDTH_1); + list->SetPercentHeight(PERCENT_HEIGHT_1); + // 2:创建ListItem子组件并挂载到List上。 + for (int32_t i = 0; i < LOOP_SIZE; ++i) { + auto listItem = std::make_shared(); + auto textNode = std::make_shared(); + textNode->SetTextContent(std::to_string(i)); + textNode->SetFontSize(FONT_SIZE); + textNode->SetPercentWidth(PERCENT_WIDTH_1); + textNode->SetHeight(HEIGHT_SIZE); + textNode->SetBackgroundColor(0xFFfffacd); + textNode->SetTextAlign(ARKUI_TEXT_ALIGNMENT_CENTER); + listItem->AddChild(textNode); + // 列表项注册点击事件。 + auto onClick = [](ArkUI_NodeEvent *event) { + // 从组件事件中获取基础事件对象 + auto *inputEvent = OH_ArkUI_NodeEvent_GetInputEvent(event); + if (inputEvent == nullptr) { + return; + } + // 从组件事件获取事件类型 + auto eventType = OH_ArkUI_NodeEvent_GetEventType(event); + OH_LOG_Print(LOG_APP, LOG_INFO, LOG_PRINT_DOMAIN, "[Sample_NdkAddInteractionEvent]", + "NdkAddInteractionEvent_eventInfo inputEvent = %{public}p", inputEvent); + OH_LOG_Print(LOG_APP, LOG_INFO, LOG_PRINT_DOMAIN, "[Sample_NdkAddInteractionEvent]", + "NdkAddInteractionEvent_eventInfo eventType = %{public}d", eventType); + auto componentEvent = OH_ArkUI_NodeEvent_GetNodeComponentEvent(event); + // 获取组件事件中的数字类型数据 + OH_LOG_Print(LOG_APP, LOG_INFO, LOG_PRINT_DOMAIN, "[Sample_NdkAddInteractionEvent]", + "NdkAddInteractionEvent_eventInfo componentEvent = %{public}p", componentEvent); + // 获取触发该事件的组件对象 + auto nodeHandle = OH_ArkUI_NodeEvent_GetNodeHandle(event); + if (nodeHandle == nullptr) { + return; + } + OH_LOG_Print(LOG_APP, LOG_INFO, LOG_PRINT_DOMAIN, "[Sample_NdkAddInteractionEvent]", + "NdkAddInteractionEvent_eventInfo nodeHandle = %{public}p", nodeHandle); + // 根据eventType来区分事件类型,进行差异化处理,其他获取事件信息的接口也可类似方式来进行差异化的处理 + switch (eventType) { + case NODE_ON_CLICK_EVENT: { + // 触发点击事件所进行的操作,从基础事件获取事件信息 + auto x = OH_ArkUI_PointerEvent_GetX(inputEvent); + auto y = OH_ArkUI_PointerEvent_GetY(inputEvent); + auto displayX = OH_ArkUI_PointerEvent_GetDisplayX(inputEvent); + auto displayY = OH_ArkUI_PointerEvent_GetDisplayY(inputEvent); + auto windowX = OH_ArkUI_PointerEvent_GetWindowX(inputEvent); + auto windowY = OH_ArkUI_PointerEvent_GetWindowY(inputEvent); + auto pointerCount = OH_ArkUI_PointerEvent_GetPointerCount(inputEvent); + auto xByIndex = OH_ArkUI_PointerEvent_GetXByIndex(inputEvent, 0); + auto yByIndex = OH_ArkUI_PointerEvent_GetYByIndex(inputEvent, 0); + auto displayXByIndex = OH_ArkUI_PointerEvent_GetDisplayXByIndex(inputEvent, 0); + auto displayYByIndex = OH_ArkUI_PointerEvent_GetDisplayYByIndex(inputEvent, 0); + auto windowXByIndex = OH_ArkUI_PointerEvent_GetWindowXByIndex(inputEvent, 0); + auto windowYByIndex = OH_ArkUI_PointerEvent_GetWindowYByIndex(inputEvent, 0); + auto pointerId = OH_ArkUI_PointerEvent_GetPointerId(inputEvent, 0); + auto pressure = OH_ArkUI_PointerEvent_GetPressure(inputEvent, 0); + auto action = OH_ArkUI_UIInputEvent_GetAction(inputEvent); + auto eventTime = OH_ArkUI_UIInputEvent_GetEventTime(inputEvent); + auto sourceType = OH_ArkUI_UIInputEvent_GetSourceType(inputEvent); + auto type = OH_ArkUI_UIInputEvent_GetType(inputEvent); + std::string eventInfo = + "x: " + std::to_string(x) + ", y: " + std::to_string(y) + + ", displayX: " + std::to_string(displayX) + ", displayY: " + std::to_string(displayY) + + ", windowX: " + std::to_string(windowX) + ", windowY: " + std::to_string(windowY) + + ", pointerCount: " + std::to_string(pointerCount) + ", xByIndex: " + std::to_string(xByIndex) + + ", yByIndex: " + std::to_string(yByIndex) + + ", displayXByIndex: " + std::to_string(displayXByIndex) + + ", displayYByIndex: " + std::to_string(displayYByIndex) + + ", windowXByIndex: " + std::to_string(windowXByIndex) + + ", windowYByIndex: " + std::to_string(windowYByIndex) + + ", pointerId: " + std::to_string(pointerId) + ", pressure: " + std::to_string(pressure) + + ", action: " + std::to_string(action) + ", eventTime: " + std::to_string(eventTime) + + ", sourceType: " + std::to_string(sourceType) + ", type: " + std::to_string(type); + OH_LOG_Print(LOG_APP, LOG_INFO, LOG_PRINT_DOMAIN, "[Sample_NdkAddInteractionEvent]", + "NdkAddInteractionEvent_eventInfoOfCommonEvent eventInfo = %{public}s", + eventInfo.c_str()); + } + default: { + break; + } + } + }; + listItem->RegisterOnClick(onClick); + list->AddChild(listItem); + } + // 3:注册List相关监听事件. + list->RegisterOnScrollIndex([](int32_t index) { OH_LOG_INFO(LOG_APP, "on list scroll index: %{public}d", index); }); + // 4: 注册挂载事件。 + list->RegisterOnAppear([]() { OH_LOG_INFO(LOG_APP, "on list mount to tree"); }); + // 5: 注册卸载事件。 + list->RegisterOnDisappear([]() { OH_LOG_INFO(LOG_APP, "on list unmount from tree"); }); + return list; +} +} // namespace NativeModule + +#endif // MYAPPLICATION_NORMALTEXTLISTEXAMPLE_H +// [End normal_text_list_example] \ No newline at end of file diff --git a/ArkUIKit/NdkAddInteractionEvent/entry/src/main/cpp/SwipeAndPinchExclusiveGesture.h b/ArkUIKit/NdkAddInteractionEvent/entry/src/main/cpp/SwipeAndPinchExclusiveGesture.h new file mode 100644 index 0000000000000000000000000000000000000000..c82678958d3201c7dbe8d07489852fed7cf3f827 --- /dev/null +++ b/ArkUIKit/NdkAddInteractionEvent/entry/src/main/cpp/SwipeAndPinchExclusiveGesture.h @@ -0,0 +1,164 @@ +/* + * 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. + */ +#ifndef SWIPE_AND_PINCH_EXCLUSIVE_GESTURE_H +#define SWIPE_AND_PINCH_EXCLUSIVE_GESTURE_H + +// [Start swipe_and_pinch_exclusive_gesture] +#include +#include +#include +#include +#include +#include +#include +#include "Common.h" +#include "Function.h" +// [StartExclude swipe_and_pinch_exclusive_gesture] +namespace NativeModule { +// [EndExclude swipe_and_pinch_exclusive_gesture] + +ArkUI_NodeHandle SwipeAndPinchExclusiveGesture() +{ + OH_ArkUI_GetModuleInterface(ARKUI_NATIVE_NODE, ArkUI_NativeNodeAPI_1, nodeAPI); + if (nodeAPI == nullptr) { + return nullptr; + } + auto column = nodeAPI->createNode(ARKUI_NODE_COLUMN); + + // 创建节点 + ArkUI_NumberValue value[] = {{.u32 = 0xff112233}}; + ArkUI_AttributeItem item = {value, 1}; + nodeAPI->setAttribute(column, NODE_BACKGROUND_COLOR, &item); + ArkUI_NumberValue widthValue[] = {{WIDTH_SIZE}}; + ArkUI_AttributeItem width = {widthValue, ITEM_SIZE_ONE}; + nodeAPI->setAttribute(column, NODE_WIDTH, &width); + ArkUI_NumberValue heightValue[] = {{HEIGHT_SIZE}}; + ArkUI_AttributeItem height = {heightValue, ITEM_SIZE_ONE}; + nodeAPI->setAttribute(column, NODE_HEIGHT, &height); + + // 判断是否支持创建手势 + auto gestureApi = reinterpret_cast( + OH_ArkUI_QueryModuleInterfaceByName(ARKUI_NATIVE_GESTURE, "ArkUI_NativeGestureAPI_1")); + if (gestureApi->createGroupGesture) { + OH_LOG_Print(LOG_APP, LOG_INFO, LOG_PRINT_DOMAIN, "[Sample_NdkAddInteractionEvent]", + "NdkAddInteractionEvent_GestureSampleLog, createGroupGesture api exist"); + } else { + OH_LOG_Print(LOG_APP, LOG_INFO, LOG_PRINT_DOMAIN, "[Sample_NdkAddInteractionEvent]", + "NdkAddInteractionEvent_GestureSampleLog, createGroupGesture api not exist"); + } + auto groupGesture = gestureApi->createGroupGesture(ArkUI_GroupGestureMode::EXCLUSIVE_GROUP); + + // 创建滑动手势 + auto panGesture = gestureApi->createPanGesture(GINGERS_NUM, GESTURE_DIRECTION_VERTICAL, DURATION_NUM); + if (gestureApi->getGestureType) { + ArkUI_GestureRecognizerType type = gestureApi->getGestureType(panGesture); + OH_LOG_Print(LOG_APP, LOG_INFO, LOG_PRINT_DOMAIN, "[Sample_NdkAddInteractionEvent]", + "NdkAddInteractionEvent_GestureSampleLog panGesture, ArkUI_GestureRecognizerType %{public}d", + type); + } + // 给滑动手势绑定回调 + auto onActionCallBackPan = [](ArkUI_GestureEvent *event, void *extraParam) { + ArkUI_GestureEventActionType actionType = OH_ArkUI_GestureEvent_GetActionType(event); + + float velocity = OH_ArkUI_PanGesture_GetVelocity(event); + float velocityX = OH_ArkUI_PanGesture_GetVelocityX(event); + float velocityY = OH_ArkUI_PanGesture_GetVelocityY(event); + float offsetX = OH_ArkUI_PanGesture_GetOffsetX(event); + float offsetY = OH_ArkUI_PanGesture_GetOffsetY(event); + float scale = OH_ArkUI_PinchGesture_GetScale(event); + float centerX = OH_ArkUI_PinchGesture_GetCenterX(event); + float centerY = OH_ArkUI_PinchGesture_GetCenterY(event); + float angle = OH_ArkUI_SwipeGesture_GetAngle(event); + float velocityS = OH_ArkUI_SwipeGesture_GetVelocity(event); + float angleR = OH_ArkUI_RotationGesture_GetAngle(event); + float repeat = OH_ArkUI_LongPress_GetRepeatCount(event); + + // 通过日志查看 + OH_LOG_Print( + LOG_APP, LOG_INFO, LOG_PRINT_DOMAIN, "[Sample_NdkAddInteractionEvent]", + "NdkAddInteractionEvent_GestureSampleLog, panGesture callback actionType: %{public}d, " + "velocity %{public}f,velocityX %{public}f; " + "velocityY %{public}f, offsetX %{public}f, offsetY %{public}f, scale %{public}fcenterX " + "%{public}f centerY" + " %{public}f angle %{public}f velocityS %{public}f angleR %{public}f repeat %{public}f", + actionType, velocity, velocityX, velocityY, offsetX, offsetY, scale, centerX, centerY, angle, velocityS, + angleR, repeat); + }; + gestureApi->setGestureEventTarget(panGesture, + GESTURE_EVENT_ACTION_ACCEPT | GESTURE_EVENT_ACTION_UPDATE | + GESTURE_EVENT_ACTION_END | GESTURE_EVENT_ACTION_CANCEL, + column, onActionCallBackPan); + // 将滑动手势添加到手势组 + if (gestureApi->addChildGesture) { + gestureApi->addChildGesture(groupGesture, panGesture); + OH_LOG_Print(LOG_APP, LOG_INFO, LOG_PRINT_DOMAIN, "[Sample_NdkAddInteractionEvent]", + "NdkAddInteractionEvent_GestureSampleLog, addChildGesture panGesture"); + } + // 创建捏合手势 + auto pinchGesture = gestureApi->createPinchGesture(0, 0); + if (gestureApi->getGestureType) { + ArkUI_GestureRecognizerType type = gestureApi->getGestureType(pinchGesture); + OH_LOG_Print(LOG_APP, LOG_INFO, LOG_PRINT_DOMAIN, "[Sample_NdkAddInteractionEvent]", + "NdkAddInteractionEvent_GestureSampleLog pinchGesture, " + "ArkUI_GestureRecognizerType %{public}d", type); + } + // 给捏合手势绑定回调 + auto onActionCallBack = [](ArkUI_GestureEvent *event, void *extraParam) { + ArkUI_GestureEventActionType actionType = OH_ArkUI_GestureEvent_GetActionType(event); + + float velocity = OH_ArkUI_PanGesture_GetVelocity(event); + float velocityX = OH_ArkUI_PanGesture_GetVelocityX(event); + float velocityY = OH_ArkUI_PanGesture_GetVelocityY(event); + float offsetX = OH_ArkUI_PanGesture_GetOffsetX(event); + float offsetY = OH_ArkUI_PanGesture_GetOffsetY(event); + float scale = OH_ArkUI_PinchGesture_GetScale(event); + float centerX = OH_ArkUI_PinchGesture_GetCenterX(event); + float centerY = OH_ArkUI_PinchGesture_GetCenterY(event); + float angle = OH_ArkUI_SwipeGesture_GetAngle(event); + float velocityS = OH_ArkUI_SwipeGesture_GetVelocity(event); + float angleR = OH_ArkUI_RotationGesture_GetAngle(event); + float repeat = OH_ArkUI_LongPress_GetRepeatCount(event); + + OH_LOG_Print( + LOG_APP, LOG_INFO, LOG_PRINT_DOMAIN, "[Sample_NdkAddInteractionEvent]", + "NdkAddInteractionEvent_GestureSampleLog, pinchGesture callback actionType: %{public}d, " + "velocity %{public}f,velocityX %{public}f; " + "velocityY %{public}f, offsetX %{public}f, offsetY %{public}f, scale %{public}fcenterX " + "%{public}f centerY" + " %{public}f angle %{public}f velocityS %{public}f angleR %{public}f repeat %{public}f", + actionType, velocity, velocityX, velocityY, offsetX, offsetY, scale, centerX, centerY, angle, velocityS, + angleR, repeat); + ArkUI_NumberValue value[] = {{.f32 = scale}, {.f32 = scale}}; + ArkUI_AttributeItem item = {value, ITEM_SIZE_TWO}; + auto column = reinterpret_cast(extraParam); + nodeAPI->setAttribute(column, NODE_SCALE, &item); + }; + gestureApi->setGestureEventTarget(pinchGesture, + GESTURE_EVENT_ACTION_ACCEPT | GESTURE_EVENT_ACTION_UPDATE | + GESTURE_EVENT_ACTION_END | GESTURE_EVENT_ACTION_CANCEL, + column, onActionCallBack); + // 将捏合手势添加到手势组 + if (gestureApi->addChildGesture) { + gestureApi->addChildGesture(groupGesture, pinchGesture); + OH_LOG_Print(LOG_APP, LOG_INFO, LOG_PRINT_DOMAIN, "[Sample_NdkAddInteractionEvent]", + "NdkAddInteractionEvent_GestureSampleLog, addChildGesture pinchGesture"); + } + // 将手势组设置到组件上 + gestureApi->addGestureToNode(column, groupGesture, PRIORITY, NORMAL_GESTURE_MASK); + return column; +} +// [End swipe_and_pinch_exclusive_gesture] +} // namespace NativeXComponentSample +#endif // SWIPE_AND_PINCH_EXCLUSIVE_GESTURE_H \ No newline at end of file diff --git a/ArkUIKit/NdkAddInteractionEvent/entry/src/main/cpp/napi_init.cpp b/ArkUIKit/NdkAddInteractionEvent/entry/src/main/cpp/napi_init.cpp new file mode 100644 index 0000000000000000000000000000000000000000..92ceebeac7c613b6c329a007ddaef2e58a98991c --- /dev/null +++ b/ArkUIKit/NdkAddInteractionEvent/entry/src/main/cpp/napi_init.cpp @@ -0,0 +1,52 @@ +/* + * 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. + */ + +// entry/src/main/cpp/napi_init.cpp +#include "napi/native_api.h" +#include "NativeEntry.h" + +EXTERN_C_START +static napi_value Init(napi_env env, napi_value exports) +{ + // 绑定Native侧的创建组件和销毁组件。 + napi_property_descriptor desc[] = { + {"createNativeRoot", nullptr, NativeModule::CreateNativeRoot, nullptr, nullptr, nullptr, napi_default, nullptr}, + {"createNativeNode", nullptr, NativeModule::CreateNativeNode, nullptr, nullptr, nullptr, napi_default, nullptr}, + {"createNativeNodeForGesture", nullptr, NativeModule::CreateNativeNodeForGesture, nullptr, nullptr, nullptr, + napi_default, nullptr}, + {"createNativeNodeForLongPressAndSwipe", nullptr, NativeModule::CreateNativeNodeForLongPressAndSwipe, nullptr, + nullptr, nullptr, napi_default, nullptr}, + {"createNativeNodeForLongPressAndFlick", nullptr, NativeModule::CreateNativeNodeForLongPressAndFlick, nullptr, + nullptr, nullptr, napi_default, nullptr}, + {"createNativeNodeForSwipeAndPinchExclusive", nullptr, NativeModule::CreateNativeNodeForSwipeAndPinchExclusive, + nullptr, nullptr, nullptr, napi_default, nullptr}, + {"destroyNativeRoot", nullptr, NativeModule::DestroyNativeRoot, nullptr, nullptr, nullptr, napi_default, + nullptr}}; + napi_define_properties(env, exports, sizeof(desc) / sizeof(desc[0]), desc); + return exports; +} +EXTERN_C_END + +static napi_module demoModule = { + .nm_version = 1, + .nm_flags = 0, + .nm_filename = nullptr, + .nm_register_func = Init, + .nm_modname = "entry", + .nm_priv = ((void *)0), + .reserved = {0}, +}; + +extern "C" __attribute__((constructor)) void RegisterEntryModule(void) { napi_module_register(&demoModule); } \ No newline at end of file diff --git a/ArkUIKit/NdkAddInteractionEvent/entry/src/main/cpp/types/libentry/Index.d.ts b/ArkUIKit/NdkAddInteractionEvent/entry/src/main/cpp/types/libentry/Index.d.ts new file mode 100644 index 0000000000000000000000000000000000000000..d6b9e63401c3112ee054a0e0f83321fd44ed6a35 --- /dev/null +++ b/ArkUIKit/NdkAddInteractionEvent/entry/src/main/cpp/types/libentry/Index.d.ts @@ -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. + */ + +// entry/src/main/cpp/types/libentry/Index.d.ts + +export const createNativeRoot: (content: Object) => void; +export const destroyNativeRoot: () => void; +export const createNativeNode: (content: Object) => void; +export const createNativeNodeForGesture: (content: Object) => void; +export const createNativeNodeForLongPressAndSwipe: (content: Object) => void; +export const createNativeNodeForLongPressAndFlick: (content: Object) => void; +export const createNativeNodeForSwipeAndPinchExclusive: (content: Object) => void; \ No newline at end of file diff --git a/ArkUIKit/NdkAddInteractionEvent/entry/src/main/cpp/types/libentry/oh-package.json5 b/ArkUIKit/NdkAddInteractionEvent/entry/src/main/cpp/types/libentry/oh-package.json5 new file mode 100644 index 0000000000000000000000000000000000000000..6abf3b7c20f22c62aaac6a995a25cae672f73f35 --- /dev/null +++ b/ArkUIKit/NdkAddInteractionEvent/entry/src/main/cpp/types/libentry/oh-package.json5 @@ -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. + */ + +{ + "name": "libentry.so", + "types": "./Index.d.ts", + "version": "1.0.0", + "description": "Please describe the basic information." +} \ No newline at end of file diff --git a/ArkUIKit/NdkAddInteractionEvent/entry/src/main/ets/entryability/EntryAbility.ets b/ArkUIKit/NdkAddInteractionEvent/entry/src/main/ets/entryability/EntryAbility.ets new file mode 100644 index 0000000000000000000000000000000000000000..62f53acbc95e5be7985f8fb1fe2db591cea260bd --- /dev/null +++ b/ArkUIKit/NdkAddInteractionEvent/entry/src/main/ets/entryability/EntryAbility.ets @@ -0,0 +1,63 @@ +/* + * 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 { window } from '@kit.ArkUI'; + +const DOMAIN = 0x0000; + +export default class EntryAbility extends UIAbility { + onCreate(want: Want, launchParam: AbilityConstant.LaunchParam): void { + try { + this.context.getApplicationContext().setColorMode(ConfigurationConstant.ColorMode.COLOR_MODE_NOT_SET); + } catch (err) { + hilog.error(DOMAIN, 'testTag', 'Failed to set colorMode. Cause: %{public}s', JSON.stringify(err)); + } + hilog.info(DOMAIN, 'testTag', '%{public}s', 'Ability onCreate'); + } + + onDestroy(): void { + hilog.info(DOMAIN, 'testTag', '%{public}s', 'Ability onDestroy'); + } + + onWindowStageCreate(windowStage: window.WindowStage): void { + // Main window is created, set main page for this ability + hilog.info(DOMAIN, 'testTag', '%{public}s', 'Ability onWindowStageCreate'); + + 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/NdkAddInteractionEvent/entry/src/main/ets/entrybackupability/EntryBackupAbility.ets b/ArkUIKit/NdkAddInteractionEvent/entry/src/main/ets/entrybackupability/EntryBackupAbility.ets new file mode 100644 index 0000000000000000000000000000000000000000..0a97e21bd7a15599af76a806695860ff1eb0ebfe --- /dev/null +++ b/ArkUIKit/NdkAddInteractionEvent/entry/src/main/ets/entrybackupability/EntryBackupAbility.ets @@ -0,0 +1,31 @@ +/* + * 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/NdkAddInteractionEvent/entry/src/main/ets/pages/BindGestureEvent.ets b/ArkUIKit/NdkAddInteractionEvent/entry/src/main/ets/pages/BindGestureEvent.ets new file mode 100644 index 0000000000000000000000000000000000000000..46c8677db7eaf7b9e512a48b01ba00fe76a9f7b8 --- /dev/null +++ b/ArkUIKit/NdkAddInteractionEvent/entry/src/main/ets/pages/BindGestureEvent.ets @@ -0,0 +1,38 @@ +/* + * 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 nativeNode from 'libentry.so'; +import { NodeContent } from '@kit.ArkUI'; + +@Entry +@Component +struct Index { + // 初始化NodeContent对象。 + private rootSlot = new NodeContent(); + + build() { + Column() { + Button('ShowNativeUI').onClick(() => { + nativeNode.createNativeNodeForGesture(this.rootSlot); + }) + Row() { + // 将NodeContent和ContentSlot占位组件绑定。 + ContentSlot(this.rootSlot); + }.layoutWeight(1) + } + .width('100%') + .height('100%') + } +} \ No newline at end of file diff --git a/ArkUIKit/NdkAddInteractionEvent/entry/src/main/ets/pages/ComponentListenEvent.ets b/ArkUIKit/NdkAddInteractionEvent/entry/src/main/ets/pages/ComponentListenEvent.ets new file mode 100644 index 0000000000000000000000000000000000000000..7fff48e717b2b30997d28e8798a9d926f2471e8e --- /dev/null +++ b/ArkUIKit/NdkAddInteractionEvent/entry/src/main/ets/pages/ComponentListenEvent.ets @@ -0,0 +1,38 @@ +/* + * 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 nativeNode from 'libentry.so'; +import { NodeContent } from '@kit.ArkUI'; + +@Entry +@Component +struct Index { + // 初始化NodeContent对象。 + private rootSlot = new NodeContent(); + + build() { + Column() { + Button('ShowNativeUI').onClick(() => { + nativeNode.createNativeNode(this.rootSlot); + }) + Row() { + // 将NodeContent和ContentSlot占位组件绑定。 + ContentSlot(this.rootSlot); + }.layoutWeight(1) + } + .width('100%') + .height('100%') + } +} \ No newline at end of file diff --git a/ArkUIKit/NdkAddInteractionEvent/entry/src/main/ets/pages/Index.ets b/ArkUIKit/NdkAddInteractionEvent/entry/src/main/ets/pages/Index.ets new file mode 100644 index 0000000000000000000000000000000000000000..fae9fd1cd02b6a1c694dad423da4fc9add24f74b --- /dev/null +++ b/ArkUIKit/NdkAddInteractionEvent/entry/src/main/ets/pages/Index.ets @@ -0,0 +1,60 @@ +/* + * 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. + */ + +interface Ary { + path:string, + name:string +} +@Entry +@Component +struct Index { + ary:Ary[]=[ + { + name:'NormalTextList', + path:'pages/NormalTextList' + }, + { + name:'ComponentListenEvent', + path:'pages/ComponentListenEvent' + }, + { + name:'BindGestureEvent', + path:'pages/BindGestureEvent' + }, + { + name:'LongPressAndSwipe', + path:'pages/LongPressAndSwipe' + }, + { + name:'LongPressAndFlick', + path:'pages/LongPressAndFlick' + }, + { + name:'SwipeAndPinchExclusive', + path:'pages/SwipeAndPinchExclusive' + }, + ]; + build() { + Scroll() { + Column({ space: 10 }) { + ForEach(this.ary,(item:Ary)=>{ + Button(item.name) + .onClick(() => this.getUIContext().getRouter().pushUrl({url:item.path})) + },(item:Ary)=>item.name) + } + .width(300) + } + } +} \ No newline at end of file diff --git a/ArkUIKit/NdkAddInteractionEvent/entry/src/main/ets/pages/LongPressAndFlick.ets b/ArkUIKit/NdkAddInteractionEvent/entry/src/main/ets/pages/LongPressAndFlick.ets new file mode 100644 index 0000000000000000000000000000000000000000..4b16de497f97c496dcfd68e829f1bdadd4d0f716 --- /dev/null +++ b/ArkUIKit/NdkAddInteractionEvent/entry/src/main/ets/pages/LongPressAndFlick.ets @@ -0,0 +1,38 @@ +/* + * 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 nativeNode from 'libentry.so'; +import { NodeContent } from '@kit.ArkUI'; + +@Entry +@Component +struct Index { + // 初始化NodeContent对象。 + private rootSlot = new NodeContent(); + + build() { + Column() { + Button('ShowNativeUI').onClick(() => { + nativeNode.createNativeNodeForLongPressAndFlick(this.rootSlot); + }) + Row() { + // 将NodeContent和ContentSlot占位组件绑定。 + ContentSlot(this.rootSlot); + }.layoutWeight(1) + } + .width('100%') + .height('100%') + } +} \ No newline at end of file diff --git a/ArkUIKit/NdkAddInteractionEvent/entry/src/main/ets/pages/LongPressAndSwipe.ets b/ArkUIKit/NdkAddInteractionEvent/entry/src/main/ets/pages/LongPressAndSwipe.ets new file mode 100644 index 0000000000000000000000000000000000000000..ce57a459236a9b9726c2bf08c23618c240ae97c4 --- /dev/null +++ b/ArkUIKit/NdkAddInteractionEvent/entry/src/main/ets/pages/LongPressAndSwipe.ets @@ -0,0 +1,38 @@ +/* + * 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 nativeNode from 'libentry.so'; +import { NodeContent } from '@kit.ArkUI'; + +@Entry +@Component +struct Index { + // 初始化NodeContent对象。 + private rootSlot = new NodeContent(); + + build() { + Column() { + Button('ShowNativeUI').onClick(() => { + nativeNode.createNativeNodeForLongPressAndSwipe(this.rootSlot); + }) + Row() { + // 将NodeContent和ContentSlot占位组件绑定。 + ContentSlot(this.rootSlot); + }.layoutWeight(1) + } + .width('100%') + .height('100%') + } +} \ No newline at end of file diff --git a/ArkUIKit/NdkAddInteractionEvent/entry/src/main/ets/pages/NormalTextList.ets b/ArkUIKit/NdkAddInteractionEvent/entry/src/main/ets/pages/NormalTextList.ets new file mode 100644 index 0000000000000000000000000000000000000000..aee11209419196a632646db002d9d9d93e04dd62 --- /dev/null +++ b/ArkUIKit/NdkAddInteractionEvent/entry/src/main/ets/pages/NormalTextList.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 nativeNode from 'libentry.so'; +import { NodeContent } from '@kit.ArkUI'; + +@Entry +@Component +struct Index { + // 初始化NodeContent对象。 + private rootSlot = new NodeContent(); + @State @Watch('changeNativeFlag') showNative: boolean = false; + + changeNativeFlag(): void { + if (this.showNative) { + // 传递NodeContent对象用于Native创建组件的挂载显示 + nativeNode.createNativeRoot(this.rootSlot); + } else { + // 销毁NativeModule组件 + nativeNode.destroyNativeRoot(); + } + } + + build() { + Column() { + Button(this.showNative ? 'HideNativeUI' : 'ShowNativeUI').onClick(() => { + this.showNative = !this.showNative; + }) + Row() { + // 将NodeContent和ContentSlot占位组件绑定。 + ContentSlot(this.rootSlot); + }.layoutWeight(1) + } + .width('100%') + .height('100%') + } +} \ No newline at end of file diff --git a/ArkUIKit/NdkAddInteractionEvent/entry/src/main/ets/pages/SwipeAndPinchExclusive.ets b/ArkUIKit/NdkAddInteractionEvent/entry/src/main/ets/pages/SwipeAndPinchExclusive.ets new file mode 100644 index 0000000000000000000000000000000000000000..6b40d087378aa89f3729f74a25a37ede945a32ba --- /dev/null +++ b/ArkUIKit/NdkAddInteractionEvent/entry/src/main/ets/pages/SwipeAndPinchExclusive.ets @@ -0,0 +1,38 @@ +/* + * 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 nativeNode from 'libentry.so'; +import { NodeContent } from '@kit.ArkUI'; + +@Entry +@Component +struct Index { + // 初始化NodeContent对象。 + private rootSlot = new NodeContent(); + + build() { + Column() { + Button('ShowNativeUI').onClick(() => { + nativeNode.createNativeNodeForSwipeAndPinchExclusive(this.rootSlot); + }) + Row() { + // 将NodeContent和ContentSlot占位组件绑定。 + ContentSlot(this.rootSlot); + }.layoutWeight(1) + } + .width('100%') + .height('100%') + } +} \ No newline at end of file diff --git a/ArkUIKit/NdkAddInteractionEvent/entry/src/main/module.json5 b/ArkUIKit/NdkAddInteractionEvent/entry/src/main/module.json5 new file mode 100644 index 0000000000000000000000000000000000000000..9d179325a9a4cfa7d090354c3954d3a73acca327 --- /dev/null +++ b/ArkUIKit/NdkAddInteractionEvent/entry/src/main/module.json5 @@ -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. + */ + +{ + "module": { + "name": "entry", + "type": "entry", + "description": "$string:module_desc", + "mainElement": "EntryAbility", + "deviceTypes": [ + "default", + "tablet" + ], + "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/NdkAddInteractionEvent/entry/src/main/resources/base/element/color.json b/ArkUIKit/NdkAddInteractionEvent/entry/src/main/resources/base/element/color.json new file mode 100644 index 0000000000000000000000000000000000000000..3c712962da3c2751c2b9ddb53559afcbd2b54a02 --- /dev/null +++ b/ArkUIKit/NdkAddInteractionEvent/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/NdkAddInteractionEvent/entry/src/main/resources/base/element/float.json b/ArkUIKit/NdkAddInteractionEvent/entry/src/main/resources/base/element/float.json new file mode 100644 index 0000000000000000000000000000000000000000..33ea22304f9b1485b5f22d811023701b5d4e35b6 --- /dev/null +++ b/ArkUIKit/NdkAddInteractionEvent/entry/src/main/resources/base/element/float.json @@ -0,0 +1,8 @@ +{ + "float": [ + { + "name": "page_text_font_size", + "value": "50fp" + } + ] +} diff --git a/ArkUIKit/NdkAddInteractionEvent/entry/src/main/resources/base/element/string.json b/ArkUIKit/NdkAddInteractionEvent/entry/src/main/resources/base/element/string.json new file mode 100644 index 0000000000000000000000000000000000000000..f94595515a99e0c828807e243494f57f09251930 --- /dev/null +++ b/ArkUIKit/NdkAddInteractionEvent/entry/src/main/resources/base/element/string.json @@ -0,0 +1,16 @@ +{ + "string": [ + { + "name": "module_desc", + "value": "module description" + }, + { + "name": "EntryAbility_desc", + "value": "description" + }, + { + "name": "EntryAbility_label", + "value": "label" + } + ] +} \ No newline at end of file diff --git a/ArkUIKit/NdkAddInteractionEvent/entry/src/main/resources/base/media/background.png b/ArkUIKit/NdkAddInteractionEvent/entry/src/main/resources/base/media/background.png new file mode 100644 index 0000000000000000000000000000000000000000..923f2b3f27e915d6871871deea0420eb45ce102f Binary files /dev/null and b/ArkUIKit/NdkAddInteractionEvent/entry/src/main/resources/base/media/background.png differ diff --git a/ArkUIKit/NdkAddInteractionEvent/entry/src/main/resources/base/media/foreground.png b/ArkUIKit/NdkAddInteractionEvent/entry/src/main/resources/base/media/foreground.png new file mode 100644 index 0000000000000000000000000000000000000000..97014d3e10e5ff511409c378cd4255713aecd85f Binary files /dev/null and b/ArkUIKit/NdkAddInteractionEvent/entry/src/main/resources/base/media/foreground.png differ diff --git a/ArkUIKit/NdkAddInteractionEvent/entry/src/main/resources/base/media/layered_image.json b/ArkUIKit/NdkAddInteractionEvent/entry/src/main/resources/base/media/layered_image.json new file mode 100644 index 0000000000000000000000000000000000000000..fb49920440fb4d246c82f9ada275e26123a2136a --- /dev/null +++ b/ArkUIKit/NdkAddInteractionEvent/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/NdkAddInteractionEvent/entry/src/main/resources/base/media/startIcon.png b/ArkUIKit/NdkAddInteractionEvent/entry/src/main/resources/base/media/startIcon.png new file mode 100644 index 0000000000000000000000000000000000000000..205ad8b5a8a42e8762fbe4899b8e5e31ce822b8b Binary files /dev/null and b/ArkUIKit/NdkAddInteractionEvent/entry/src/main/resources/base/media/startIcon.png differ diff --git a/ArkUIKit/NdkAddInteractionEvent/entry/src/main/resources/base/profile/backup_config.json b/ArkUIKit/NdkAddInteractionEvent/entry/src/main/resources/base/profile/backup_config.json new file mode 100644 index 0000000000000000000000000000000000000000..78f40ae7c494d71e2482278f359ec790ca73471a --- /dev/null +++ b/ArkUIKit/NdkAddInteractionEvent/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/NdkAddInteractionEvent/entry/src/main/resources/base/profile/main_pages.json b/ArkUIKit/NdkAddInteractionEvent/entry/src/main/resources/base/profile/main_pages.json new file mode 100644 index 0000000000000000000000000000000000000000..14c4e3edbcd7c6b2f4668a598d34929ed9b48167 --- /dev/null +++ b/ArkUIKit/NdkAddInteractionEvent/entry/src/main/resources/base/profile/main_pages.json @@ -0,0 +1,11 @@ +{ + "src": [ + "pages/NormalTextList", + "pages/ComponentListenEvent", + "pages/Index", + "pages/BindGestureEvent", + "pages/LongPressAndSwipe", + "pages/LongPressAndFlick", + "pages/SwipeAndPinchExclusive" + ] +} diff --git a/ArkUIKit/NdkAddInteractionEvent/entry/src/main/resources/dark/element/color.json b/ArkUIKit/NdkAddInteractionEvent/entry/src/main/resources/dark/element/color.json new file mode 100644 index 0000000000000000000000000000000000000000..79b11c2747aec33e710fd3a7b2b3c94dd9965499 --- /dev/null +++ b/ArkUIKit/NdkAddInteractionEvent/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/NdkAddInteractionEvent/entry/src/main/syscap.json b/ArkUIKit/NdkAddInteractionEvent/entry/src/main/syscap.json new file mode 100644 index 0000000000000000000000000000000000000000..ab50d1a5b1f72ec8788ea4c02956e86ef0837953 --- /dev/null +++ b/ArkUIKit/NdkAddInteractionEvent/entry/src/main/syscap.json @@ -0,0 +1,23 @@ + +{ + "devices": { + "general": [ + "default", + "tablet" + ] + }, + "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" + ] + } +} diff --git a/ArkUIKit/NdkAddInteractionEvent/entry/src/mock/Libentry.mock.ets b/ArkUIKit/NdkAddInteractionEvent/entry/src/mock/Libentry.mock.ets new file mode 100644 index 0000000000000000000000000000000000000000..eebf1ed910f6a8f2a9e7e565aa71b179b7b8b537 --- /dev/null +++ b/ArkUIKit/NdkAddInteractionEvent/entry/src/mock/Libentry.mock.ets @@ -0,0 +1,22 @@ +/* + * 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. + */ + +const NativeMock: Record = { + 'add': (a: number, b: number) => { + return a + b; + }, +}; + +export default NativeMock; \ No newline at end of file diff --git a/ArkUIKit/NdkAddInteractionEvent/entry/src/mock/mock-config.json5 b/ArkUIKit/NdkAddInteractionEvent/entry/src/mock/mock-config.json5 new file mode 100644 index 0000000000000000000000000000000000000000..2c7d2ba82b796a2850ced0a277d261d7d7355416 --- /dev/null +++ b/ArkUIKit/NdkAddInteractionEvent/entry/src/mock/mock-config.json5 @@ -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. + */ + +{ + "libentry.so": { + "source": "src/mock/Libentry.mock.ets" + } +} \ No newline at end of file diff --git a/ArkUIKit/NdkAddInteractionEvent/entry/src/ohosTest/ets/test/Ability.test.ets b/ArkUIKit/NdkAddInteractionEvent/entry/src/ohosTest/ets/test/Ability.test.ets new file mode 100644 index 0000000000000000000000000000000000000000..0f8ce9a2c012f8fe36114cef65216ef0b6254f41 --- /dev/null +++ b/ArkUIKit/NdkAddInteractionEvent/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/NdkAddInteractionEvent/entry/src/ohosTest/ets/test/Index.test.ets b/ArkUIKit/NdkAddInteractionEvent/entry/src/ohosTest/ets/test/Index.test.ets new file mode 100644 index 0000000000000000000000000000000000000000..5c2bc927a66e2ec8fd28c956869cd0dfeaaab544 --- /dev/null +++ b/ArkUIKit/NdkAddInteractionEvent/entry/src/ohosTest/ets/test/Index.test.ets @@ -0,0 +1,218 @@ +/* + * 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, it, expect, Level, Size, TestType } from '@ohos/hypium' +// 导入测试依赖kit +import { abilityDelegatorRegistry, Driver, ON, MouseButton, Component, MatchPattern } from '@kit.TestKit'; +import { UIAbility, Want } from '@kit.AbilityKit'; +import hilog from '@ohos.hilog'; + +const delegator: abilityDelegatorRegistry.AbilityDelegator = abilityDelegatorRegistry.getAbilityDelegator(); +const bundleName = abilityDelegatorRegistry.getArguments().bundleName; +let abilityDelegator: abilityDelegatorRegistry.AbilityDelegator; +abilityDelegator = abilityDelegatorRegistry.getAbilityDelegator(); +let want: Want; + +const TAG = '[Sample_NdkAddInteractionEvent]'; +const DOMAIN = 0xF811; +const BUNDLE = 'NdkAddInteractionEvent_'; +const ONE_SECONDS_TIME = 1000; + +function sleep(time: number) { + return new Promise((resolve: Function) => setTimeout(resolve, time)); +} + +export default function IndexTest() { + + describe('IndexTest', () => { + + beforeAll(async () => { + }) + + /** + * @tc.number: NormalTextListTest_001 + * @tc.name: Normal text list + * @tc.desc: Test normal text list + * @tc.size: MediumTest + * @tc.type: Function + * @tc.level Level 1 + */ + it('NormalTextListTest_001', TestType.FUNCTION | Size.MEDIUMTEST | Level.LEVEL1, async (done: Function) => { + hilog.info(DOMAIN, TAG, BUNDLE + 'NormalTextListTest_001, begin'); + want = { + bundleName: bundleName, + abilityName: 'EntryAbility' + }; + await delegator.startAbility(want); + await sleep(ONE_SECONDS_TIME); + let driver = Driver.create(); + let button_root = await driver.findComponent(ON.text('NormalTextList', MatchPattern.CONTAINS)); + await button_root.click(); + let button_list = await driver.findComponent(ON.text('ShowNativeUI', MatchPattern.CONTAINS)); + expect(button_list === null).assertFalse(); + await button_list.click(); + await driver.pressBack(); + await driver.pressBack(); + await driver.delayMs(ONE_SECONDS_TIME); + hilog.info(DOMAIN, TAG, BUNDLE + 'NormalTextListTest_001, end'); + done(); + }) + + /** + * @tc.number: BindGestureEventTest_001 + * @tc.name: Bind gesture event + * @tc.desc: Test bind gesture event + * @tc.size: MediumTest + * @tc.type: Function + * @tc.level Level 1 + */ + it('BindGestureEventTest_001', TestType.FUNCTION | Size.MEDIUMTEST | Level.LEVEL1, async (done: Function) => { + hilog.info(DOMAIN, TAG, BUNDLE + 'BindGestureEventTest_001, begin'); + want = { + bundleName: bundleName, + abilityName: 'EntryAbility' + }; + await delegator.startAbility(want); + await sleep(ONE_SECONDS_TIME); + let driver = Driver.create(); + let button_root = await driver.findComponent(ON.text('BindGestureEvent', MatchPattern.CONTAINS)); + await button_root.click(); + let button_list = await driver.findComponent(ON.text('ShowNativeUI', MatchPattern.CONTAINS)); + expect(button_list === null).assertFalse(); + await button_list.click(); + await driver.pressBack(); + await driver.pressBack(); + await driver.delayMs(ONE_SECONDS_TIME); + hilog.info(DOMAIN, TAG, BUNDLE + 'BindGestureEventTest_001, end'); + done(); + }) + + /** + * @tc.number: ComponentListenEventTest_001 + * @tc.name: Component listen event + * @tc.desc: Test component listen event + * @tc.size: MediumTest + * @tc.type: Function + * @tc.level Level 1 + */ + it('ComponentListenEventTest_001', TestType.FUNCTION | Size.MEDIUMTEST | Level.LEVEL1, async (done: Function) => { + hilog.info(DOMAIN, TAG, BUNDLE + 'ComponentListenEventTest_001, begin'); + want = { + bundleName: bundleName, + abilityName: 'EntryAbility' + }; + await delegator.startAbility(want); + await sleep(ONE_SECONDS_TIME); + let driver = Driver.create(); + let button_root = await driver.findComponent(ON.text('ComponentListenEvent', MatchPattern.CONTAINS)); + await button_root.click(); + let button_list = await driver.findComponent(ON.text('ShowNativeUI', MatchPattern.CONTAINS)); + expect(button_list === null).assertFalse(); + await button_list.click(); + await driver.pressBack(); + await driver.pressBack(); + await driver.delayMs(ONE_SECONDS_TIME); + hilog.info(DOMAIN, TAG, BUNDLE + 'ComponentListenEventTest_001, end'); + done(); + }) + + /** + * @tc.number: LongPressAndFlickTest_001 + * @tc.name: Long pressAnd flick + * @tc.desc: Test long pressAnd flick + * @tc.size: MediumTest + * @tc.type: Function + * @tc.level Level 1 + */ + it('LongPressAndFlickTest_001', TestType.FUNCTION | Size.MEDIUMTEST | Level.LEVEL1, async (done: Function) => { + hilog.info(DOMAIN, TAG, BUNDLE + 'LongPressAndFlickTest_001, begin'); + want = { + bundleName: bundleName, + abilityName: 'EntryAbility' + }; + await delegator.startAbility(want); + await sleep(ONE_SECONDS_TIME); + let driver = Driver.create(); + let button_root = await driver.findComponent(ON.text('LongPressAndFlick', MatchPattern.CONTAINS)); + await button_root.click(); + let button_list = await driver.findComponent(ON.text('ShowNativeUI', MatchPattern.CONTAINS)); + expect(button_list === null).assertFalse(); + await button_list.click(); + await driver.pressBack(); + await driver.pressBack(); + await driver.delayMs(ONE_SECONDS_TIME); + hilog.info(DOMAIN, TAG, BUNDLE + 'LongPressAndFlickTest_001, end'); + done(); + }) + + /** + * @tc.number: LongPressAndSwipeTest_001 + * @tc.name: Long press and swipe + * @tc.desc: Test long press and swipe + * @tc.size: MediumTest + * @tc.type: Function + * @tc.level Level 1 + */ + it('LongPressAndSwipeTest_001', TestType.FUNCTION | Size.MEDIUMTEST | Level.LEVEL1, async (done: Function) => { + hilog.info(DOMAIN, TAG, BUNDLE + 'LongPressAndSwipeTest_001, begin'); + want = { + bundleName: bundleName, + abilityName: 'EntryAbility' + }; + await delegator.startAbility(want); + await sleep(ONE_SECONDS_TIME); + let driver = Driver.create(); + let button_root = await driver.findComponent(ON.text('LongPressAndSwipe', MatchPattern.CONTAINS)); + await button_root.click(); + let button_list = await driver.findComponent(ON.text('ShowNativeUI', MatchPattern.CONTAINS)); + expect(button_list === null).assertFalse(); + await button_list.click(); + await driver.pressBack(); + await driver.pressBack(); + await driver.delayMs(ONE_SECONDS_TIME); + hilog.info(DOMAIN, TAG, BUNDLE + 'LongPressAndSwipeTest_001, end'); + done(); + }) + + /** + * @tc.number: SwipeAndPinchExclusiveTest_001 + * @tc.name: Swipe and pinch exclusive + * @tc.desc: Test swipe and pinch exclusive + * @tc.size: MediumTest + * @tc.type: Function + * @tc.level Level 1 + */ + it('SwipeAndPinchExclusiveTest_001', TestType.FUNCTION | Size.MEDIUMTEST | Level.LEVEL1, async (done: Function) => { + hilog.info(DOMAIN, TAG, BUNDLE + 'SwipeAndPinchExclusiveTest_001, begin'); + want = { + bundleName: bundleName, + abilityName: 'EntryAbility' + }; + await delegator.startAbility(want); + await sleep(ONE_SECONDS_TIME); + let driver = Driver.create(); + let button_root = await driver.findComponent(ON.text('SwipeAndPinchExclusive', MatchPattern.CONTAINS)); + await button_root.click(); + let button_list = await driver.findComponent(ON.text('ShowNativeUI', MatchPattern.CONTAINS)); + expect(button_list === null).assertFalse(); + await button_list.click(); + await driver.pressBack(); + await driver.pressBack(); + await driver.delayMs(ONE_SECONDS_TIME); + hilog.info(DOMAIN, TAG, BUNDLE + 'SwipeAndPinchExclusiveTest_001, end'); + done(); + }) + }) +} \ No newline at end of file diff --git a/ArkUIKit/NdkAddInteractionEvent/entry/src/ohosTest/ets/test/List.test.ets b/ArkUIKit/NdkAddInteractionEvent/entry/src/ohosTest/ets/test/List.test.ets new file mode 100644 index 0000000000000000000000000000000000000000..a1951e50c73703b8b1fe39390c5287b68a1bf394 --- /dev/null +++ b/ArkUIKit/NdkAddInteractionEvent/entry/src/ohosTest/ets/test/List.test.ets @@ -0,0 +1,22 @@ +/* + * 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 abilityTest from './Ability.test'; +import IndexTest from './Index.test'; + +export default function testsuite() { + abilityTest(); + IndexTest(); +} \ No newline at end of file diff --git a/ArkUIKit/NdkAddInteractionEvent/entry/src/ohosTest/module.json5 b/ArkUIKit/NdkAddInteractionEvent/entry/src/ohosTest/module.json5 new file mode 100644 index 0000000000000000000000000000000000000000..84d30586d591412f4252801cc483bbc6d8554104 --- /dev/null +++ b/ArkUIKit/NdkAddInteractionEvent/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/NdkAddInteractionEvent/entry/src/test/List.test.ets b/ArkUIKit/NdkAddInteractionEvent/entry/src/test/List.test.ets new file mode 100644 index 0000000000000000000000000000000000000000..f1186b1f53c3a70930921c5dbd1417332bec56c9 --- /dev/null +++ b/ArkUIKit/NdkAddInteractionEvent/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/NdkAddInteractionEvent/entry/src/test/LocalUnit.test.ets b/ArkUIKit/NdkAddInteractionEvent/entry/src/test/LocalUnit.test.ets new file mode 100644 index 0000000000000000000000000000000000000000..7fc57c77dbf76d8df08a2b802a55b948e3fcf968 --- /dev/null +++ b/ArkUIKit/NdkAddInteractionEvent/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/NdkAddInteractionEvent/hvigor/hvigor-config.json5 b/ArkUIKit/NdkAddInteractionEvent/hvigor/hvigor-config.json5 new file mode 100644 index 0000000000000000000000000000000000000000..b8fea3f097bd68b0bc4d87de986d2cb7732c1d9b --- /dev/null +++ b/ArkUIKit/NdkAddInteractionEvent/hvigor/hvigor-config.json5 @@ -0,0 +1,38 @@ +/* + * 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/NdkAddInteractionEvent/hvigorfile.ts b/ArkUIKit/NdkAddInteractionEvent/hvigorfile.ts new file mode 100644 index 0000000000000000000000000000000000000000..e3340f07e45ddc5dcadbb87012668555def2e6e0 --- /dev/null +++ b/ArkUIKit/NdkAddInteractionEvent/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/NdkAddInteractionEvent/oh-package.json5 b/ArkUIKit/NdkAddInteractionEvent/oh-package.json5 new file mode 100644 index 0000000000000000000000000000000000000000..69cb43cba3addcee1840403c67405134a2a9102c --- /dev/null +++ b/ArkUIKit/NdkAddInteractionEvent/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/NdkAddInteractionEvent/ohosTest.md b/ArkUIKit/NdkAddInteractionEvent/ohosTest.md new file mode 100644 index 0000000000000000000000000000000000000000..7ddabaf17e2450cdc2444d9a3544735784018264 --- /dev/null +++ b/ArkUIKit/NdkAddInteractionEvent/ohosTest.md @@ -0,0 +1,10 @@ +| 测试功能 | 预置条件 | 输入 | 预期输出 | 测试结果 | +|-----------------------------------| ------------ | ---------------------- |-----------| -------- | +| 首页加载测试 | 设备正常运行 | 验证基础元素渲染 | 检查标题和列表组件 | Pass | +| 给点击添加相关事件测试 | 设备正常运行 | 点击"NormalTextList",再点击"ShowNativeUI",点击输出对应坐标相关日志 | 页面加载成功,输出对应日志 | Pass | +| 自定义手势判定回调测试 | 设备正常运行 | 点击"BindGestureEvent",再点击"ShowNativeUI",点击屏幕相关日志 | 页面加载成功,点击事件无效 | Pass | +| 按钮点击监听事件测试 | 设备正常运行 | 点击"ComponentListenEvent",再点击"ShowNativeUI",点击"test" | 页面加载成功,输出对应日志 | Pass | +| 顺序识别长按和滑动手势测试 | 设备正常运行 | 点击"LongPressAndSwipe",再点击"ShowNativeUI", | 页面加载成功,长按,输出对应日志 | Pass | +| 并行识别长按和快滑手势测试 | 设备正常运行 | 点击"LongPressAndFlick",再点击"ShowNativeUI", | 页面加载成功,长按,输出对应日志 | Pass | +| 互斥识别滑动手势和捏合手势 | 设备正常运行 | 点击"LongPressAndFlick",再点击"ShowNativeUI", | 页面加载成功,捏合,输出对应日志 | Pass | + diff --git a/ArkUIKit/NdkAddInteractionEvent/screenshots/pic1.jpg b/ArkUIKit/NdkAddInteractionEvent/screenshots/pic1.jpg new file mode 100644 index 0000000000000000000000000000000000000000..2ecca99ed5c21302bbba2e17225231f792fc00e4 Binary files /dev/null and b/ArkUIKit/NdkAddInteractionEvent/screenshots/pic1.jpg differ diff --git a/ArkUIKit/NdkAddInteractionEvent/screenshots/pic2.jpg b/ArkUIKit/NdkAddInteractionEvent/screenshots/pic2.jpg new file mode 100644 index 0000000000000000000000000000000000000000..fb9566f72d974ea10a8e6e020d37a5c81e55384a Binary files /dev/null and b/ArkUIKit/NdkAddInteractionEvent/screenshots/pic2.jpg differ diff --git a/ArkUIKit/NdkAddInteractionEvent/screenshots/pic3.jpg b/ArkUIKit/NdkAddInteractionEvent/screenshots/pic3.jpg new file mode 100644 index 0000000000000000000000000000000000000000..b7277195f3c71cc3ca53552882c7c1ca27b4d2ac Binary files /dev/null and b/ArkUIKit/NdkAddInteractionEvent/screenshots/pic3.jpg differ diff --git a/ArkUIKit/NdkAddInteractionEvent/screenshots/pic4.jpg b/ArkUIKit/NdkAddInteractionEvent/screenshots/pic4.jpg new file mode 100644 index 0000000000000000000000000000000000000000..68fc970a3d49eb776f2512f9241cb23f0421234e Binary files /dev/null and b/ArkUIKit/NdkAddInteractionEvent/screenshots/pic4.jpg differ diff --git a/ArkUIKit/NdkAddInteractionEvent/screenshots/pic5.jpg b/ArkUIKit/NdkAddInteractionEvent/screenshots/pic5.jpg new file mode 100644 index 0000000000000000000000000000000000000000..68fc970a3d49eb776f2512f9241cb23f0421234e Binary files /dev/null and b/ArkUIKit/NdkAddInteractionEvent/screenshots/pic5.jpg differ diff --git a/ArkUIKit/NdkAddInteractionEvent/screenshots/pic6.jpg b/ArkUIKit/NdkAddInteractionEvent/screenshots/pic6.jpg new file mode 100644 index 0000000000000000000000000000000000000000..68fc970a3d49eb776f2512f9241cb23f0421234e Binary files /dev/null and b/ArkUIKit/NdkAddInteractionEvent/screenshots/pic6.jpg differ