diff --git a/ArkUISample/ChooseComponent/.gitignore b/ArkUISample/ChooseComponent/.gitignore new file mode 100644 index 0000000000000000000000000000000000000000..d2ff20141ceed86d87c0ea5d99481973005bab2b --- /dev/null +++ b/ArkUISample/ChooseComponent/.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/ArkUISample/ChooseComponent/AppScope/app.json5 b/ArkUISample/ChooseComponent/AppScope/app.json5 new file mode 100644 index 0000000000000000000000000000000000000000..e84cdde0e36906f043d70e137c07985212f52f21 --- /dev/null +++ b/ArkUISample/ChooseComponent/AppScope/app.json5 @@ -0,0 +1,25 @@ +/* + * Copyright (c) 2024 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +{ + "app": { + "bundleName": "com.samples.choosecomponent", + "vendor": "example", + "versionCode": 1000000, + "versionName": "1.0.0", + "icon": "$media:app_icon", + "label": "$string:app_name" + } +} diff --git a/ArkUISample/ChooseComponent/AppScope/resources/base/element/string.json b/ArkUISample/ChooseComponent/AppScope/resources/base/element/string.json new file mode 100644 index 0000000000000000000000000000000000000000..8e5e7e57b323d96b2769a0899a6105aae260470b --- /dev/null +++ b/ArkUISample/ChooseComponent/AppScope/resources/base/element/string.json @@ -0,0 +1,8 @@ +{ + "string": [ + { + "name": "app_name", + "value": "ChooseComponent" + } + ] +} diff --git a/ArkUISample/ChooseComponent/AppScope/resources/base/media/app_icon.png b/ArkUISample/ChooseComponent/AppScope/resources/base/media/app_icon.png new file mode 100644 index 0000000000000000000000000000000000000000..a39445dc87828b76fed6d2ec470dd455c45319e3 Binary files /dev/null and b/ArkUISample/ChooseComponent/AppScope/resources/base/media/app_icon.png differ diff --git a/ArkUISample/ChooseComponent/README_zh.md b/ArkUISample/ChooseComponent/README_zh.md new file mode 100644 index 0000000000000000000000000000000000000000..1b106d09ec7c76a575721f67aab47a1c23374fcc --- /dev/null +++ b/ArkUISample/ChooseComponent/README_zh.md @@ -0,0 +1,81 @@ +# ArkUI指南文档示例 + +### 介绍 + +本示例通过使用[ArkUI指南文档](https://gitee.com/openharmony/docs/tree/master/zh-cn/application-dev/ui)中各场景的开发示例,展示在工程中,帮助开发者更好地理解ArkUI提供的组件及组件属性并合理使用。该工程中展示的代码详细描述可查如下链接: + +1. [按钮 (Button)开发指导](https://gitee.com/openharmony/docs/blob/master/zh-cn/application-dev/ui/arkts-common-components-button.md)。 +2. [单选框 (Radio)开发指导](https://gitee.com/openharmony/docs/blob/master/zh-cn/application-dev/ui/arkts-common-components-radio-button.md)。 +3. [切换按钮 (Toggle)开发指导](https://gitee.com/openharmony/docs/blob/master/zh-cn/application-dev/ui/arkts-common-components-switch.md)。 +### 效果预览 + +| 首页 | 按钮组件目录 | 创建按钮场景示例 | +|------------------------------------|------------------------------------|------------------------------------| +| ![](screenshots/device/image1.png) | ![](screenshots/device/image2.png) | ![](screenshots/device/image3.png) | + +### 使用说明 + +1. 在主界面,可以点击对应卡片,选择需要参考的组件示例。 + +2. 在组件目录选择详细的示例参考。 + +3. 进入示例界面,查看参考示例。 + +4. 通过自动测试框架可进行测试及维护。 + +### 工程目录 +``` +entry/src/main/ets/ +|---entryability +|---pages +| |---button +| | |---CreateButton.ets // 按钮创建示例代码 +| | |---ButtonCustomStyle.ets // 按钮自定义示例代码 +| | |---FloatingButton.ets // 按钮悬浮场景示例代码 +| | |---Index.ets // 第二层级目录 +| | |---SetButtonType.ets // 按钮类型设置示例代码 +| | |---SubmitForm.ets // 按钮注册场景示例代码 +| |---radio +| | |---RadioSample.ets // 单选框场景示例代码 +| | |---Index.ets // 第二层级目录 +| |---toggle +| | |---CreateToggle.ets // 切换按钮创建示例代码 +| | |---ToggleCustomStyle.ets // 切换按钮自定义示例代码 +| | |---ToggleCaseExample.ets // 切换按钮场景示例代码 +| | |---Index.ets // 第二层级目录 +|---pages +| |---Index.ets // 应用主页面 +entry/src/ohosTest/ +|---ets +| |---index.test.ets // 示例代码测试代码 +``` + +### 相关权限 + +不涉及。 + +### 依赖 + +不涉及。 + +### 约束与限制 + +1. 本示例仅支持标准系统上运行,支持设备:华为手机。 + +2. HarmonyOS系统:HarmonyOS 5.1.0 Release及以上。 + +3. DevEco Studio版本:DevEco Studio 5.1.0 Release及以上。 + +4. HarmonyOS SDK版本:HarmonyOS 5.1.0 Release及以上。 + +### 下载 + +如需单独下载本工程,执行如下命令: + +```` +git init +git config core.sparsecheckout true +echo ArkUISample/ChooseComponent > .git/info/sparse-checkout +git remote add origin https://gitee.com/harmonyos_samples/guide-snippets.git +git pull origin master +```` \ No newline at end of file diff --git a/ArkUISample/ChooseComponent/build-profile.json5 b/ArkUISample/ChooseComponent/build-profile.json5 new file mode 100644 index 0000000000000000000000000000000000000000..49fcc67881e91d17cffc643580dc683464cef904 --- /dev/null +++ b/ArkUISample/ChooseComponent/build-profile.json5 @@ -0,0 +1,58 @@ +/* + * Copyright (c) 2024 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +{ + "app": { + "signingConfigs": [ + ], + "products": [ + { + "name": "default", + "signingConfig": "default", + "compatibleSdkVersion": "5.1.0(18)", + "targetSdkVersion": "5.1.0(18)", + "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/ArkUISample/ChooseComponent/code-linter.json5 b/ArkUISample/ChooseComponent/code-linter.json5 new file mode 100644 index 0000000000000000000000000000000000000000..eff2dbc9b8a447e5a99b0aab08ca2b766d786bf6 --- /dev/null +++ b/ArkUISample/ChooseComponent/code-linter.json5 @@ -0,0 +1,35 @@ +/* + * Copyright (c) 2024 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +{ + "files": [ + "**/*.ets" + ], + "ignore": [ + "**/src/ohosTest/**/*", + "**/src/test/**/*", + "**/src/mock/**/*", + "**/node_modules/**/*", + "**/oh_modules/**/*", + "**/build/**/*", + "**/.preview/**/*" + ], + "ruleSet": [ + "plugin:@performance/recommended", + "plugin:@typescript-eslint/recommended" + ], + "rules": { + } +} \ No newline at end of file diff --git a/ArkUISample/ChooseComponent/entry/.gitignore b/ArkUISample/ChooseComponent/entry/.gitignore new file mode 100644 index 0000000000000000000000000000000000000000..e2713a2779c5a3e0eb879efe6115455592caeea5 --- /dev/null +++ b/ArkUISample/ChooseComponent/entry/.gitignore @@ -0,0 +1,6 @@ +/node_modules +/oh_modules +/.preview +/build +/.cxx +/.test \ No newline at end of file diff --git a/ArkUISample/ChooseComponent/entry/build-profile.json5 b/ArkUISample/ChooseComponent/entry/build-profile.json5 new file mode 100644 index 0000000000000000000000000000000000000000..31bf2f4c4df15f0403582b255ebdff1354312357 --- /dev/null +++ b/ArkUISample/ChooseComponent/entry/build-profile.json5 @@ -0,0 +1,43 @@ +/* + * Copyright (c) 2024 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +{ + "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/ArkUISample/ChooseComponent/entry/hvigorfile.ts b/ArkUISample/ChooseComponent/entry/hvigorfile.ts new file mode 100644 index 0000000000000000000000000000000000000000..ac00aaeaf45982325e06e5a576ed7c336bbdb351 --- /dev/null +++ b/ArkUISample/ChooseComponent/entry/hvigorfile.ts @@ -0,0 +1,21 @@ +/* + * Copyright (c) 2024 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { 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/ArkUISample/ChooseComponent/entry/obfuscation-rules.txt b/ArkUISample/ChooseComponent/entry/obfuscation-rules.txt new file mode 100644 index 0000000000000000000000000000000000000000..272efb6ca3f240859091bbbfc7c5802d52793b0b --- /dev/null +++ b/ArkUISample/ChooseComponent/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/ArkUISample/ChooseComponent/entry/oh-package.json5 b/ArkUISample/ChooseComponent/entry/oh-package.json5 new file mode 100644 index 0000000000000000000000000000000000000000..4e54d14e1b444a338b2c922f94a4fe4deed5be45 --- /dev/null +++ b/ArkUISample/ChooseComponent/entry/oh-package.json5 @@ -0,0 +1,25 @@ +/* + * Copyright (c) 2024 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +{ + "name": "entry", + "version": "1.0.0", + "description": "Please describe the basic information.", + "main": "", + "author": "", + "license": "", + "dependencies": {} +} + diff --git a/ArkUISample/ChooseComponent/entry/src/main/ets/common/Card.ets b/ArkUISample/ChooseComponent/entry/src/main/ets/common/Card.ets new file mode 100644 index 0000000000000000000000000000000000000000..a9ce32e1f5851798d76f86f8dff6aa2554daa6ed --- /dev/null +++ b/ArkUISample/ChooseComponent/entry/src/main/ets/common/Card.ets @@ -0,0 +1,137 @@ +/* + * Copyright (c) 2024 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +@Component +export struct CompletedRoutableCard { + @Prop + symbol: Resource = $r('sys.symbol.label'); + @Prop + @Require + title: string; + @Prop + @Require + description: ResourceStr; + + build() { + Card({ verticalAlign: VerticalAlign.Top }) { + Button({ type: ButtonType.Circle }) { + SymbolGlyph(this.symbol) + .fontColor(['#fff']) + .fontSize(16) + } + .borderRadius(14) + + Column({ space: 8 }) { + Text(this.title) + .fontColor($r('sys.color.font_primary')) + + Text(this.description) + .fontColor($r('sys.color.font_secondary')) + .fontSize($r('sys.float.Body_S')) + } + .alignItems(HorizontalAlign.Start) + .layoutWeight(1) + } + } +} + +@Component +export struct Card { + @Prop + verticalAlign: VerticalAlign = VerticalAlign.Center; + @BuilderParam + content: () => void; + + build() { + Row({ space: 12 }) { + this.content() + } + .alignItems(this.verticalAlign) + .backgroundColor('#fff') + .borderRadius(12) + .padding(12) + .width('100%') + } +} + +@Component +export struct RoutableCard { + @Prop + icon: Resource = $r('sys.symbol.label'); + @Prop + @Require + title: ResourceStr; + + build() { + Card() { + Button({ type: ButtonType.Circle }) { + SymbolGlyph(this.icon) + .fontColor(['#fff']) + .fontSize(16) + } + .borderRadius(14) + + Text(this.title) + .fontColor($r('sys.color.font_primary')) + .minFontSize(12) + .maxFontSize(16) + .maxLines(1) + .textOverflow({ overflow: TextOverflow.Ellipsis }) + + Blank() + + Button({ type: ButtonType.Normal, buttonStyle: ButtonStyleMode.TEXTUAL }) { + SymbolGlyph($r('sys.symbol.chevron_right')) + .fontSize(18) + .fontColor([$r('sys.color.font_secondary')]) + } + } + } +} + +@Component +export struct ComponentCard { + @Prop + @Require + title: ResourceStr; + @BuilderParam content: () => void; + @Prop + description?: ResourceStr; + + build() { + Column({ space: 8 }) { + Text(this.title) + .fontSize(14) + .fontColor('#666') + Row({ space: 12}) { + this.content(); + } + if (this.description) { + Text(this.description) + .backgroundColor('#eee') + .borderRadius(4) + .padding(4) + .fontSize(12) + .fontColor('#999') + .width('100%') + } + } + .alignItems(HorizontalAlign.Start) + .backgroundColor('#fff') + .borderRadius(12) + .padding(12) + .width('100%') + } +} \ No newline at end of file diff --git a/ArkUISample/ChooseComponent/entry/src/main/ets/common/Route.ets b/ArkUISample/ChooseComponent/entry/src/main/ets/common/Route.ets new file mode 100644 index 0000000000000000000000000000000000000000..67f364e8705e18d5be514dcde5772cc44ffa2da3 --- /dev/null +++ b/ArkUISample/ChooseComponent/entry/src/main/ets/common/Route.ets @@ -0,0 +1,21 @@ +/* + * Copyright (c) 2024 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +export interface Route { + title: string ; + name: string; + items?: Route[]; + description?: ResourceStr; +} \ No newline at end of file diff --git a/ArkUISample/ChooseComponent/entry/src/main/ets/common/resource.ets b/ArkUISample/ChooseComponent/entry/src/main/ets/common/resource.ets new file mode 100644 index 0000000000000000000000000000000000000000..9d0cd43adf4ca62c85c7a22b883d2bb76a125d2f --- /dev/null +++ b/ArkUISample/ChooseComponent/entry/src/main/ets/common/resource.ets @@ -0,0 +1,25 @@ +/* + * Copyright (c) 2024 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +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/ArkUISample/ChooseComponent/entry/src/main/ets/entryability/EntryAbility.ets b/ArkUISample/ChooseComponent/entry/src/main/ets/entryability/EntryAbility.ets new file mode 100644 index 0000000000000000000000000000000000000000..51bdf85846c3b83c16542085365521bdc35baf50 --- /dev/null +++ b/ArkUISample/ChooseComponent/entry/src/main/ets/entryability/EntryAbility.ets @@ -0,0 +1,57 @@ +/* + * Copyright (c) 2024 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { AbilityConstant, ConfigurationConstant, UIAbility, Want } from '@kit.AbilityKit'; +import { hilog } from '@kit.PerformanceAnalysisKit'; +import { window } from '@kit.ArkUI'; + +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(0x0000, 'testTag', '%{public}s', 'Ability onCreate'); + } + + onDestroy(): void { + hilog.info(0x0000, 'testTag', '%{public}s', 'Ability onDestroy'); + } + + onWindowStageCreate(windowStage: window.WindowStage): void { + // Main window is created, set main page for this ability + hilog.info(0x0000, 'testTag', '%{public}s', 'Ability onWindowStageCreate'); + + windowStage.loadContent('pages/Index', (err) => { + if (err.code) { + hilog.error(0x0000, 'testTag', 'Failed to load the content. Cause: %{public}s', JSON.stringify(err) ?? ''); + return; + } + hilog.info(0x0000, 'testTag', 'Succeeded in loading the content.'); + }); + } + + onWindowStageDestroy(): void { + // Main window is destroyed, release UI related resources + hilog.info(0x0000, 'testTag', '%{public}s', 'Ability onWindowStageDestroy'); + } + + onForeground(): void { + // Ability has brought to foreground + hilog.info(0x0000, 'testTag', '%{public}s', 'Ability onForeground'); + } + + onBackground(): void { + // Ability has back to background + hilog.info(0x0000, 'testTag', '%{public}s', 'Ability onBackground'); + } +} \ No newline at end of file diff --git a/ArkUISample/ChooseComponent/entry/src/main/ets/entrybackupability/EntryBackupAbility.ets b/ArkUISample/ChooseComponent/entry/src/main/ets/entrybackupability/EntryBackupAbility.ets new file mode 100644 index 0000000000000000000000000000000000000000..6b744d7eaa66e51e79fc4e0896e251292ee767c5 --- /dev/null +++ b/ArkUISample/ChooseComponent/entry/src/main/ets/entrybackupability/EntryBackupAbility.ets @@ -0,0 +1,27 @@ +/* + * Copyright (c) 2024 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { hilog } from '@kit.PerformanceAnalysisKit'; +import { BackupExtensionAbility, BundleVersion } from '@kit.CoreFileKit'; + +export default class EntryBackupAbility extends BackupExtensionAbility { + async onBackup() { + hilog.info(0x0000, 'testTag', 'onBackup ok'); + } + + async onRestore(bundleVersion: BundleVersion) { + hilog.info(0x0000, 'testTag', 'onRestore ok %{public}s', JSON.stringify(bundleVersion)); + } +} \ No newline at end of file diff --git a/ArkUISample/ChooseComponent/entry/src/main/ets/pages/Index.ets b/ArkUISample/ChooseComponent/entry/src/main/ets/pages/Index.ets new file mode 100644 index 0000000000000000000000000000000000000000..d2728aad7b666b4b861f7f78797991ca46c7385b --- /dev/null +++ b/ArkUISample/ChooseComponent/entry/src/main/ets/pages/Index.ets @@ -0,0 +1,103 @@ +/* + * Copyright (c) 2024 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { BUTTON_ROUTE_PREFIX, buttonDestination } from './button/Index'; +import { LengthMetrics } from '@kit.ArkUI'; +import { radioDestination, RADIO_ROUTE_PREFIX } from './radio/Index'; +import { RoutableCard } from '../common/Card'; +import { Route } from '../common/Route'; +import { toggleDestination, TOGGLE_ROUTE_PREFIX } from './toggle/Index'; +import resource from '../common/resource'; + +const routes: Route[] = [ + { + title: resource.resourceToString($r('app.string.button')), + name: BUTTON_ROUTE_PREFIX + }, + { + title: resource.resourceToString($r('app.string.radio')), + name: RADIO_ROUTE_PREFIX + }, + { + title: resource.resourceToString($r('app.string.toggle')), + name: TOGGLE_ROUTE_PREFIX + } +]; + +@Builder +function destination(name: string) { + if (name.startsWith(BUTTON_ROUTE_PREFIX)) { + buttonDestination(name); + } else if (name.startsWith(RADIO_ROUTE_PREFIX)) { + radioDestination(name); + } else if (name.startsWith(TOGGLE_ROUTE_PREFIX)) { + toggleDestination(name); + } +} + +@Entry +@Component +struct Index { + @State condition: string = ''; + @Provide pathStack: NavPathStack = new NavPathStack(); + + getFilteredRoutes(): Route[] { + if (!this.condition) { + return routes; + } + return routes.filter((route: Route) => { + return route.title.includes(this.condition); + }) + } + + @LocalBuilder + Title() { + Column() { + Search({ value: this.condition }) + .onChange(value => { + this.condition = value; + }) + .margin({ start: LengthMetrics.vp(16), end: LengthMetrics.vp(16) }) + } + .justifyContent(FlexAlign.Center) + .height('100%') + } + + build() { + Navigation(this.pathStack) { + List({ space: 12 }) { + ForEach(this.getFilteredRoutes(), (route: Route) => { + ListItem() { + RoutableCard({ title: route.title }) + } + .width('100%') + .onClick(() => { + this.pathStack.pushPath({ name: route.name }); + }) + }) + } + .padding({ start: LengthMetrics.vp(16), end: LengthMetrics.vp(16) }) + .contentStartOffset(56) + .height('100%') + .width('100%') + } + .backgroundColor('#f1f3f5') + .title({ builder: this.Title, height: 56 }, { + backgroundBlurStyle: BlurStyle.COMPONENT_THICK, + barStyle: BarStyle.STACK + }) + .navDestination(destination) + } +} \ No newline at end of file diff --git a/ArkUISample/ChooseComponent/entry/src/main/ets/pages/button/ButtonCustomStyle.ets b/ArkUISample/ChooseComponent/entry/src/main/ets/pages/button/ButtonCustomStyle.ets new file mode 100644 index 0000000000000000000000000000000000000000..dfbc79820732da7a70944289750bfd113e8b5222 --- /dev/null +++ b/ArkUISample/ChooseComponent/entry/src/main/ets/pages/button/ButtonCustomStyle.ets @@ -0,0 +1,71 @@ +/* + * Copyright (c) 2024 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { ComponentCard } from '../../common/Card'; + +@Entry +@Component +export struct ButtonCustomStyle { + pathStack: NavPathStack = new NavPathStack(); + + resourceToString(resource: Resource): string { + return getContext(this).resourceManager.getStringSync(resource); + } + + build() { + NavDestination() { + Column({ space: 12 }) { + ComponentCard({ + title: $r('app.string.ButtonCustomStyle_titleOne'), + description: $r('app.string.ButtonCustomStyle_descriptionOne') + }) { + // [Start custom_button_border_radius] + Button('Button', { type: ButtonType.Normal }) + .id('circle_border') + .borderRadius(10) + // [End custom_button_border_radius] + } + + ComponentCard({ + title: $r('app.string.ButtonCustomStyle_titleTwo'), + description: $r('app.string.ButtonCustomStyle_descriptionTwo') + }) { + // [Start custom_font_style] + Button('Button').id('font_style') + .fontSize(20) + .fontColor(Color.Pink) + .fontWeight(800) + // [End custom_font_style] + } + + ComponentCard({ + title: $r('app.string.ButtonCustomStyle_titleThree'), + description: $r('app.string.ButtonCustomStyle_descriptionThree') + }) { + // [Start custom_background_color] + Button('Button').id('background_color') + .backgroundColor(Color.Red) + // [End custom_background_color] + } + } + .width('100%') + .height('100%') + .padding({ left: 12, right: 12 }) + } + .backgroundColor('#f1f2f3') + .title(this.resourceToString($r('app.string.ButtonCustomStyle_title'))) + } +} + diff --git a/ArkUISample/ChooseComponent/entry/src/main/ets/pages/button/CreateButton.ets b/ArkUISample/ChooseComponent/entry/src/main/ets/pages/button/CreateButton.ets new file mode 100644 index 0000000000000000000000000000000000000000..d903c8599d0ab0c0d8e93fa44da34b2411ddc72d --- /dev/null +++ b/ArkUISample/ChooseComponent/entry/src/main/ets/pages/button/CreateButton.ets @@ -0,0 +1,58 @@ +/* + * Copyright (c) 2024 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +import { ComponentCard } from '../../common/Card'; + +@Entry +@Component +export struct CreateButton { + resourceToString(resource: Resource): string { + return getContext(this).resourceManager.getStringSync(resource); + } + + build() { + NavDestination() { + Column({ space: 12 }) { + ComponentCard({ + title: $r('app.string.CreateButton_titleOne'), + description: $r('app.string.CreateButton_descriptionOne') + }) { + // [Start create_button_by_label] + Button('Button', { type: ButtonType.Capsule, stateEffect: true }) + .id('button') + // [End create_button_by_label] + } + + ComponentCard({ + title: $r('app.string.CreateButton_titleTwo'), + description: $r('app.string.CreateButton_descriptionTwo') + }) { + // [Start create_button_by_button_options] + Button() { + Row({ space: 4 }) { + Image($r('sys.media.ohos_ic_back')).width(20).height(40).fillColor(0xffffff) + Text('back').fontColor(0xffffff) + }.alignItems(VerticalAlign.Center).justifyContent(FlexAlign.Center).width(90).height(40) + }.id('button_back') + // [End create_button_by_button_options] + } + } + .width('100%') + .height('100%') + .padding({ left: 12, right: 12 }) + } + .backgroundColor('#f1f2f3') + .title(this.resourceToString($r('app.string.CreateButton_title'))) + } +} \ No newline at end of file diff --git a/ArkUISample/ChooseComponent/entry/src/main/ets/pages/button/FloatingButton.ets b/ArkUISample/ChooseComponent/entry/src/main/ets/pages/button/FloatingButton.ets new file mode 100644 index 0000000000000000000000000000000000000000..8d8cc3306c0d8817ea76e2569bc4e641e0414f2f --- /dev/null +++ b/ArkUISample/ChooseComponent/entry/src/main/ets/pages/button/FloatingButton.ets @@ -0,0 +1,82 @@ +/* + * Copyright (c) 2024 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +// [Start floating_button] +@Entry +@Component +export struct FloatingButton { + @State private arr: number[] = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]; + // [StartExclude floating_button] + pathStack: NavPathStack = new NavPathStack(); + + resourceToString(resource: Resource): string { + return getContext(this).resourceManager.getStringSync(resource); + } + // [EndExclude floating_button] + + build() { + // [StartExclude floating_button] + NavDestination() { + // [EndExclude floating_button] + Stack() { + List({ space: 12, initialIndex: 0 }) { + ForEach(this.arr, (item: number) => { + ListItem() { + Text(`${item}`) + .width('100%') + .height(100) + .fontSize(16) + .textAlign(TextAlign.Center) + .borderRadius(10) + .backgroundColor(0xFFFFFF) + } + }, (item: number) => item.toString()) + } + .id('List') + .width('100%') + .padding({ + left: 15, + right: 15 + }) + + // [Start custom_button_function] + Button() { + Image($r('sys.media.ohos_ic_public_add')) + .fillColor(0xffffff) + .width(24) + .height(24) + } + .id('Button') + .width(40) + .height(40) + .position({ x: '80%', y: 570 }) + .onClick(() => { + // 需要执行的操作 + // [StartExclude custom_button_function] + this.arr.push(this.arr.length); + // [EndExclude custom_button_function] + }) + // [End custom_button_function] + } + .width('100%') + .height('100%') + .backgroundColor(0xDCDCDC) + .padding({ top: 6 }) + } + // [End floating_button] + .backgroundColor('#f1f2f3') + .title(this.resourceToString($r('app.string.FloatingButton_title'))) + } +} \ No newline at end of file diff --git a/ArkUISample/ChooseComponent/entry/src/main/ets/pages/button/Index.ets b/ArkUISample/ChooseComponent/entry/src/main/ets/pages/button/Index.ets new file mode 100644 index 0000000000000000000000000000000000000000..f37f6f3bd71096b1f6fd86e9612037192180f1cb --- /dev/null +++ b/ArkUISample/ChooseComponent/entry/src/main/ets/pages/button/Index.ets @@ -0,0 +1,103 @@ +/* + * Copyright (c) 2024 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { ButtonCustomStyle } from './ButtonCustomStyle'; +import { CompletedRoutableCard } from '../../common/Card'; +import { CreateButton } from './CreateButton' +import { FloatingButton } from './FloatingButton'; +import { Route } from '../../common/Route'; +import { SetButtonType } from './SetButtonType'; +import { SubmitForm } from './SubmitForm'; +import resource from '../../common/resource' + +export const BUTTON_ROUTE_PREFIX: string = 'button'; + +const routes: Route[] = [ + { + name: `${BUTTON_ROUTE_PREFIX}/CreateButton`, + title: resource.resourceToString($r('app.string.CreateButton_title')), + description: $r('app.string.CreateButton_description') + }, + { + name: `${BUTTON_ROUTE_PREFIX}/SetButtonType`, + title: resource.resourceToString($r('app.string.SetButtonType_title')), + description: $r('app.string.SetButtonType_description') + }, + { + name: `${BUTTON_ROUTE_PREFIX}/ButtonCustomStyle`, + title: resource.resourceToString($r('app.string.ButtonCustomStyle_title')), + description: $r('app.string.ButtonCustomStyle_description') + }, + { + name: `${BUTTON_ROUTE_PREFIX}/SubmitForm`, + title: resource.resourceToString($r('app.string.SubmitForm_title')), + description: $r('app.string.SubmitForm_description') + }, + { + name: `${BUTTON_ROUTE_PREFIX}/FloatingButton`, + title: resource.resourceToString($r('app.string.FloatingButton_title')), + description: $r('app.string.FloatingButton_description') + }, +] + +@Builder +export function buttonDestination(name: string) { + if (name === BUTTON_ROUTE_PREFIX) { + ButtonExample(); + } else if (name === routes[0].name) { + CreateButton(); + } else if (name === routes[1].name) { + SetButtonType(); + } else if (name === routes[2].name) { + ButtonCustomStyle(); + } else if (name === routes[3].name) { + SubmitForm(); + } else if (name === routes[4].name) { + FloatingButton(); + } +} + +@Entry +@Component +struct ButtonExample { + @Consume pathStack: NavPathStack; + + resourceToString(resource: Resource): string { + return getContext(this).resourceManager.getStringSync(resource); + } + build() { + NavDestination() { + List({ space: 12 }) { + ForEach(routes, (route: Route) => { + ListItem() { + CompletedRoutableCard({ title: route.title, description: route.description }) + } + .width('100%') + .onClick(() => { + this.pathStack.pushPath({ name: route.name }); + }) + }) + } + .contentStartOffset(20) + .padding({ left: 16, right: 16 }) + } + .backgroundColor('#f1f3f5') + .title('Button', { + backgroundBlurStyle: BlurStyle.COMPONENT_THICK, + barStyle: BarStyle.STACK + }) + .title('Button') + } +} \ No newline at end of file diff --git a/ArkUISample/ChooseComponent/entry/src/main/ets/pages/button/SetButtonType.ets b/ArkUISample/ChooseComponent/entry/src/main/ets/pages/button/SetButtonType.ets new file mode 100644 index 0000000000000000000000000000000000000000..489944cc97e22d3f1d81c1e1ce544bc4c10e186c --- /dev/null +++ b/ArkUISample/ChooseComponent/entry/src/main/ets/pages/button/SetButtonType.ets @@ -0,0 +1,76 @@ +/* + * Copyright (c) 2024 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { ComponentCard } from '../../common/Card'; + +@Entry +@Component +export struct SetButtonType { + pathStack: NavPathStack = new NavPathStack(); + + resourceToString(resource: Resource): string { + return getContext(this).resourceManager.getStringSync(resource); + } + + build() { + NavDestination() { + Column({ space: 12 }) { + ComponentCard({ + title: $r('app.string.SetButtonType_titleOne'), + description: $r('app.string.SetButtonType_descriptionOne') + }) { + // [Start create_capsule_button] + Button('Button', { type: ButtonType.Capsule }) + .id('Capsule') + // [End create_capsule_button] + } + + ComponentCard({ + title: $r('app.string.SetButtonType_titleTwo'), + description: $r('app.string.SetButtonType_descriptionTwo') + }) { + // [Start create_circle_button] + Button('Button', { type: ButtonType.Circle }) + .id('Circle') + .width(80) + // [End create_circle_button] + } + + ComponentCard({ + title: $r('app.string.SetButtonType_titleThree'), + description: $r('app.string.SetButtonType_descriptionThree') + }) { + // [Start create_normal_button] + Button('Button', { type: ButtonType.Normal }) + .id('Normal') + // [End create_normal_button] + } + + ComponentCard({ + title: $r('app.string.SetButtonType_titleFour'), + description: $r('app.string.SetButtonType_descriptionFour') + }) { + Button('Button', { type: ButtonType.ROUNDED_RECTANGLE }) + .id('Round') + } + } + .width('100%') + .height('100%') + .padding({ left: 12, right: 12 }) + } + .backgroundColor('#f1f2f3') + .title(this.resourceToString($r('app.string.SetButtonType_title'))) + } +} \ No newline at end of file diff --git a/ArkUISample/ChooseComponent/entry/src/main/ets/pages/button/SubmitForm.ets b/ArkUISample/ChooseComponent/entry/src/main/ets/pages/button/SubmitForm.ets new file mode 100644 index 0000000000000000000000000000000000000000..8fa9b3a42c08a5da64c3b5767c70a4dad1d477a4 --- /dev/null +++ b/ArkUISample/ChooseComponent/entry/src/main/ets/pages/button/SubmitForm.ets @@ -0,0 +1,66 @@ +/* + * Copyright (c) 2024 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +// [Start button_to_log_in_or_register] +@Entry +@Component +export struct SubmitForm { + // [StartExclude button_to_log_in_or_register] + @State username: string = '' + @State password: string = '' + pathStack: NavPathStack = new NavPathStack(); + + resourceToString(resource: Resource): string { + return getContext(this).resourceManager.getStringSync(resource); + } + // [EndExclude button_to_log_in_or_register] + + build() { + // [StartExclude button_to_log_in_or_register] + NavDestination() { + // [EndExclude button_to_log_in_or_register] + Column({ space: 12 }) { + TextInput({ text: this.username, placeholder: 'input your username' }) + .id('username') + // [StartExclude button_to_log_in_or_register] + .onChange((value: string) => { + this.username = value; + }) + // [EndExclude button_to_log_in_or_register] + TextInput({ text: this.password, placeholder: 'input your password' }) + .type(InputType.Password) + .id('password') + // [StartExclude button_to_log_in_or_register] + .onChange((value: string) => { + this.password = value; + }) + // [EndExclude button_to_log_in_or_register] + Button('Register') + .width('100%') + .id('register') + .onClick(() => { + // 需要执行的操作 + // [StartExclude button_to_log_in_or_register] + this.username = 'your username'; + this.password = 'your password'; + // [EndExclude button_to_log_in_or_register] + }) + }.padding(12) + // [End button_to_log_in_or_register] + } + .backgroundColor('#f1f2f3') + .title(this.resourceToString($r('app.string.SubmitForm_title'))) + } +} \ No newline at end of file diff --git a/ArkUISample/ChooseComponent/entry/src/main/ets/pages/radio/Index.ets b/ArkUISample/ChooseComponent/entry/src/main/ets/pages/radio/Index.ets new file mode 100644 index 0000000000000000000000000000000000000000..0d8d10f22d228e32415822f5bf08a3ea7e766c80 --- /dev/null +++ b/ArkUISample/ChooseComponent/entry/src/main/ets/pages/radio/Index.ets @@ -0,0 +1,67 @@ +/* + * Copyright (c) 2024 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { RadioSample } from './RadioSample'; +import { CompletedRoutableCard } from '../../common/Card'; +import { Route } from '../../common/Route'; +import resource from '../../common/resource'; + +export const RADIO_ROUTE_PREFIX: string = 'radio'; + +const routes: Route[] = [ + { + name: `${RADIO_ROUTE_PREFIX}/RadioSample`, + title: resource.resourceToString($r('app.string.RadioSample_title')), + description: $r('app.string.RadioSample_description') + } +] + +@Builder +export function radioDestination(name: string) { + if (name === RADIO_ROUTE_PREFIX) { + RadioExample(); + } else if (name === routes[0].name) { + RadioSample(); + } +} + +@Entry +@Component +struct RadioExample { + @Consume pathStack: NavPathStack; + + build() { + NavDestination() { + List({ space: 12 }) { + ForEach(routes, (route: Route) => { + ListItem() { + CompletedRoutableCard({ title: route.title, description: route.description }) + } + .width('100%') + .onClick(() => { + this.pathStack.pushPath({ name: route.name }); + }) + }) + } + .contentStartOffset(56) + .padding({ left: 16, right: 16 }) + } + .backgroundColor('#f1f3f5') + .title('Radio', { + backgroundBlurStyle: BlurStyle.COMPONENT_THICK, + barStyle: BarStyle.STACK + }) + } +} \ No newline at end of file diff --git a/ArkUISample/ChooseComponent/entry/src/main/ets/pages/radio/RadioSample.ets b/ArkUISample/ChooseComponent/entry/src/main/ets/pages/radio/RadioSample.ets new file mode 100644 index 0000000000000000000000000000000000000000..eb388781aedbc0549a2df34f5140b21e56afa3cc --- /dev/null +++ b/ArkUISample/ChooseComponent/entry/src/main/ets/pages/radio/RadioSample.ets @@ -0,0 +1,98 @@ +/* + * Copyright (c) 2024 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +// [Start click_radio_to_change_function] +import { promptAction } from '@kit.ArkUI'; + +@Entry +@Component +export struct RadioSample { + @State message: string = 'Ringing'; + pathStack: NavPathStack = new NavPathStack(); + + resourceToString(resource: Resource): string { + return getContext(this).resourceManager.getStringSync(resource); + } + + build() { + NavDestination() { + Column({ space: 8 }) { + Column({ space: 8 }) { + Text(this.message).id('message') + Row() { + // [Start set_radio_status] + Radio({ value: 'Ringing', group: 'radioGroup' }) + .checked(true) + // [End set_radio_status] + .id('ringing') + .onChange((isChecked: boolean) => { + if (isChecked) { + // 切换为响铃模式 + // [StartExclude click_radio_to_change_function] + this.message = 'Ringing mode'; + // [EndExclude click_radio_to_change_function] + promptAction.showToast({ 'message': 'Ringing mode.' }); + } + }) + Text('Ringing') + }.width('25%') + + // [Start change_radio_function] + Row() { + Radio({ value: 'Vibration', group: 'radioGroup' }) + .id('vibration') + .onChange((isChecked: boolean) => { + if (isChecked) { + // 切换为振动模式 + // [StartExclude change_radio_function] + this.message = 'Vibration'; + // [EndExclude change_radio_function] + promptAction.showToast({ 'message': 'Vibration mode.' }); + } + }) + Text('Vibration') + }.width('25%') + + Row() { + Radio({ value: 'Silent', group: 'radioGroup' }) + .id('silent') + .onChange((isChecked: boolean) => { + if (isChecked) { + // 切换为静音模式 + // [StartExclude change_radio_function] + this.message = 'Silent'; + // [EndExclude change_radio_function] + promptAction.showToast({ 'message': 'Silent mode.' }); + } + }) + Text('Silent') + }.width('25%') + // [End change_radio_function] + } + .alignItems(HorizontalAlign.Center) + .backgroundColor('#fff') + .borderRadius(12) + .padding(12) + .width('100%') + } + .width('100%') + .height('100%') + .padding({ left: 12, right: 12 }) + } + .backgroundColor('#f1f2f3') + .title(this.resourceToString($r('app.string.RadioSample_title'))) + } +} +// [End click_radio_to_change_function] \ No newline at end of file diff --git a/ArkUISample/ChooseComponent/entry/src/main/ets/pages/toggle/CreateToggle.ets b/ArkUISample/ChooseComponent/entry/src/main/ets/pages/toggle/CreateToggle.ets new file mode 100644 index 0000000000000000000000000000000000000000..c930bc32b36cf30f480a5e7c07fe6911c9c26318 --- /dev/null +++ b/ArkUISample/ChooseComponent/entry/src/main/ets/pages/toggle/CreateToggle.ets @@ -0,0 +1,73 @@ +/* + * Copyright (c) 2024 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { ComponentCard } from '../../common/Card'; + +@Entry +@Component +export struct CreateToggle { + pathStack: NavPathStack = new NavPathStack(); + + resourceToString(resource: Resource): string { + return getContext(this).resourceManager.getStringSync(resource); + } + + build() { + NavDestination() { + Column({ space: 12 }) { + ComponentCard({ + title: 'ToggleType is Checkbox', + }) { + // [Start create_toggle_with_checkbox] + Toggle({ type: ToggleType.Checkbox, isOn: false }).id('toggle1') + Toggle({ type: ToggleType.Checkbox, isOn: true }).id('toggle2') + // [End create_toggle_with_checkbox] + } + + ComponentCard({ + title: 'ToggleType is Switch', + }) { + // [Start create_toggle_with_switch] + Toggle({ type: ToggleType.Switch, isOn: false }).id('toggle3') + Toggle({ type: ToggleType.Switch, isOn: true }).id('toggle4') + // [End create_toggle_with_switch] + } + + ComponentCard({ + title: 'ToggleType is Button', + }) { + // [Start create_a_toggle_that_contains_subcomponents] + Toggle({ type: ToggleType.Button, isOn: false }) { + Text('status button') + .fontColor('#182431') + .fontSize(12) + }.width(100).id('toggle5') + + Toggle({ type: ToggleType.Button, isOn: true }) { + Text('status button') + .fontColor('#182431') + .fontSize(12) + }.width(100).id('toggle6') + // [End create_a_toggle_that_contains_subcomponents] + } + } + .width('100%') + .height('100%') + .padding({ left: 12, right: 12 }) + } + .backgroundColor('#f1f2f3') + .title(this.resourceToString($r('app.string.CreateToggle_title'))) + } +} \ No newline at end of file diff --git a/ArkUISample/ChooseComponent/entry/src/main/ets/pages/toggle/Index.ets b/ArkUISample/ChooseComponent/entry/src/main/ets/pages/toggle/Index.ets new file mode 100644 index 0000000000000000000000000000000000000000..98531313404afe0347a25719923de82147dc59c9 --- /dev/null +++ b/ArkUISample/ChooseComponent/entry/src/main/ets/pages/toggle/Index.ets @@ -0,0 +1,84 @@ +/* + * Copyright (c) 2024 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { CompletedRoutableCard } from '../../common/Card'; +import { CreateToggle } from './CreateToggle'; +import { CustomStyle } from './ToggleCustomStyle'; +import { Route } from '../../common/Route'; +import { ToggleSample } from './ToggleCaseExample'; +import resource from '../../common/resource'; + +export const TOGGLE_ROUTE_PREFIX: string = 'toggle'; + +const routes: Route[] = [ + { + name: `${TOGGLE_ROUTE_PREFIX}/CreateToggle`, + title: resource.resourceToString($r('app.string.CreateToggle_title')), + description: $r('app.string.CreateToggle_description') + }, + { + name: `${TOGGLE_ROUTE_PREFIX}/ToggleCustomStyle`, + title: resource.resourceToString($r('app.string.ToggleCustomStyle_title')), + description: $r('app.string.ToggleCustomStyle_description') + }, + { + name: `${TOGGLE_ROUTE_PREFIX}/ToggleCaseExample`, + title: resource.resourceToString($r('app.string.changeToggle_example')), + description: $r('app.string.ToggleCaseExample_description') + } +] + +@Builder +export function toggleDestination(name: string) { + if (name === TOGGLE_ROUTE_PREFIX) { + ToggleExample(); + } else if (name === routes[0].name) { + CreateToggle(); + } else if (name === routes[1].name) { + CustomStyle(); + } else if (name === routes[2].name) { + ToggleSample(); + } +} + +@Entry +@Component +struct ToggleExample { + @Consume pathStack: NavPathStack; + + build() { + NavDestination() { + List({ space: 12 }) { + ForEach(routes, (route: Route) => { + ListItem() { + CompletedRoutableCard({ title: route.title, description: route.description }) + } + .width('100%') + .onClick(() => { + this.pathStack.pushPath({ name: route.name }); + }) + }) + } + .contentStartOffset(56) + .padding({ left: 16, right: 16 }) + } + .backgroundColor('#f1f3f5') + .title('Toggle', { + backgroundBlurStyle: BlurStyle.COMPONENT_THICK, + barStyle: BarStyle.STACK + }) + } +} + diff --git a/ArkUISample/ChooseComponent/entry/src/main/ets/pages/toggle/ToggleCaseExample.ets b/ArkUISample/ChooseComponent/entry/src/main/ets/pages/toggle/ToggleCaseExample.ets new file mode 100644 index 0000000000000000000000000000000000000000..10a05aa64686c376e0586b1b6eec411b5e9dccd0 --- /dev/null +++ b/ArkUISample/ChooseComponent/entry/src/main/ets/pages/toggle/ToggleCaseExample.ets @@ -0,0 +1,71 @@ +/* + * Copyright (c) 2024 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +// [Start the_example_of_bluetooth] +import { promptAction } from '@kit.ArkUI'; + +@Entry +@Component +export struct ToggleSample { + @State message: string = 'off'; + pathStack: NavPathStack = new NavPathStack(); + + resourceToString(resource: Resource): string { + return getContext(this).resourceManager.getStringSync(resource); + } + + build() { + NavDestination() { + Column({ space: 8 }) { + Column({ space: 8 }) { + Text('Bluetooth Mode: ' + this.message) + .id('message') + Row() { + Text('Bluetooth') + Blank() + // [Start create_toggle_case] + Toggle({ type: ToggleType.Switch }) + .id('toggle') + .onChange((isOn: boolean) => { + if (isOn) { + // [StartExclude create_toggle_case] + this.message = 'on'; + promptAction.showToast({ 'message': 'Bluetooth is on.' }); + // [EndExclude create_toggle_case] + } else { + // [StartExclude create_toggle_case] + this.message = 'off'; + promptAction.showToast({ 'message': 'Bluetooth is off.' }); + // [EndExclude create_toggle_case] + } + }) + // [End create_toggle_case] + }.width('100%') + } + .alignItems(HorizontalAlign.Start) + .backgroundColor('#fff') + .borderRadius(12) + .padding(12) + .width('100%') + } + .width('100%') + .height('100%') + .padding({ left: 12, right: 12 }) + } + .backgroundColor('#f1f2f3') + .title(this.resourceToString($r('app.string.ToggleCaseExample_title'))) + } +} +// [End the_example_of_bluetooth] \ No newline at end of file diff --git a/ArkUISample/ChooseComponent/entry/src/main/ets/pages/toggle/ToggleCustomStyle.ets b/ArkUISample/ChooseComponent/entry/src/main/ets/pages/toggle/ToggleCustomStyle.ets new file mode 100644 index 0000000000000000000000000000000000000000..529b693ebc6283e06161e6bd7e21583fb7a3ee32 --- /dev/null +++ b/ArkUISample/ChooseComponent/entry/src/main/ets/pages/toggle/ToggleCustomStyle.ets @@ -0,0 +1,73 @@ +/* + * Copyright (c) 2024 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { ComponentCard } from '../../common/Card'; + +@Entry +@Component +export struct CustomStyle { + pathStack: NavPathStack = new NavPathStack(); + + resourceToString(resource: Resource): string { + return getContext(this).resourceManager.getStringSync(resource); + } + + build() { + NavDestination() { + Column({ space: 12 }) { + ComponentCard({ + title: $r('app.string.ToggleCustomStyle_titleOne'), + description: $r('app.string.ToggleCustomStyle_descriptionOne') + }) { + // [Start custom_toggle] + Toggle({ type: ToggleType.Button, isOn: true }) { + Text('status button') + .fontColor(Color.White) + .fontSize(12) + }.width(100) + .selectedColor(Color.Pink) + .id('toggle1') + + Toggle({ type: ToggleType.Checkbox, isOn: true }) + .selectedColor(Color.Pink) + .id('toggle2') + Toggle({ type: ToggleType.Switch, isOn: true }) + .selectedColor(Color.Pink) + .id('toggle3') + // [End custom_toggle] + } + + ComponentCard({ + title: $r('app.string.ToggleCustomStyle_titleTwo'), + description: $r('app.string.ToggleCustomStyle_descriptionTwo') + }) { + // [Start custom_switch_point_color] + Toggle({ type: ToggleType.Switch, isOn: false }) + .switchPointColor(Color.Pink) + .id('toggle4') + Toggle({ type: ToggleType.Switch, isOn: true }) + .switchPointColor(Color.Pink) + .id('toggle5') + // [End custom_switch_point_color] + } + } + .width('100%') + .height('100%') + .padding({ left: 12, right: 12 }) + } + .backgroundColor('#f1f2f3') + .title(this.resourceToString($r('app.string.ToggleCustomStyle_title'))) + } +} diff --git a/ArkUISample/ChooseComponent/entry/src/main/module.json5 b/ArkUISample/ChooseComponent/entry/src/main/module.json5 new file mode 100644 index 0000000000000000000000000000000000000000..cb5df2316a385286bf09b1aab230f0bf56d8b993 --- /dev/null +++ b/ArkUISample/ChooseComponent/entry/src/main/module.json5 @@ -0,0 +1,66 @@ +/* + * Copyright (c) 2024 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +{ + "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": [ + "action.system.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/ArkUISample/ChooseComponent/entry/src/main/resources/base/element/color.json b/ArkUISample/ChooseComponent/entry/src/main/resources/base/element/color.json new file mode 100644 index 0000000000000000000000000000000000000000..3c712962da3c2751c2b9ddb53559afcbd2b54a02 --- /dev/null +++ b/ArkUISample/ChooseComponent/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/ArkUISample/ChooseComponent/entry/src/main/resources/base/element/string.json b/ArkUISample/ChooseComponent/entry/src/main/resources/base/element/string.json new file mode 100644 index 0000000000000000000000000000000000000000..f5c2a333b646c84f8fa9b84e843d1a0b8e2676f1 --- /dev/null +++ b/ArkUISample/ChooseComponent/entry/src/main/resources/base/element/string.json @@ -0,0 +1,211 @@ +{ + "string": [ + { + "name": "module_desc", + "value": "module description" + }, + { + "name": "EntryAbility_desc", + "value": "description" + }, + { + "name": "EntryAbility_label", + "value": "ChooseComponent" + }, + { + "name": "RadioSample_title", + "value": "单选框示例示例" + }, + { + "name": "Sample", + "value": "示例" + }, + { + "name": "RadioSample_description", + "value": "单选框示例,模拟单选框应用效果。" + }, + { + "name": "ToggleCaseExample_title", + "value": "toggle蓝牙示例" + }, + { + "name": "ToggleCaseExample_description", + "value": "Toggle 组件的场景示例,模拟toggle的使用场景。" + }, + { + "name": "ToggleCustomStyle_title", + "value": "自定义切换按钮" + }, + { + "name": "CreateToggle_title", + "value": "创建切换按钮" + }, + { + "name": "CreateToggle_description", + "value": "Toggle 组件的创建,分别创建默认不带子组件的按钮和自定义带子组件的切换按钮。" + }, + { + "name": "ToggleCustomStyle_titleOne", + "value": "selectedColor设置选中后的背景颜色" + }, + { + "name": "ToggleCustomStyle_titleTwo", + "value": "设置Switch类型的圆形滑块颜色" + }, + { + "name": "ToggleCustomStyle_description", + "value": "Toggle 组件具体样式的设置,可对字体、背景等要素进行设置。" + }, + { + "name": "ToggleCustomStyle_descriptionOne", + "value": "通过selectedColor属性设置Toggle打开选中后的背景颜色。" + }, + { + "name": "ToggleCustomStyle_descriptionTwo", + "value": "通过switchPointColor属性设置Switch类型的圆形滑块颜色,仅对type为ToggleType.Switch生效。" + }, + { + "name": "CreateButton_title", + "value": "创建按钮" + }, + { + "name": "CreateButton_titleOne", + "value": "不包含子组件的按钮" + }, + { + "name": "CreateButton_titleTwo", + "value": "包含子组件的按钮" + }, + { + "name": "CreateButton_description", + "value": "Button 组件的创建,分别创建默认不带子组件的按钮和自定义带子组件的按钮。" + }, + { + "name": "CreateButton_descriptionOne", + "value": "通过接口创建按钮,label用来设置按钮文字,type用于设置Button类型,stateEffect属性设置Button是否开启点击效果。" + }, + { + "name": "CreateButton_descriptionTwo", + "value": "通过接口创建带子组件的按钮。使用Row作为子组件容器,Image引用箭头图片,Text显示‘back’文本。" + }, + { + "name": "SetButtonType_test", + "value": "按钮类型" + }, + { + "name": "SetButtonType_title", + "value": "设置按钮类型" + }, + { + "name": "SetButtonType_titleOne", + "value": "胶囊型按钮" + }, + { + "name": "SetButtonType_titleTwo", + "value": "圆形按钮" + }, + { + "name": "SetButtonType_titleThree", + "value": "普通按钮" + }, + { + "name": "SetButtonType_titleFour", + "value": "圆角矩形按钮" + }, + { + "name": "SetButtonType_description", + "value": "Button 组件的类型的设置,共有四种类型:胶囊按钮、圆形按钮、普通按钮、圆角矩形按钮。" + }, + { + "name": "SetButtonType_descriptionOne", + "value": "通过type属性为ButtonType.Capsule,将按钮类型设置为胶囊型按钮(圆角默认为高度的一半)。" + }, + { + "name": "SetButtonType_descriptionTwo", + "value": "通过type属性为ButtonType.Circle,将按钮类型设置为圆形按钮。" + }, + { + "name": "SetButtonType_descriptionThree", + "value": "通过type属性为ButtonType.Normal,将按钮类型设置为普通按钮(默认不带圆角)。" + }, + { + "name": "SetButtonType_descriptionFour", + "value": "通过type属性为ButtonType.ROUNDED_RECTANGLE,将按钮类型设置为圆角矩形按钮。" + }, + { + "name": "ButtonCustomStyle_test", + "value": "按钮样式" + }, + { + "name": "ButtonCustomStyle_title", + "value": "自定义按钮样式" + }, + { + "name": "ButtonCustomStyle_titleOne", + "value": "设置边框弧度" + }, + { + "name": "ButtonCustomStyle_titleTwo", + "value": "设置文本样式" + }, + { + "name": "ButtonCustomStyle_titleThree", + "value": "设置背景颜色" + }, + { + "name": "ButtonCustomStyle_description", + "value": "Button 组件具体样式的设置,可对字体、背景等要素进行设置。" + }, + { + "name": "ButtonCustomStyle_descriptionOne", + "value": "按钮type属性为ButtonType.Normal,通过borderRadius设置边框圆角半径为10。" + }, + { + "name": "ButtonCustomStyle_descriptionTwo", + "value": "通过fontSize设置按钮中字体的大小为20,fontColor设置字体颜色为粉色,fontWeight设置字体的粗细值为800。" + }, + { + "name": "ButtonCustomStyle_descriptionThree", + "value": "通过backgroundColor属性设置按钮里的背景颜色为红色。" + }, + { + "name": "SubmitForm", + "value": "注册" + }, + { + "name": "SubmitForm_title", + "value": "注册登录示例" + }, + { + "name": "SubmitForm_description", + "value": "Button 组件使用的场景示例,对注册/登录页面的模拟。" + }, + { + "name": "FloatingButton_title", + "value": "悬浮按钮示例" + }, { + "name": "FloatingButton", + "value": "Button 组件悬浮按钮的场景示例,在场景中设置悬浮于容器的按钮。" + }, + { + "name": "FloatingButton_description", + "value": "Button 组件悬浮按钮的场景示例,在场景中设置悬浮于容器的按钮。" + }, + { + "name": "changeToggle_example", + "value": "切换按钮示例" + }, + { + "name": "button", + "value": "按钮/Button" + }, + { + "name": "radio", + "value": "单选框/Radio" + }, + { + "name": "toggle", + "value": "切换按钮/Toggle" + } + ] +} \ No newline at end of file diff --git a/ArkUISample/ChooseComponent/entry/src/main/resources/base/media/background.png b/ArkUISample/ChooseComponent/entry/src/main/resources/base/media/background.png new file mode 100644 index 0000000000000000000000000000000000000000..f939c9fa8cc8914832e602198745f592a0dfa34d Binary files /dev/null and b/ArkUISample/ChooseComponent/entry/src/main/resources/base/media/background.png differ diff --git a/ArkUISample/ChooseComponent/entry/src/main/resources/base/media/foreground.png b/ArkUISample/ChooseComponent/entry/src/main/resources/base/media/foreground.png new file mode 100644 index 0000000000000000000000000000000000000000..4483ddad1f079e1089d685bd204ee1cfe1d01902 Binary files /dev/null and b/ArkUISample/ChooseComponent/entry/src/main/resources/base/media/foreground.png differ diff --git a/ArkUISample/ChooseComponent/entry/src/main/resources/base/media/layered_image.json b/ArkUISample/ChooseComponent/entry/src/main/resources/base/media/layered_image.json new file mode 100644 index 0000000000000000000000000000000000000000..fb49920440fb4d246c82f9ada275e26123a2136a --- /dev/null +++ b/ArkUISample/ChooseComponent/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/ArkUISample/ChooseComponent/entry/src/main/resources/base/media/startIcon.png b/ArkUISample/ChooseComponent/entry/src/main/resources/base/media/startIcon.png new file mode 100644 index 0000000000000000000000000000000000000000..205ad8b5a8a42e8762fbe4899b8e5e31ce822b8b Binary files /dev/null and b/ArkUISample/ChooseComponent/entry/src/main/resources/base/media/startIcon.png differ diff --git a/ArkUISample/ChooseComponent/entry/src/main/resources/base/profile/backup_config.json b/ArkUISample/ChooseComponent/entry/src/main/resources/base/profile/backup_config.json new file mode 100644 index 0000000000000000000000000000000000000000..78f40ae7c494d71e2482278f359ec790ca73471a --- /dev/null +++ b/ArkUISample/ChooseComponent/entry/src/main/resources/base/profile/backup_config.json @@ -0,0 +1,3 @@ +{ + "allowToBackupRestore": true +} \ No newline at end of file diff --git a/ArkUISample/ChooseComponent/entry/src/main/resources/base/profile/main_pages.json b/ArkUISample/ChooseComponent/entry/src/main/resources/base/profile/main_pages.json new file mode 100644 index 0000000000000000000000000000000000000000..fea96ecefefeef6879b28d68293f12f11459aafe --- /dev/null +++ b/ArkUISample/ChooseComponent/entry/src/main/resources/base/profile/main_pages.json @@ -0,0 +1,14 @@ +{ + "src": [ + "pages/Index", + "pages/button/CreateButton", + "pages/button/ButtonCustomStyle", + "pages/button/FloatingButton", + "pages/radio/RadioSample", + "pages/button/SetButtonType", + "pages/button/SubmitForm", + "pages/toggle/CreateToggle", + "pages/toggle/ToggleCustomStyle", + "pages/toggle/ToggleCaseExample" + ] +} diff --git a/ArkUISample/ChooseComponent/entry/src/main/resources/dark/element/color.json b/ArkUISample/ChooseComponent/entry/src/main/resources/dark/element/color.json new file mode 100644 index 0000000000000000000000000000000000000000..79b11c2747aec33e710fd3a7b2b3c94dd9965499 --- /dev/null +++ b/ArkUISample/ChooseComponent/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/ArkUISample/ChooseComponent/entry/src/mock/mock-config.json5 b/ArkUISample/ChooseComponent/entry/src/mock/mock-config.json5 new file mode 100644 index 0000000000000000000000000000000000000000..26ed9f53bc46192a07ad5ab16ea24e7ce9a79328 --- /dev/null +++ b/ArkUISample/ChooseComponent/entry/src/mock/mock-config.json5 @@ -0,0 +1,17 @@ +/* + * Copyright (c) 2024 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +{ +} \ No newline at end of file diff --git a/ArkUISample/ChooseComponent/entry/src/ohosTest/ets/test/Ability.test.ets b/ArkUISample/ChooseComponent/entry/src/ohosTest/ets/test/Ability.test.ets new file mode 100644 index 0000000000000000000000000000000000000000..a8ff110e5899c2d1727217919dd5badeacdfe061 --- /dev/null +++ b/ArkUISample/ChooseComponent/entry/src/ohosTest/ets/test/Ability.test.ets @@ -0,0 +1,50 @@ +/* + * Copyright (c) 2024 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { 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/ArkUISample/ChooseComponent/entry/src/ohosTest/ets/test/Index.test.ets b/ArkUISample/ChooseComponent/entry/src/ohosTest/ets/test/Index.test.ets new file mode 100644 index 0000000000000000000000000000000000000000..31e1bf86e0086fe7ff7737c06a1ee2cb9ebcd06a --- /dev/null +++ b/ArkUISample/ChooseComponent/entry/src/ohosTest/ets/test/Index.test.ets @@ -0,0 +1,256 @@ +/* + * Copyright (c) 2024 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { describe, it, expect, beforeAll } from '@ohos/hypium'; +// 导入测试依赖kit +import { abilityDelegatorRegistry, Driver, ON, MouseButton, Component, MatchPattern } from '@kit.TestKit'; +import { UIAbility, Want } from '@kit.AbilityKit'; + + +const delegator: abilityDelegatorRegistry.AbilityDelegator = abilityDelegatorRegistry.getAbilityDelegator(); +const bundleName = abilityDelegatorRegistry.getArguments().bundleName; +let abilityDelegator: abilityDelegatorRegistry.AbilityDelegator; +abilityDelegator = abilityDelegatorRegistry.getAbilityDelegator(); +let want: Want; + + +function sleep(time: number) { + return new Promise((resolve: Function) => setTimeout(resolve, time)); +} + +async function getResourceString(resource: Resource): Promise { + let manage = abilityDelegator.getAppContext().resourceManager; + let textString: string = await manage.getStringValue(resource); + return textString; +} + + +export default function IndexTest() { + + describe('IndexTest', () => { + + beforeAll(async () => { + want = { + bundleName: bundleName, + abilityName: 'EntryAbility' + }; + await delegator.startAbility(want); + await sleep(1000); + const ability: UIAbility = await delegator.getCurrentTopAbility(); + console.info("get top ability"); + expect(ability.context.abilityInfo.name).assertEqual('EntryAbility'); + }) + + it('testCreateButton', 0, async (done: Function) => { + console.info("uitest: testCreateButton begin"); + let driver = Driver.create(); + let button_list = await driver.findComponent(ON.text('Button', MatchPattern.CONTAINS)); + expect(button_list === null).assertFalse(); + await button_list.click(); + let str = await getResourceString($r('app.string.CreateButton_title')); + let button_search = await driver.findComponent(ON.text(str, MatchPattern.CONTAINS)); + expect(button_search === null).assertFalse(); + await button_search.click(); + + let button_normal = await driver.findComponent(ON.id('button')); + let button_back = await driver.findComponent(ON.id('button_back')); + expect(button_normal === null).assertFalse(); + expect(button_back === null).assertFalse(); + await button_normal.click(); + await button_back.click(); + await driver.pressBack(); + await driver.pressBack(); + done(); + }) + + it('testSetButtonType', 0, async (done: Function) => { + console.info("uitest: testSetButtonType begin"); + let driver = Driver.create(); + let button_list = await driver.findComponent(ON.text('Button', MatchPattern.CONTAINS)); + expect(button_list === null).assertFalse(); + await button_list.click(); + let str = await getResourceString($r('app.string.SetButtonType_test')); + let button_search = await driver.findComponent(ON.text(str, MatchPattern.CONTAINS)); + expect(button_search === null).assertFalse(); + await button_search.click(); + + let button_Capsule = await driver.findComponent(ON.id('Capsule')); + let button_Circle = await driver.findComponent(ON.id('Circle')); + let button_Normal = await driver.findComponent(ON.id('Normal')); + let button_Round = await driver.findComponent(ON.id('Round')); + expect(button_Capsule === null).assertFalse(); + expect(button_Circle === null).assertFalse(); + expect(button_Normal === null).assertFalse(); + expect(button_Round === null).assertFalse(); + await button_Capsule.click(); + await button_Circle.click(); + await button_Normal.click(); + await button_Round.click(); + await driver.pressBack(); + await driver.pressBack(); + done(); + }) + + it('testCustomStyle', 0, async (done: Function) => { + console.info("uitest: testCustomStyle begin"); + let driver = Driver.create(); + let button_list = await driver.findComponent(ON.text('Button', MatchPattern.CONTAINS)); + expect(button_list === null).assertFalse(); + await button_list.click(); + let str = await getResourceString($r('app.string.ButtonCustomStyle_test')); + let button_search = await driver.findComponent(ON.text(str, MatchPattern.CONTAINS)); + expect(button_search === null).assertFalse(); + await button_search.click(); + + let button_circle = await driver.findComponent(ON.id('circle_border')); + let button_font = await driver.findComponent(ON.id('font_style')); + let button_color = await driver.findComponent(ON.id('background_color')); + expect(button_circle === null).assertFalse(); + expect(button_font === null).assertFalse(); + expect(button_color === null).assertFalse(); + await button_circle.click(); + await button_font.click(); + await button_color.click(); + await driver.pressBack(); + await driver.pressBack(); + done(); + }) + + it('testSubmitForm', 0, async (done: Function) => { + console.info("uitest: testSubmitForm begin"); + let driver = Driver.create(); + let button_list = await driver.findComponent(ON.text('Button', MatchPattern.CONTAINS)); + expect(button_list === null).assertFalse(); + await button_list.click(); + let str = await getResourceString($r('app.string.SubmitForm')); + let button_search = await driver.findComponent(ON.text(str, MatchPattern.CONTAINS)); + expect(button_search === null).assertFalse(); + await button_search.click(); + + let username = await driver.findComponent(ON.id('username')); + let password = await driver.findComponent(ON.id('password')); + let registerButton = await driver.findComponent(ON.id('register')); + expect(username === null).assertFalse(); + expect(password === null).assertFalse(); + expect(registerButton === null).assertFalse(); + await username.inputText('username'); + await password.inputText('password'); + expect(await username.getText() === 'username').assertTrue(); + + let point = await password.getBoundsCenter(); + await driver.mouseClick({ + x: point.x + 300, y: point.y + }, MouseButton.MOUSE_BUTTON_LEFT, 0, 0); + expect(await password.getText() === 'password').assertTrue(); + await registerButton.click(); + await driver.pressBack(); + await driver.pressBack(); + await driver.pressBack(); + done(); + }) + + it('testFloatingButton', 0, async (done: Function) => { + console.info("uitest: testFloatingButton begin"); + let driver = Driver.create(); + let button_list = await driver.findComponent(ON.text('Button', MatchPattern.CONTAINS)); + expect(button_list === null).assertFalse(); + await button_list.click(); + let str = await getResourceString($r('app.string.FloatingButton')); + let button_search = await driver.findComponent(ON.text(str, MatchPattern.CONTAINS)); + expect(button_search === null).assertFalse(); + await button_search.click(); + + let floatingButton = await driver.findComponent(ON.id('Button')); + let stackList = await driver.findComponent(ON.id('List')); + expect(floatingButton === null).assertFalse(); + expect(stackList === null).assertFalse(); + await floatingButton.click(); + await stackList.scrollToBottom(); + await driver.pressBack(); + await driver.pressBack(); + done(); + }) + + it('testToggleUiExample1', 0, async (done: Function) => { + let driver: Driver = Driver.create(); + let button_list = await driver.findComponent(ON.text('Toggle', MatchPattern.CONTAINS)); + expect(button_list === null).assertFalse(); + await button_list.click(); + let str = await getResourceString($r('app.string.CreateToggle_title')); + let button_search = await driver.findComponent(ON.text(str, MatchPattern.CONTAINS)); + expect(button_search === null).assertFalse(); + await button_search.click(); + + let toggle1: Component = await driver.findComponent(ON.id('toggle1')); + let toggle2: Component = await driver.findComponent(ON.id('toggle2')); + let toggle3: Component = await driver.findComponent(ON.id('toggle3')); + let toggle4: Component = await driver.findComponent(ON.id('toggle4')); + let toggle5: Component = await driver.findComponent(ON.id('toggle5')); + let toggle6: Component = await driver.findComponent(ON.id('toggle6')); + await toggle1.click(); + await toggle2.click(); + await toggle3.click(); + await toggle4.click(); + await toggle5.click(); + await toggle6.click(); + await driver.pressBack(); + await driver.pressBack(); + done(); + }) + + it('testToggleUiExample2', 0, async (done: Function) => { + let driver: Driver = Driver.create(); + let button_list = await driver.findComponent(ON.text('Toggle', MatchPattern.CONTAINS)); + expect(button_list === null).assertFalse(); + await button_list.click(); + let str = await getResourceString($r('app.string.ToggleCustomStyle_title')); + let button_search = await driver.findComponent(ON.text(str, MatchPattern.CONTAINS)); + expect(button_search === null).assertFalse(); + await button_search.click(); + let toggle1: Component = await driver.findComponent(ON.id('toggle1')); + let toggle2: Component = await driver.findComponent(ON.id('toggle2')); + let toggle3: Component = await driver.findComponent(ON.id('toggle3')); + let toggle4: Component = await driver.findComponent(ON.id('toggle4')); + let toggle5: Component = await driver.findComponent(ON.id('toggle5')); + await toggle1.click(); + await toggle2.click(); + await toggle3.click(); + await toggle4.click(); + await toggle5.click(); + await driver.pressBack(); + await driver.pressBack(); + done(); + }) + + it('testToggleUiExample3', 0, async (done: Function) => { + let driver: Driver = Driver.create(); + let button_list = await driver.findComponent(ON.text('Toggle', MatchPattern.CONTAINS)); + expect(button_list === null).assertFalse(); + await button_list.click(); + let str = await getResourceString($r('app.string.Sample')); + let button_search = await driver.findComponent(ON.text(str, MatchPattern.CONTAINS)); + expect(button_search === null).assertFalse(); + await button_search.click(); + let message: Component = await driver.findComponent(ON.id('message')); + expect(await message.getText() === 'Bluetooth Mode: off').assertTrue(); + let toggle: Component = await driver.findComponent(ON.id('toggle')); + await toggle.click(); + expect(await message.getText() === 'Bluetooth Mode: on').assertTrue(); + await driver.pressBack(); + await driver.pressBack(); + done(); + }) + }) +} \ No newline at end of file diff --git a/ArkUISample/ChooseComponent/entry/src/ohosTest/ets/test/List.test.ets b/ArkUISample/ChooseComponent/entry/src/ohosTest/ets/test/List.test.ets new file mode 100644 index 0000000000000000000000000000000000000000..b702cb892d42ccb442e67abafa97484d540b599c --- /dev/null +++ b/ArkUISample/ChooseComponent/entry/src/ohosTest/ets/test/List.test.ets @@ -0,0 +1,22 @@ +/* + * Copyright (c) 2024 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import IndexTest from './Index.test'; +import abilityTest from './Ability.test'; + +export default function testsuite() { + abilityTest(); + IndexTest(); +} \ No newline at end of file diff --git a/ArkUISample/ChooseComponent/entry/src/ohosTest/module.json5 b/ArkUISample/ChooseComponent/entry/src/ohosTest/module.json5 new file mode 100644 index 0000000000000000000000000000000000000000..5f63462032245655b8df990c83c5d7312015c089 --- /dev/null +++ b/ArkUISample/ChooseComponent/entry/src/ohosTest/module.json5 @@ -0,0 +1,27 @@ +/* + * Copyright (c) 2024 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +{ + "module": { + "name": "entry_test", + "type": "feature", + "deviceTypes": [ + "default", + "tablet" + ], + "deliveryWithInstall": true, + "installationFree": false + } +} diff --git a/ArkUISample/ChooseComponent/entry/src/test/List.test.ets b/ArkUISample/ChooseComponent/entry/src/test/List.test.ets new file mode 100644 index 0000000000000000000000000000000000000000..ab6445db05608a5b7f851a85add24f32b890b0f8 --- /dev/null +++ b/ArkUISample/ChooseComponent/entry/src/test/List.test.ets @@ -0,0 +1,20 @@ +/* + * Copyright (c) 2024 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import localUnitTest from './LocalUnit.test'; + +export default function testsuite() { + localUnitTest(); +} \ No newline at end of file diff --git a/ArkUISample/ChooseComponent/entry/src/test/LocalUnit.test.ets b/ArkUISample/ChooseComponent/entry/src/test/LocalUnit.test.ets new file mode 100644 index 0000000000000000000000000000000000000000..4b7b4eb2ff9627c7184e386fe88c2ba1b507f905 --- /dev/null +++ b/ArkUISample/ChooseComponent/entry/src/test/LocalUnit.test.ets @@ -0,0 +1,48 @@ +/* + * Copyright (c) 2024 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { 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/ArkUISample/ChooseComponent/hvigor/hvigor-config.json5 b/ArkUISample/ChooseComponent/hvigor/hvigor-config.json5 new file mode 100644 index 0000000000000000000000000000000000000000..0df4e83ad09f9c4378b3d49faeeaf118df8bc59c --- /dev/null +++ b/ArkUISample/ChooseComponent/hvigor/hvigor-config.json5 @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2024 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +{ + "modelVersion": "5.0.1", + "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/ArkUISample/ChooseComponent/hvigorfile.ts b/ArkUISample/ChooseComponent/hvigorfile.ts new file mode 100644 index 0000000000000000000000000000000000000000..662a6284a1c4416b603fa1da8b52fffa406d70c2 --- /dev/null +++ b/ArkUISample/ChooseComponent/hvigorfile.ts @@ -0,0 +1,21 @@ +/* + * Copyright (c) 2024 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { 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/ArkUISample/ChooseComponent/oh-package.json5 b/ArkUISample/ChooseComponent/oh-package.json5 new file mode 100644 index 0000000000000000000000000000000000000000..936cf43ead6c6ae132fc8169d8ffb96fcd8e6fa6 --- /dev/null +++ b/ArkUISample/ChooseComponent/oh-package.json5 @@ -0,0 +1,25 @@ +/* + * Copyright (c) 2024 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +{ + "modelVersion": "5.0.1", + "description": "Please describe the basic information.", + "dependencies": { + }, + "devDependencies": { + "@ohos/hypium": "1.0.19", + "@ohos/hamock": "1.0.0" + } +} diff --git a/ArkUISample/ChooseComponent/screenshots/device/image1.png b/ArkUISample/ChooseComponent/screenshots/device/image1.png new file mode 100644 index 0000000000000000000000000000000000000000..601206d1d753a54f606bdd9f1df32c6e755b31ac Binary files /dev/null and b/ArkUISample/ChooseComponent/screenshots/device/image1.png differ diff --git a/ArkUISample/ChooseComponent/screenshots/device/image2.png b/ArkUISample/ChooseComponent/screenshots/device/image2.png new file mode 100644 index 0000000000000000000000000000000000000000..eb04f65c824dde144cfd7c34adcb28bac6166832 Binary files /dev/null and b/ArkUISample/ChooseComponent/screenshots/device/image2.png differ diff --git a/ArkUISample/ChooseComponent/screenshots/device/image3.png b/ArkUISample/ChooseComponent/screenshots/device/image3.png new file mode 100644 index 0000000000000000000000000000000000000000..29f949276660bf307aeecd7cbcc493998d2d9aa3 Binary files /dev/null and b/ArkUISample/ChooseComponent/screenshots/device/image3.png differ diff --git a/ArkUISample/ScrollableComponent/.gitignore b/ArkUISample/ScrollableComponent/.gitignore new file mode 100644 index 0000000000000000000000000000000000000000..d2ff20141ceed86d87c0ea5d99481973005bab2b --- /dev/null +++ b/ArkUISample/ScrollableComponent/.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/ArkUISample/ScrollableComponent/AppScope/app.json5 b/ArkUISample/ScrollableComponent/AppScope/app.json5 new file mode 100644 index 0000000000000000000000000000000000000000..92ed3a36e833607bc64578b181c20330a75dafe2 --- /dev/null +++ b/ArkUISample/ScrollableComponent/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.scrollablecomponent", + "vendor": "example", + "versionCode": 1000000, + "versionName": "1.0.0", + "icon": "$media:app_icon", + "label": "$string:app_name" + } +} diff --git a/ArkUISample/ScrollableComponent/AppScope/resources/base/element/string.json b/ArkUISample/ScrollableComponent/AppScope/resources/base/element/string.json new file mode 100644 index 0000000000000000000000000000000000000000..0f965de3af08def5019fc97d5107ecd98928fd97 --- /dev/null +++ b/ArkUISample/ScrollableComponent/AppScope/resources/base/element/string.json @@ -0,0 +1,8 @@ +{ + "string": [ + { + "name": "app_name", + "value": "ScrollableComponent" + } + ] +} diff --git a/ArkUISample/ScrollableComponent/AppScope/resources/base/media/app_icon.png b/ArkUISample/ScrollableComponent/AppScope/resources/base/media/app_icon.png new file mode 100644 index 0000000000000000000000000000000000000000..a39445dc87828b76fed6d2ec470dd455c45319e3 Binary files /dev/null and b/ArkUISample/ScrollableComponent/AppScope/resources/base/media/app_icon.png differ diff --git a/ArkUISample/ScrollableComponent/README_zh.md b/ArkUISample/ScrollableComponent/README_zh.md new file mode 100644 index 0000000000000000000000000000000000000000..36e52b989279993a3782f208316cf271954d1e1f --- /dev/null +++ b/ArkUISample/ScrollableComponent/README_zh.md @@ -0,0 +1,152 @@ +# ArkUI使用滚动类指南文档示例 + +### 介绍 + +本示例通过使用[ArkUI指南文档](https://gitee.com/openharmony/docs/tree/master/zh-cn/application-dev/ui)中各场景的开发示例,展示在工程中,帮助开发者更好地理解ArkUI提供的组件及组件属性并合理使用。该工程中展示的代码详细描述可查如下链接: + +1. [创建列表 (List)](https://gitee.com/openharmony/docs/blob/OpenHarmony-5.1.0-Release/zh-cn/application-dev/ui/arkts-layout-development-create-list.md)。 +2. [创建弧形列表 (ArcList)](https://gitee.com/openharmony/docs/blob/OpenHarmony-5.1.0-Release/zh-cn/application-dev/ui/arkts-layout-development-create-arclist.md)(圆形屏幕推荐使用) +3. [创建网格 (Grid/GridItem)](https://gitee.com/openharmony/docs/blob/OpenHarmony-5.1.0-Release/zh-cn/application-dev/ui/arkts-layout-development-create-grid.md)。 +4. [创建瀑布流 (WaterFlow)](https://gitee.com/openharmony/docs/blob/OpenHarmony-5.1.0-Release/zh-cn/application-dev/ui/arkts-layout-development-create-waterflow.md) +5. [创建轮播 (Swiper)](https://gitee.com/openharmony/docs/blob/OpenHarmony-5.1.0-Release/zh-cn/application-dev/ui/arkts-layout-development-create-looping.md)。 +6. [创建弧形轮播 (ArcSwiper)](https://gitee.com/openharmony/docs/blob/OpenHarmony-5.1.0-Release/zh-cn/application-dev/ui/arkts-layout-development-arcswiper.md)(圆形屏幕推荐使用) +7. [选项卡 (Tabs)](https://gitee.com/openharmony/docs/blob/OpenHarmony-5.1.0-Release/zh-cn/application-dev/ui/arkts-navigation-tabs.md) +### 效果预览 + +| 首页 | 列表类组件目录 | 列表中显示数据示例 | +|------------------------------------|------------------------------------|------------------------------------| +| ![](screenshots/device/image1.png) | ![](screenshots/device/image2.png) | ![](screenshots/device/image3.png) | + +### 使用说明 + +1. 在主界面,可以点击对应卡片,选择需要参考的组件示例。 + +2. 在组件目录选择详细的示例参考。 + +3. 进入示例界面,查看参考示例。 + +4. 通过自动测试框架可进行测试及维护。 + +### 工程目录 +``` +entry/src/main/ets/ +|---entryability +|---pages +| |---arcList //弧形列表 +| | |---ArcListAcrScrollBar.ets +| | |---ArcListArcIndexerBar.ets +| | |---arcListBuiltInScrollerBar.ets +| | |---ArcListContents.ets +| | |---ArcListCrown.ets +| | |---ArcListShow.ets +| | |---ArcListSideSlip.ets +| | |---ArcListStyles.ets +| | |---ArcLongList.ets +| | |---index.ets +| |---arcSwiper //弧形轮播 +| | |---ArcSwiperAction.ets +| | |---ArcSwiperHorizontal.ets +| | |---ArcSwiperSideSlip.ets +| | |---ArcSwiperStyles.ets +| | |---ArcSwiperToggle.ets +| | |---ArcSwiperVertical.ets +| | |---index.ets +| |---grid //列表 +| | |---DataInGrid.ets +| | |---GridDataSource.ets +| | |---GridLayout.ets +| | |---GridScrollbar.ets +| | |---GridSideToSide.ets +| | |---index.ets +| | |---LongGrid.ets +| | |---ScrollableGrid.ets +| | |---ScrollPosition.ets +| |---list //网格 +| | |---AddListItem.ets +| | |---CollapseAndExpand.ets +| | |---ControlledScrollPositionList.ets +| | |---CustomListStyle.ets +| | |---DataInList.ets +| | |---DeleteListItem.ets +| | |---GroupedList.ets +| | |---index.ets +| | |---ListChatRoom.ets +| | |---ListDataSource.ets +| | |---ListIteration.ets +| | |---ListLayout.ets +| | |---LongList.ets +| | |---ResponsiveScrollPositionList.ets +| | |---StickyHeaderList.ets +| | |---SwipeListItem.ets +| | |---TaggedListItems.ets +| |---swiper //轮播 +| | |---index.ets +| | |---SwiperAndTabsLinkage.ets +| | |---SwiperAutoPlay.ets +| | |---SwiperCustomAnimation.ets +| | |---SwiperDirection.ets +| | |---SwiperIgnoreComponentSize.ets +| | |---SwiperIndicatorStyle.ets +| | |---SwiperLoop.ets +| | |---SwiperMultiPage.ets +| | |---SwiperPageSwitchMethod.ets +| |---tabs //选项卡 +| | |---AgeFriendlyTabs.ets +| | |---BottomTabBar.ets +| | |---ContentWillChange.ets +| | |---CustomTabBar.ets +| | |---FixedTabBar.ets +| | |---index.ets +| | |---ScrollableTabBar.ets +| | |---SideTabBar.ets +| | |---SwipeLockedTabBar.ets +| | |---TabsLayout.ets +| | |---TopTabBar.ets +| |---waterFlow //瀑布流 +| | |---AgeFriendlyTabs.ets +| | |---BottomTabBar.ets +| | |---ContentWillChange.ets +| | |---CustomTabBar.ets +| | |---FixedTabBar.ets +| | |---index.ets +| | |---WaterFlowDataSource.ets +| | |---WaterFlowDynamicSwitchover.ets +| | |---WaterFlowGroupingMixing.ets +| | |---WaterFlowInfiniteScrolling.ets +| | |---WaterFlowInfiniteScrollingEarly.ets +|---pages +| |---Index.ets // 应用主页面 +entry/src/ohosTest/ +|---ets +| |---index.test.ets // 示例代码测试代码 +``` + +### 相关权限 + +不涉及。 + +### 依赖 + +不涉及。 + +### 约束与限制 + +1. 本示例仅支持标准系统上运行,支持设备:华为手机。 + +2. HarmonyOS系统:HarmonyOS 5.1.0 Release及以上。 + +3. DevEco Studio版本:DevEco Studio 5.1.0 Release及以上。 + +4. HarmonyOS SDK版本:HarmonyOS 5.1.0 Release及以上。 + +### 下载 + +如需单独下载本工程,执行如下命令: + +```` +git init +git config core.sparsecheckout true +echo ArkUIDocSample/ScrollableComponent > .git/info/sparse-checkout +git remote add origin https://gitee.com/harmonyos_samples/guide-snippets.git +git pull origin master +```` \ No newline at end of file diff --git a/ArkUISample/ScrollableComponent/build-profile.json5 b/ArkUISample/ScrollableComponent/build-profile.json5 new file mode 100644 index 0000000000000000000000000000000000000000..407b1cd9c40170066f910968ee92fae261ef8758 --- /dev/null +++ b/ArkUISample/ScrollableComponent/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", + "compatibleSdkVersion": "5.1.0(18)", + "targetSdkVersion": "5.1.0(18)", + "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/ArkUISample/ScrollableComponent/code-linter.json5 b/ArkUISample/ScrollableComponent/code-linter.json5 new file mode 100644 index 0000000000000000000000000000000000000000..28586467ee7a761c737d8654a73aed6fddbc3c71 --- /dev/null +++ b/ArkUISample/ScrollableComponent/code-linter.json5 @@ -0,0 +1,35 @@ +/* + * Copyright (c) 2025 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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": { + } +} \ No newline at end of file diff --git a/ArkUISample/ScrollableComponent/entry/.gitignore b/ArkUISample/ScrollableComponent/entry/.gitignore new file mode 100644 index 0000000000000000000000000000000000000000..e2713a2779c5a3e0eb879efe6115455592caeea5 --- /dev/null +++ b/ArkUISample/ScrollableComponent/entry/.gitignore @@ -0,0 +1,6 @@ +/node_modules +/oh_modules +/.preview +/build +/.cxx +/.test \ No newline at end of file diff --git a/ArkUISample/ScrollableComponent/entry/build-profile.json5 b/ArkUISample/ScrollableComponent/entry/build-profile.json5 new file mode 100644 index 0000000000000000000000000000000000000000..e7569e3056e27af38e9991b7ea73ec10f3ba8a05 --- /dev/null +++ b/ArkUISample/ScrollableComponent/entry/build-profile.json5 @@ -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. + */ + +{ + "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/ArkUISample/ScrollableComponent/entry/hvigorfile.ts b/ArkUISample/ScrollableComponent/entry/hvigorfile.ts new file mode 100644 index 0000000000000000000000000000000000000000..e4f43d54667f8327c367c8096bd08bb8c75aff54 --- /dev/null +++ b/ArkUISample/ScrollableComponent/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. */ +} diff --git a/ArkUISample/ScrollableComponent/entry/obfuscation-rules.txt b/ArkUISample/ScrollableComponent/entry/obfuscation-rules.txt new file mode 100644 index 0000000000000000000000000000000000000000..272efb6ca3f240859091bbbfc7c5802d52793b0b --- /dev/null +++ b/ArkUISample/ScrollableComponent/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/ArkUISample/ScrollableComponent/entry/oh-package.json5 b/ArkUISample/ScrollableComponent/entry/oh-package.json5 new file mode 100644 index 0000000000000000000000000000000000000000..c9cb6c8174858277c9b0d465a51547dcab16d5ff --- /dev/null +++ b/ArkUISample/ScrollableComponent/entry/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. + */ + +{ + "name": "entry", + "version": "1.0.0", + "description": "Please describe the basic information.", + "main": "", + "author": "", + "license": "", + "dependencies": {} +} + diff --git a/ArkUISample/ScrollableComponent/entry/src/main/ets/common/Card.ets b/ArkUISample/ScrollableComponent/entry/src/main/ets/common/Card.ets new file mode 100644 index 0000000000000000000000000000000000000000..8eef9a0fc9b2138668c3048c8076d9db3e453c85 --- /dev/null +++ b/ArkUISample/ScrollableComponent/entry/src/main/ets/common/Card.ets @@ -0,0 +1,137 @@ +/* + * Copyright (c) 2025 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +@Component +export struct CompletedRoutableCard { + @Prop + symbol: Resource = $r('sys.symbol.label'); + @Prop + @Require + title: string; + @Prop + @Require + description: ResourceStr; + + build() { + Card({ verticalAlign: VerticalAlign.Top }) { + Button({ type: ButtonType.Circle }) { + SymbolGlyph(this.symbol) + .fontColor(['#fff']) + .fontSize(16) + } + .borderRadius(14) + + Column({ space: 8 }) { + Text(this.title) + .fontColor($r('sys.color.font_primary')) + + Text(this.description) + .fontColor($r('sys.color.font_secondary')) + .fontSize($r('sys.float.Body_S')) + } + .alignItems(HorizontalAlign.Start) + .layoutWeight(1) + } + } +} + +@Component +export struct Card { + @Prop + verticalAlign: VerticalAlign = VerticalAlign.Center; + @BuilderParam + content: () => void; + + build() { + Row({ space: 12 }) { + this.content() + } + .alignItems(this.verticalAlign) + .backgroundColor('#fff') + .borderRadius(12) + .padding(12) + .width('100%') + } +} + +@Component +export struct RoutableCard { + @Prop + icon: Resource = $r('sys.symbol.label'); + @Prop + @Require + title: ResourceStr; + + build() { + Card() { + Button({ type: ButtonType.Circle }) { + SymbolGlyph(this.icon) + .fontColor(['#fff']) + .fontSize(16) + } + .borderRadius(14) + + Text(this.title) + .fontColor($r('sys.color.font_primary')) + .minFontSize(12) + .maxFontSize(16) + .maxLines(1) + .textOverflow({ overflow: TextOverflow.Ellipsis }) + + Blank() + + Button({ type: ButtonType.Normal, buttonStyle: ButtonStyleMode.TEXTUAL }) { + SymbolGlyph($r('sys.symbol.chevron_right')) + .fontSize(18) + .fontColor([$r('sys.color.font_secondary')]) + } + } + } +} + +@Component +export struct ComponentCard { + @Prop + @Require + title: ResourceStr; + @BuilderParam content: () => void; + @Prop + description?: ResourceStr; + + build() { + Column({ space: 8 }) { + Text(this.title) + .fontSize(14) + .fontColor('#666') + Row({ space: 12}) { + this.content(); + } + if (this.description) { + Text(this.description) + .backgroundColor('#eee') + .borderRadius(4) + .padding(4) + .fontSize(12) + .fontColor('#999') + .width('100%') + } + } + .alignItems(HorizontalAlign.Start) + .backgroundColor('#fff') + .borderRadius(12) + .padding(12) + .width('100%') + } +} \ No newline at end of file diff --git a/ArkUISample/ScrollableComponent/entry/src/main/ets/common/Route.ets b/ArkUISample/ScrollableComponent/entry/src/main/ets/common/Route.ets new file mode 100644 index 0000000000000000000000000000000000000000..da3d2cc3284d5cba7d3b667a3c1c61f5c6b5a9dc --- /dev/null +++ b/ArkUISample/ScrollableComponent/entry/src/main/ets/common/Route.ets @@ -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. + */ + +export interface Route { + title: string ; + name: string; + items?: Route[]; + description?: ResourceStr; +} \ No newline at end of file diff --git a/ArkUISample/ScrollableComponent/entry/src/main/ets/common/resource.ets b/ArkUISample/ScrollableComponent/entry/src/main/ets/common/resource.ets new file mode 100644 index 0000000000000000000000000000000000000000..e240a1079ad09a0f19080b49b57a6a0720416e6c --- /dev/null +++ b/ArkUISample/ScrollableComponent/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 ResourceManager { + public resourceToString(resource: Resource): string { + return getContext(this).resourceManager.getStringSync(resource); + } +} + +// 默认导出let +let resourceToStringManager = new ResourceManager(); + +export default resourceToStringManager as ResourceManager; \ No newline at end of file diff --git a/ArkUISample/ScrollableComponent/entry/src/main/ets/entryability/EntryAbility.ets b/ArkUISample/ScrollableComponent/entry/src/main/ets/entryability/EntryAbility.ets new file mode 100644 index 0000000000000000000000000000000000000000..edc2839f203ba057c186e19b0cbbbf80c8faa8b3 --- /dev/null +++ b/ArkUISample/ScrollableComponent/entry/src/main/ets/entryability/EntryAbility.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. + */ + +import { AbilityConstant, ConfigurationConstant, UIAbility, Want } from '@kit.AbilityKit'; +import { hilog } from '@kit.PerformanceAnalysisKit'; +import { window } from '@kit.ArkUI'; + +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(0x0000, 'testTag', '%{public}s', 'Ability onCreate'); + } + + onDestroy(): void { + hilog.info(0x0000, 'testTag', '%{public}s', 'Ability onDestroy'); + } + + onWindowStageCreate(windowStage: window.WindowStage): void { + // Main window is created, set main page for this ability + hilog.info(0x0000, 'testTag', '%{public}s', 'Ability onWindowStageCreate'); + + windowStage.loadContent('pages/Index', (err) => { + if (err.code) { + hilog.error(0x0000, 'testTag', 'Failed to load the content. Cause: %{public}s', JSON.stringify(err) ?? ''); + return; + } + hilog.info(0x0000, 'testTag', 'Succeeded in loading the content.'); + }); + } + + onWindowStageDestroy(): void { + // Main window is destroyed, release UI related resources + hilog.info(0x0000, 'testTag', '%{public}s', 'Ability onWindowStageDestroy'); + } + + onForeground(): void { + // Ability has brought to foreground + hilog.info(0x0000, 'testTag', '%{public}s', 'Ability onForeground'); + } + + onBackground(): void { + // Ability has back to background + hilog.info(0x0000, 'testTag', '%{public}s', 'Ability onBackground'); + } +} \ No newline at end of file diff --git a/ArkUISample/ScrollableComponent/entry/src/main/ets/entrybackupability/EntryBackupAbility.ets b/ArkUISample/ScrollableComponent/entry/src/main/ets/entrybackupability/EntryBackupAbility.ets new file mode 100644 index 0000000000000000000000000000000000000000..b1e212947256c5533c7b06285a597c94f840a6e3 --- /dev/null +++ b/ArkUISample/ScrollableComponent/entry/src/main/ets/entrybackupability/EntryBackupAbility.ets @@ -0,0 +1,27 @@ +/* + * Copyright (c) 2025 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { hilog } from '@kit.PerformanceAnalysisKit'; +import { BackupExtensionAbility, BundleVersion } from '@kit.CoreFileKit'; + +export default class EntryBackupAbility extends BackupExtensionAbility { + async onBackup() { + hilog.info(0x0000, 'testTag', 'onBackup ok'); + } + + async onRestore(bundleVersion: BundleVersion) { + hilog.info(0x0000, 'testTag', 'onRestore ok %{public}s', JSON.stringify(bundleVersion)); + } +} \ No newline at end of file diff --git a/ArkUISample/ScrollableComponent/entry/src/main/ets/pages/Index.ets b/ArkUISample/ScrollableComponent/entry/src/main/ets/pages/Index.ets new file mode 100644 index 0000000000000000000000000000000000000000..be9cdd168523a39eec9f2753548c165d168b2da0 --- /dev/null +++ b/ArkUISample/ScrollableComponent/entry/src/main/ets/pages/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 { gridDestination, GRID_ROUTE_PREFIX } from './grid'; +import { List_ROUTE_PREFIX, listDestination } from './list/Index'; +import { LengthMetrics } from '@kit.ArkUI'; +import { Route } from '../common/Route'; +import { RoutableCard } from '../common/Card'; +import { swiperDestination, SWIPER_ROUTE_PREFIX } from './swiper'; +import { waterFlowDestination, WATERFLOW_ROUTE_PREFIX } from './waterFlow'; +import { tabsDestination, TABS_ROUTE_PREFIX } from './tabs'; +import { arcSwiperDestination, ARCSWIPER_ROUTE_PREFIX } from './arcSwiper'; +import { arcListDestination, ARCLIST_ROUTE_PREFIX } from './arcList'; +import resource from '../common/resource'; + +const routes: Route[] = [ + { + title: resource.resourceToString($r('app.string.pageIndex_List')), + name: List_ROUTE_PREFIX + }, + { + title: resource.resourceToString($r('app.string.pageIndex_ArcList')), + name: ARCLIST_ROUTE_PREFIX + }, + { + title: resource.resourceToString($r('app.string.pageIndex_Grid')), + name: GRID_ROUTE_PREFIX + }, + { + title: resource.resourceToString($r('app.string.pageIndex_WaterFlow')), + name: WATERFLOW_ROUTE_PREFIX + }, + { + title: resource.resourceToString($r('app.string.pageIndex_Swiper')), + name: SWIPER_ROUTE_PREFIX + }, + { + title: resource.resourceToString($r('app.string.pageIndex_ArcSwiper')), + name: ARCSWIPER_ROUTE_PREFIX + }, + { + title: resource.resourceToString($r('app.string.pageIndex_Tabs')), + name: TABS_ROUTE_PREFIX + } +]; + +@Builder +function destination(name: string) { + if (name.startsWith(List_ROUTE_PREFIX)) { + listDestination(name); + } else if (name.startsWith(GRID_ROUTE_PREFIX)) { + gridDestination(name); + } else if (name.startsWith(SWIPER_ROUTE_PREFIX)) { + swiperDestination(name); + } else if (name.startsWith(ARCSWIPER_ROUTE_PREFIX)) { + arcSwiperDestination(name); + } else if (name.startsWith(TABS_ROUTE_PREFIX)) { + tabsDestination(name); + } else if (name.startsWith(WATERFLOW_ROUTE_PREFIX)) { + waterFlowDestination(name); + } else if (name.startsWith(ARCLIST_ROUTE_PREFIX)) { + arcListDestination(name); + } +} + +@Entry +@Component +struct Index { + @State condition: string = ''; + @Provide pathStack: NavPathStack = new NavPathStack(); + + getFilteredRoutes(): Route[] { + if (!this.condition) { + return routes; + } + return routes.filter((route: Route) => { + return route.title.includes(this.condition); + }) + } + + @LocalBuilder + Title() { + Column() { + Search({ value: this.condition }) + .onChange(value => { + this.condition = value; + }) + .margin({ start: LengthMetrics.vp(16), end: LengthMetrics.vp(16) }) + } + .justifyContent(FlexAlign.Center) + .height('100%') + } + + build() { + Navigation(this.pathStack) { + List({ space: 12 }) { + ForEach(this.getFilteredRoutes(), (route: Route) => { + ListItem() { + RoutableCard({ title: route.title }) + } + .width('100%') + .onClick(() => { + this.pathStack.pushPath({ name: route.name }); + }) + }) + } + .padding({ start: LengthMetrics.vp(16), end: LengthMetrics.vp(16) }) + .contentStartOffset(56) + .height('100%') + .width('100%') + } + .backgroundColor('#f1f3f5') + .title({ builder: this.Title, height: 56 }, { + backgroundBlurStyle: BlurStyle.COMPONENT_THICK, + barStyle: BarStyle.STACK + }) + .navDestination(destination) + } +} \ No newline at end of file diff --git a/ArkUISample/ScrollableComponent/entry/src/main/ets/pages/arcList/ArcListAcrScrollBar.ets b/ArkUISample/ScrollableComponent/entry/src/main/ets/pages/arcList/ArcListAcrScrollBar.ets new file mode 100644 index 0000000000000000000000000000000000000000..cc00ad82b6345c21a1ad6e98e881a4b1ec4cfabd --- /dev/null +++ b/ArkUISample/ScrollableComponent/entry/src/main/ets/pages/arcList/ArcListAcrScrollBar.ets @@ -0,0 +1,139 @@ +/* + * Copyright (c) 2025 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 { + ArcList, + ArcListItem, + ArcListAttribute, + ArcListItemAttribute, + LengthMetrics, + ArcScrollBar, +} from '@kit.ArkUI'; +import { ComponentCard } from '../../common/Card'; + +@Entry +@Component +export struct ArcListAcrScrollBar { + private arcListScroller: Scroller = new Scroller(); + + build() { + NavDestination() { + Column({ space: 12 }) { + ComponentCard({ title: $r('app.string.ArcListAcrScrollBar_title') }) { + ArcList({ scroller: this.arcListScroller }) { + ArcListItem() { + Row() { + Image($r('app.media.wlan')).width('99px').height('99px') + .borderRadius('50px').margin({ left: 7 }) + Column() { + Text($r('app.string.ArcListStyles_waln')).fontSize('38px').fontColor('#FFFFFFFF') + Text($r('app.string.ArcListStyles_open')).fontSize('20px').fontColor('#FFFFFFFF') + }.width('190px') + + Image($r('app.media.ic_settings_arrow')).width('92px').height('92px') + .borderRadius('50px') + } + } + .borderRadius('65px') + .width('414px') + .height('129px') + .backgroundColor('#26FFFFFF') + + ArcListItem() { + Row() { + Image($r('app.media.blueTooth')).width('99px').height('99px') + .borderRadius('50px').margin({ left: 7 }) + Column() { + Text($r('app.string.ArcListStyles_blue')).fontSize('38px').fontColor('#FFFFFFFF') + Text($r('app.string.ArcListStyles_open')).fontSize('20px').fontColor('#FFFFFFFF') + }.width('190px') + + Image($r('app.media.ic_settings_arrow')).width('92px').height('92px') + .borderRadius('50px') + } + } + .borderRadius('65px') + .width('414px') + .height('129px') + .backgroundColor('#26FFFFFF') + + ArcListItem() { + Row() { + Image($r('app.media.mobileData')).width('99px').height('99px') + .borderRadius('50px').margin({ left: 7 }) + Column() { + Text($r('app.string.ArcListStyles_net')).fontSize('38px').fontColor('#FFFFFFFF') + }.width('190px') + + Image($r('app.media.ic_settings_arrow')).width('92px').height('92px') + .borderRadius('50px') + } + } + .borderRadius('65px') + .width('414px') + .height('129px') + .backgroundColor('#26FFFFFF') + + ArcListItem() { + Row() { + Image($r('app.media.ic_settings_more_connections')).width('99px').height('99px') + .borderRadius('50px').margin({ left: 7 }) + Column() { + Text($r('app.string.ArcListStyles_connect')).fontSize('38px').fontColor('#FFFFFFFF') + }.width('190px') + + Image($r('app.media.ic_settings_arrow')).width('92px').height('92px') + .borderRadius('50px') + } + } + .borderRadius('65px') + .width('414px') + .height('129px') + .backgroundColor('#26FFFFFF') + + ArcListItem() { + Row() { + Image($r('app.media.displayAndBrightness')).width('99px').height('99px') + .borderRadius('50px').margin({ left: 7 }) + Column() { + Text($r('app.string.ArcListStyles_light')).fontSize('38px').fontColor('#FFFFFFFF') + }.width('190px') + + Image($r('app.media.ic_settings_arrow')).width('92px').height('92px') + .borderRadius('50px') + } + } + .borderRadius('65px') + .width('414px') + .height('129px') + .backgroundColor('#26FFFFFF') + } + .width('466px') + .height('466px') + .space(LengthMetrics.px(10)) + .borderRadius('233px') + .backgroundColor(Color.Black) + + ArcScrollBar({ scroller: this.arcListScroller }) + } + } + .width('100%') + .height('100%') + .padding({ left: 12, right: 12 }) + } + .backgroundColor('#f1f2f3') + .title($r('app.string.ArcListAcrScrollBar_title')) + } +} \ No newline at end of file diff --git a/ArkUISample/ScrollableComponent/entry/src/main/ets/pages/arcList/ArcListArcIndexerBar.ets b/ArkUISample/ScrollableComponent/entry/src/main/ets/pages/arcList/ArcListArcIndexerBar.ets new file mode 100644 index 0000000000000000000000000000000000000000..a6ac032409c9cd1811c02123ad28ef2e424a4a65 --- /dev/null +++ b/ArkUISample/ScrollableComponent/entry/src/main/ets/pages/arcList/ArcListArcIndexerBar.ets @@ -0,0 +1,155 @@ +/* + * Copyright (c) 2025 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 { ArcList, ArcListAttribute, ArcListItemAttribute, ArcListItem, LengthMetrics } from '@kit.ArkUI'; +import { ColorMetrics, ComponentContent } from '@ohos.arkui.node'; +import { util } from '@kit.ArkTS'; +import { ArcAlphabetIndexer, ArcAlphabetIndexerAttribute } from '@ohos.arkui.ArcAlphabetIndexer'; +import { ComponentCard } from '../../common/Card'; + +class Contact { + key: string = util.generateRandomUUID(true); + name: string; + firstChar: string; + + constructor(name: string, firstChar: string) { + this.name = name; + this.firstChar = firstChar; + } +} +@Builder +function buildText() { + Column() { + Text('Contacts') + .fontColor('#FFFFFF') + .fontSize('19fp') + + } +} + +@Entry +@Component +export struct ArcListArcIndexerBar { + + @State contacts: Array = [ + new Contact('阿哈', 'A'), + new Contact('贝贝', 'B'), + new Contact('彩彩', 'C'), + new Contact('东东', 'D'), + new Contact('嗯嗯', 'E'), + new Contact('芳芳', 'F'), + new Contact('哥哥', 'G'), + new Contact('哈哈', 'H'), + new Contact('吉吉', 'J'), + new Contact('可可', 'K'), + new Contact('乐乐', 'L'), + new Contact('妹妹', 'M'), + new Contact('妮妮', 'N'), + new Contact('哦豁', 'O'), + new Contact('胖胖', 'P'), + new Contact('琪琪', 'Q'), + new Contact('然然', 'R'), + new Contact('叔叔', 'S'), + new Contact('天天', 'T'), + ]; + private scrollerForList: Scroller = new Scroller(); + private watchSize: string = '600px'; // 手表默认宽高:233*233 + private fullValue: string[] = [ + '#', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'J', 'K', 'L', 'M', 'N', + 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z' + ]; + @State indexerIndex: number = 0; + + context: UIContext = this.getUIContext(); + tabBar1: ComponentContent = new ComponentContent(this.context, wrapBuilder(buildText)); + + build() { + NavDestination() { + Column({ space: 12 }) { + ComponentCard({ title: $r('app.string.ArcListArcIndexerBar_title') }) { + Stack() { + ArcList({ initialIndex: 0, header:this.tabBar1, scroller:this.scrollerForList }) { + ForEach(this.contacts, (item: Contact) => { + ArcListItem() { + Row() { + Text(item.firstChar) + .textAlign(TextAlign.Center) + .width(30) + .height(30) + .margin(10) + .backgroundColor('#FF9CC998') + .borderRadius(20) + Text(item.name).fontSize('38px').fontColor('#FFFFFFFF') + } + .width('100%') + .justifyContent(FlexAlign.Start) + } + .borderRadius('65px') + .width('370px') + .height('130px') + .backgroundColor('#26FFFFFF') + }, (item: Contact) => JSON.stringify(item)) + } + .space(LengthMetrics.px(10)) + .scrollBar(BarState.Off) + .width(this.watchSize) + .height(this.watchSize) + .borderRadius(this.watchSize) + .backgroundColor(Color.Black) + .onScrollIndex((firstIndex: number, lastIndex: number, centerIndex: number) => { + this.indexerIndex = centerIndex + 1; + }) + + ArcAlphabetIndexer({ arrayValue: this.fullValue, selected: this.indexerIndex}) + .autoCollapse(true) + .width(this.watchSize) + .height(this.watchSize) + .usePopup(false) + .selected(this.indexerIndex!!) + .onSelect((index: number) => { + this.indexerIndex = index + this.scrollerForList.scrollToIndex(this.indexerIndex - 1) + }) + .hitTestBehavior(HitTestMode.Transparent) + .selectedColor(ColorMetrics.resourceColor(0xFFFFFF)) + .selectedBackgroundColor(ColorMetrics.resourceColor(0x1F71FF)) + .color(ColorMetrics.resourceColor(0xFFFFFF)) + .popupColor(ColorMetrics.resourceColor(0xFFFFFF)) + .popupBackground(ColorMetrics.resourceColor(0xD8404040)) + .itemSize(LengthMetrics.px(12)) + .selectedFont({ + size: '11.0fp', + style: FontStyle.Normal, + weight: 500, + family: 'HarmonyOS Sans' + }) + .font({ + size: '11.0fp', + style: FontStyle.Normal, + weight: 500, + family: 'HarmonyOS Sans' + }) + + }.width('600px') + } + } + .width('100%') + .height('100%') + .padding({ left: 12, right: 12 }) + } + .backgroundColor('#f1f2f3') + .title($r('app.string.ArcListArcIndexerBar_title')) + } +} diff --git a/ArkUISample/ScrollableComponent/entry/src/main/ets/pages/arcList/ArcListContents.ets b/ArkUISample/ScrollableComponent/entry/src/main/ets/pages/arcList/ArcListContents.ets new file mode 100644 index 0000000000000000000000000000000000000000..ed930ddd36e2ddc7fed5f0c11c2873c9552f38b1 --- /dev/null +++ b/ArkUISample/ScrollableComponent/entry/src/main/ets/pages/arcList/ArcListContents.ets @@ -0,0 +1,81 @@ +/* + * Copyright (c) 2025 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { ArcList, ArcListAttribute, ArcListItemAttribute, ArcListItem, LengthMetrics } from '@kit.ArkUI'; +import { util } from '@kit.ArkTS'; +import { ComponentCard } from '../../common/Card'; + +class Contact { + key: string = util.generateRandomUUID(true); + name: string; + icon: Resource; + + constructor(name: string, icon: Resource) { + this.name = name; + this.icon = icon; + } +} + +@Entry +@Component +export struct ArcListContents { + private contacts: Array = [ + new Contact('小红', $r('app.media.ic_contact')), + new Contact('小兰', $r('app.media.ic_contact')), + new Contact('小王', $r('app.media.ic_contact')), + new Contact('小李', $r('app.media.ic_contact')), + new Contact('小明', $r('app.media.ic_contact')) + ]; + + build() { + NavDestination() { + Column({ space: 12 }) { + ComponentCard({ title: $r('app.string.ArcListContents_title') }) { + ArcList({ initialIndex: 2 }) { + ForEach(this.contacts, (item: Contact) => { + ArcListItem() { + Row() { + Image(item.icon) + .width(40) + .height(40) + .margin(10) + .backgroundColor('#FF9CC998') + .borderRadius(20) + Text(item.name).fontSize('38px').fontColor('#FFFFFFFF') + } + .width('100%') + .justifyContent(FlexAlign.Start) + } + .borderRadius('65px') + .width('410px') + .height('130px') + .backgroundColor('#26FFFFFF') + }, (item: Contact) => JSON.stringify(item)) + } + .space(LengthMetrics.px(10)) + .width('466px') + .height('466px') + .borderRadius('233px') + .backgroundColor(Color.Black) + } + } + .width('100%') + .height('100%') + .padding({ left: 12, right: 12 }) + } + .backgroundColor('#f1f2f3') + .title($r('app.string.ArcListContents_title')) + } +} \ No newline at end of file diff --git a/ArkUISample/ScrollableComponent/entry/src/main/ets/pages/arcList/ArcListCrown.ets b/ArkUISample/ScrollableComponent/entry/src/main/ets/pages/arcList/ArcListCrown.ets new file mode 100644 index 0000000000000000000000000000000000000000..e25e75003be9b927fa36e38acb2f0ae34e43ae68 --- /dev/null +++ b/ArkUISample/ScrollableComponent/entry/src/main/ets/pages/arcList/ArcListCrown.ets @@ -0,0 +1,135 @@ +/* + * Copyright (c) 2025 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 { ColorMetrics, LengthMetrics } from '@kit.ArkUI'; +import { ArcList, ArcListItem, ArcListAttribute, ArcListItemAttribute } from '@kit.ArkUI'; +import { ComponentCard } from '../../common/Card'; + +@Builder +function buildText() { + Column() { + Text($r('app.string.ArcListCrown_set')) + .fontColor('#FFFFFF') + .fontSize('19fp') + + }.height(10) +} + +@Entry +@Component +export struct ArcListCrown { + private watchSize: string = '466px'; // 手表默认宽高:466*466 + + build() { + NavDestination() { + Column({ space: 12 }) { + ComponentCard({ title: $r('app.string.ArcListCrown_title') }) { + Stack() { + ArcList({ + initialIndex: 2, + }) { + ArcListItem() { + Text('Network').fontSize('38px').fontColor('#FFFFFFFF') + } + .borderRadius('65px') + .width('414px') + .height('50px') + .autoScale(false) + + ArcListItem() { + Row() { + Image($r('app.media.wlan')).width('80px').height('80px') + .borderRadius('50px').margin({ left: 7 }) + Column() { + Text('WLAN').fontSize('38px').fontColor('#FFFFFFFF') + Text('On').fontSize('20px').fontColor('#FFFFFFFF') + }.width('190px') + + Image($r('app.media.ic_settings_arrow')).width('80px').height('80px') + .borderRadius('50px') + } + + } + .borderRadius('65px') + .width('414px') + .height('100px') + .backgroundColor('#26FFFFFF') + + ArcListItem() { + Row() { + Image($r('app.media.mobileData')).width('80px').height('80px') + .borderRadius('50px').margin({ left: 7 }) + Column() { + Text('Bluetooth').fontSize('38px').fontColor('#FFFFFFFF') + }.width('190px') + + Image($r('app.media.ic_settings_arrow')).width('80px').height('80px') + .borderRadius('50px') + } + + } + .borderRadius('65px') + .width('414px') + .height('100px') + .backgroundColor('#26FFFFFF') + + ArcListItem() { + Text('Display').fontSize('38px').fontColor('#FFFFFFFF') + } + .borderRadius('65px') + .width('414px') + .height('50px') + .autoScale(false) + + ArcListItem() { + Row() { + Image($r('app.media.displayAndBrightness')).width('80px').height('80px') + .borderRadius('50px').margin({ left: 7 }) + Column() { + Text('Display & brightness').fontSize('38px').fontColor('#FFFFFFFF') + }.width('190px') + + Image($r('app.media.ic_settings_arrow')).width('80px').height('80px') + .borderRadius('50px') + } + } + .borderRadius('65px') + .width('414px') + .height('100px') + .backgroundColor('#26FFFFFF') + } + .space(LengthMetrics.px(10)) + .scrollBarWidth(LengthMetrics.px(10)) + .scrollBarColor(ColorMetrics.resourceColor(Color.White)) + .borderRadius(this.watchSize) + .focusable(true) + .focusOnTouch(true) + .defaultFocus(true) + } + .align(Alignment.Center) + .width(this.watchSize) + .height(this.watchSize) + .borderRadius(this.watchSize) + .backgroundColor(Color.Black) + } + } + .width('100%') + .height('100%') + .padding({ left: 12, right: 12 }) + } + .backgroundColor('#f1f2f3') + .title($r('app.string.ArcListCrown_title')) + } +} \ No newline at end of file diff --git a/ArkUISample/ScrollableComponent/entry/src/main/ets/pages/arcList/ArcListShow.ets b/ArkUISample/ScrollableComponent/entry/src/main/ets/pages/arcList/ArcListShow.ets new file mode 100644 index 0000000000000000000000000000000000000000..a46936d5cd23d715bede61ca511a2c804d486dbb --- /dev/null +++ b/ArkUISample/ScrollableComponent/entry/src/main/ets/pages/arcList/ArcListShow.ets @@ -0,0 +1,128 @@ +/* + * Copyright (c) 2025 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 { ArcList, ArcListItem, ArcListAttribute, ArcListItemAttribute, LengthMetrics, } from '@kit.ArkUI'; +import { ComponentCard } from '../../common/Card'; + +@Entry +@Component +export struct ArcListShow { + build() { + NavDestination() { + Column({ space: 12 }) { + ComponentCard({ title: $r('app.string.ArcListShow_title') }) { + ArcList({ initialIndex: 2 }) { + ArcListItem() { + Row() { + Image($r('app.media.wlan')).width('99px').height('99px') + .borderRadius('50px').margin({ left: 7 }) + Column() { + Text($r('app.string.ArcListStyles_waln')).fontSize('38px').fontColor('#FFFFFFFF') + Text($r('app.string.ArcListStyles_open')).fontSize('20px').fontColor('#FFFFFFFF') + }.width('190px') + + Image($r('app.media.ic_settings_arrow')).width('92px').height('92px') + .borderRadius('50px') + } + } + .borderRadius('65px') + .width('414px') + .height('129px') + .backgroundColor('#26FFFFFF') + + ArcListItem() { + Row() { + Image($r('app.media.blueTooth')).width('99px').height('99px') + .borderRadius('50px').margin({ left: 7 }) + Column() { + Text($r('app.string.ArcListStyles_blue')).fontSize('38px').fontColor('#FFFFFFFF') + Text($r('app.string.ArcListStyles_open')).fontSize('20px').fontColor('#FFFFFFFF') + }.width('190px') + + Image($r('app.media.ic_settings_arrow')).width('92px').height('92px') + .borderRadius('50px') + } + } + .borderRadius('65px') + .width('414px') + .height('129px') + .backgroundColor('#26FFFFFF') + + ArcListItem() { + Row() { + Image($r('app.media.mobileData')).width('99px').height('99px') + .borderRadius('50px').margin({ left: 7 }) + Column() { + Text($r('app.string.ArcListStyles_net')).fontSize('38px').fontColor('#FFFFFFFF') + }.width('190px') + + Image($r('app.media.ic_settings_arrow')).width('92px').height('92px') + .borderRadius('50px') + } + } + .borderRadius('65px') + .width('414px') + .height('129px') + .backgroundColor('#26FFFFFF') + + ArcListItem() { + Row() { + Image($r('app.media.ic_settings_more_connections')).width('99px').height('99px') + .borderRadius('50px').margin({ left: 7 }) + Column() { + Text($r('app.string.ArcListStyles_connect')).fontSize('38px').fontColor('#FFFFFFFF') + }.width('190px') + + Image($r('app.media.ic_settings_arrow')).width('92px').height('92px') + .borderRadius('50px') + } + } + .borderRadius('65px') + .width('414px') + .height('129px') + .backgroundColor('#26FFFFFF') + + ArcListItem() { + Row() { + Image($r('app.media.displayAndBrightness')).width('99px').height('99px') + .borderRadius('50px').margin({ left: 7 }) + Column() { + Text($r('app.string.ArcListStyles_light')).fontSize('38px').fontColor('#FFFFFFFF') + }.width('190px') + + Image($r('app.media.ic_settings_arrow')).width('92px').height('92px') + .borderRadius('50px') + } + } + .borderRadius('65px') + .width('414px') + .height('129px') + .backgroundColor('#26FFFFFF') + } + .width('466px') + .height('466px') + .space(LengthMetrics.px(10)) + .borderRadius('233px') + .backgroundColor(Color.Black) + } + } + .width('100%') + .height('100%') + .padding({ left: 12, right: 12 }) + } + .backgroundColor('#f1f2f3') + .title($r('app.string.ArcListShow_title')) + } +} \ No newline at end of file diff --git a/ArkUISample/ScrollableComponent/entry/src/main/ets/pages/arcList/ArcListSideSlip.ets b/ArkUISample/ScrollableComponent/entry/src/main/ets/pages/arcList/ArcListSideSlip.ets new file mode 100644 index 0000000000000000000000000000000000000000..e17cda188035f7eeca3e0a64a8bed949c0e56be0 --- /dev/null +++ b/ArkUISample/ScrollableComponent/entry/src/main/ets/pages/arcList/ArcListSideSlip.ets @@ -0,0 +1,159 @@ +/* + * Copyright (c) 2025 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 { ArcList, ArcListAttribute, ArcListItemAttribute, ArcListItem } from '@kit.ArkUI'; +import { ComponentContent, LengthMetrics } from '@ohos.arkui.node'; +import { util } from '@kit.ArkTS'; +import { ComponentCard } from '../../common/Card'; + +class Contact { + key: string = util.generateRandomUUID(true); + name: string; + firstChar: string; + + constructor(name: string, firstChar: string) { + this.name = name; + this.firstChar = firstChar; + } +} +@Builder +function buildText() { + Column() { + Text('Contacts ') + .fontColor('#FFFFFF') + .fontSize('19fp') + + } +} + +@Entry +@Component +export struct ArcListSideSlip { + @State contacts: Array = [ + new Contact('Alice', 'A'), + new Contact('Bob', 'B'), + new Contact('Charlie', 'C'), + new Contact('Diana', 'D'), + new Contact('Eve', 'E'), + new Contact('阿哈', 'A'), + new Contact('贝贝', 'B'), + new Contact('彩彩', 'C'), + new Contact('东东', 'D'), + new Contact('嗯嗯', 'E'), + new Contact('芳芳', 'F'), + new Contact('哥哥', 'G'), + new Contact('哈哈', 'H'), + new Contact('吉吉', 'J'), + new Contact('可可', 'K'), + new Contact('乐乐', 'L'), + new Contact('妹妹', 'M'), + new Contact('妮妮', 'N'), + new Contact('哦豁', 'O'), + new Contact('胖胖', 'P'), + new Contact('琪琪', 'Q'), + new Contact('然然', 'R'), + new Contact('叔叔', 'S'), + new Contact('天天', 'T'), + ]; + + private scrollerForList: Scroller = new Scroller(); + + @State indexerIndex: number = 0; + context: UIContext = this.getUIContext(); + tabBar1: ComponentContent = new ComponentContent(this.context, wrapBuilder(buildText)); + + @Builder + itemEnd(item: Contact) { + // 构建尾端滑出组件 + Button({ type: ButtonType.Circle }) { + Image($r('app.media.MaterialSymbolsDelete')) + .width(20) + .height(20) + } + .width(20) + .height(20) + .backgroundColor(Color.Black) + .onClick(() => { + this.getUIContext()?.animateTo({ + duration: 1000, + curve: Curve.Smooth, + iterations: 1, + playMode: PlayMode.Normal, + }, () => { + let index = this.contacts.indexOf(item); + this.contacts.splice(index, 1); + }) + + }) + } + + build() { + NavDestination() { + Column({ space: 12 }) { + ComponentCard({ title: $r('app.string.ArcListSideSlip_title') }) { + Stack() { + ArcList({ initialIndex: 0, header: this.tabBar1, scroller: this.scrollerForList }) { + ForEach(this.contacts, (item: Contact) => { + ArcListItem() { + Row() { + Text(item.firstChar) + .textAlign(TextAlign.Center) + .width(30) + .height(30) + .margin(10) + .backgroundColor('#FF9CC998') + .borderRadius(20) + Text(item.name).fontSize('38px').fontColor('#FFFFFFFF') + } + .backgroundColor('#26FFFFFF') + .borderRadius('65px') + .width('90%') + .justifyContent(FlexAlign.Start) + } + .swipeAction({ + end: { + // index为该ArcListItem在ArcList中的索引值。 + builder: () => { + this.itemEnd(item); + }, + } + }) // 设置侧滑属性. + .borderRadius('65px') + .width('400px') + .height('130px') + + }, (item: Contact) => JSON.stringify(item)) + } + .space(LengthMetrics.px(10)) + .scrollBar(BarState.Auto) + .width('466px') + .height('466px') + .borderRadius('233px') + .backgroundColor(Color.Black) + .margin(50) + .onScrollIndex((firstIndex: number, lastIndex: number, centerIndex: number) => { + this.indexerIndex = centerIndex + 1; + }) + } + } + } + .width('100%') + .height('100%') + .padding({ left: 12, right: 12 }) + } + .backgroundColor('#f1f2f3') + .title($r('app.string.ArcListSideSlip_title')) + } +} \ No newline at end of file diff --git a/ArkUISample/ScrollableComponent/entry/src/main/ets/pages/arcList/ArcListStyles.ets b/ArkUISample/ScrollableComponent/entry/src/main/ets/pages/arcList/ArcListStyles.ets new file mode 100644 index 0000000000000000000000000000000000000000..ff990f8ed76e3cd0207f65d1883e1f5965ed15c9 --- /dev/null +++ b/ArkUISample/ScrollableComponent/entry/src/main/ets/pages/arcList/ArcListStyles.ets @@ -0,0 +1,351 @@ +/* + * Copyright (c) 2025 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 { + ArcList, + ArcListItem, + ArcListAttribute, + ArcListItemAttribute, + LengthMetrics, + ComponentContent +} from '@kit.ArkUI'; +import { ComponentCard } from '../../common/Card'; + +@Builder +function customHeader() { + Column() { + Text($r('app.string.ArcListCrown_set')) + .fontColor('#FFFFFFFF') + .fontSize('19fp') + } +} + + +@Entry +@Component +export struct ArcListStyles { + context: UIContext = this.getUIContext(); + arcListHeader: ComponentContent = new ComponentContent(this.context, wrapBuilder(customHeader)); + + build() { + NavDestination() { + Column({ space: 12 }) { + List(){ + ListItem(){ + ComponentCard({ title: $r('app.string.ArcListStyles_head') }) { + ArcList({ header: this.arcListHeader }) { + ArcListItem() { + Row() { + Image($r('app.media.wlan')).width('99px').height('99px') + .borderRadius('50px').margin({ left: 7 }) + Column() { + Text($r('app.string.ArcListStyles_waln')).fontSize('38px').fontColor('#FFFFFFFF') + Text($r('app.string.ArcListStyles_open')).fontSize('20px').fontColor('#FFFFFFFF') + }.width('190px') + + Image($r('app.media.ic_settings_arrow')).width('92px').height('92px') + .borderRadius('50px') + } + } + .borderRadius('65px') + .width('414px') + .height('129px') + .backgroundColor('#26FFFFFF') + + ArcListItem() { + Row() { + Image($r('app.media.blueTooth')).width('99px').height('99px') + .borderRadius('50px').margin({ left: 7 }) + Column() { + Text($r('app.string.ArcListStyles_blue')).fontSize('38px').fontColor('#FFFFFFFF') + Text($r('app.string.ArcListStyles_open')).fontSize('20px').fontColor('#FFFFFFFF') + }.width('190px') + + Image($r('app.media.ic_settings_arrow')).width('92px').height('92px') + .borderRadius('50px') + } + } + .borderRadius('65px') + .width('414px') + .height('129px') + .backgroundColor('#26FFFFFF') + + ArcListItem() { + Row() { + Image($r('app.media.mobileData')).width('99px').height('99px') + .borderRadius('50px').margin({ left: 7 }) + Column() { + Text($r('app.string.ArcListStyles_net')).fontSize('38px').fontColor('#FFFFFFFF') + }.width('190px') + + Image($r('app.media.ic_settings_arrow')).width('92px').height('92px') + .borderRadius('50px') + } + } + .borderRadius('65px') + .width('414px') + .height('129px') + .backgroundColor('#26FFFFFF') + + ArcListItem() { + Row() { + Image($r('app.media.ic_settings_more_connections')).width('99px').height('99px') + .borderRadius('50px').margin({ left: 7 }) + Column() { + Text($r('app.string.ArcListStyles_connect')).fontSize('38px').fontColor('#FFFFFFFF') + }.width('190px') + + Image($r('app.media.ic_settings_arrow')).width('92px').height('92px') + .borderRadius('50px') + } + } + .borderRadius('65px') + .width('414px') + .height('129px') + .backgroundColor('#26FFFFFF') + + ArcListItem() { + Row() { + Image($r('app.media.displayAndBrightness')).width('99px').height('99px') + .borderRadius('50px').margin({ left: 7 }) + Column() { + Text($r('app.string.ArcListStyles_light')).fontSize('38px').fontColor('#FFFFFFFF') + }.width('190px') + + Image($r('app.media.ic_settings_arrow')).width('92px').height('92px') + .borderRadius('50px') + } + } + .borderRadius('65px') + .width('414px') + .height('129px') + .backgroundColor('#26FFFFFF') + } + .width('466px') + .height('466px') + .space(LengthMetrics.px(10)) + .borderRadius('233px') + .backgroundColor(Color.Black) + } + } + + ListItem(){ + ComponentCard({ title: $r('app.string.ArcListStyles_titleSpacing') }) { + ArcList({ initialIndex: 2 }) { + ArcListItem() { + Row() { + Image($r('app.media.wlan')).width('99px').height('99px') + .borderRadius('50px').margin({ left: 7 }) + Column() { + Text($r('app.string.ArcListStyles_waln')).fontSize('38px').fontColor('#FFFFFFFF') + Text($r('app.string.ArcListStyles_open')).fontSize('20px').fontColor('#FFFFFFFF') + }.width('190px') + + Image($r('app.media.ic_settings_arrow')).width('92px').height('92px') + .borderRadius('50px') + } + } + .borderRadius('65px') + .width('414px') + .height('129px') + .backgroundColor('#26FFFFFF') + + ArcListItem() { + Row() { + Image($r('app.media.blueTooth')).width('99px').height('99px') + .borderRadius('50px').margin({ left: 7 }) + Column() { + Text($r('app.string.ArcListStyles_blue')).fontSize('38px').fontColor('#FFFFFFFF') + Text($r('app.string.ArcListStyles_open')).fontSize('20px').fontColor('#FFFFFFFF') + }.width('190px') + + Image($r('app.media.ic_settings_arrow')).width('92px').height('92px') + .borderRadius('50px') + } + } + .borderRadius('65px') + .width('414px') + .height('129px') + .backgroundColor('#26FFFFFF') + + ArcListItem() { + Row() { + Image($r('app.media.mobileData')).width('99px').height('99px') + .borderRadius('50px').margin({ left: 7 }) + Column() { + Text($r('app.string.ArcListStyles_net')).fontSize('38px').fontColor('#FFFFFFFF') + }.width('190px') + + Image($r('app.media.ic_settings_arrow')).width('92px').height('92px') + .borderRadius('50px') + } + } + .borderRadius('65px') + .width('414px') + .height('129px') + .backgroundColor('#26FFFFFF') + + ArcListItem() { + Row() { + Image($r('app.media.ic_settings_more_connections')).width('99px').height('99px') + .borderRadius('50px').margin({ left: 7 }) + Column() { + Text($r('app.string.ArcListStyles_connect')).fontSize('38px').fontColor('#FFFFFFFF') + }.width('190px') + + Image($r('app.media.ic_settings_arrow')).width('92px').height('92px') + .borderRadius('50px') + } + } + .borderRadius('65px') + .width('414px') + .height('129px') + .backgroundColor('#26FFFFFF') + + ArcListItem() { + Row() { + Image($r('app.media.displayAndBrightness')).width('99px').height('99px') + .borderRadius('50px').margin({ left: 7 }) + Column() { + Text($r('app.string.ArcListStyles_light')).fontSize('38px').fontColor('#FFFFFFFF') + }.width('190px') + + Image($r('app.media.ic_settings_arrow')).width('92px').height('92px') + .borderRadius('50px') + } + } + .borderRadius('65px') + .width('414px') + .height('129px') + .backgroundColor('#26FFFFFF') + } + .width('466px') + .height('466px') + .space(LengthMetrics.px(30)) + .borderRadius('233px') + .backgroundColor(Color.Black) + + } + } + + ListItem(){ + ComponentCard({ title: $r('app.string.ArcListStyles_titleScale') }) { + ArcList({ initialIndex: 2 }) { + ArcListItem() { + Row() { + Image($r('app.media.wlan')).width('99px').height('99px') + .borderRadius('50px').margin({ left: 7 }) + Column() { + Text($r('app.string.ArcListStyles_waln')).fontSize('38px').fontColor('#FFFFFFFF') + Text($r('app.string.ArcListStyles_open')).fontSize('20px').fontColor('#FFFFFFFF') + }.width('190px') + + Image($r('app.media.ic_settings_arrow')).width('92px').height('92px') + .borderRadius('50px') + } + } + .borderRadius('65px') + .width('414px') + .height('129px') + .backgroundColor('#26FFFFFF') + + ArcListItem() { + Row() { + Image($r('app.media.blueTooth')).width('99px').height('99px') + .borderRadius('50px').margin({ left: 7 }) + Column() { + Text($r('app.string.ArcListStyles_blue')).fontSize('38px').fontColor('#FFFFFFFF') + Text($r('app.string.ArcListStyles_open')).fontSize('20px').fontColor('#FFFFFFFF') + }.width('190px') + + Image($r('app.media.ic_settings_arrow')).width('92px').height('92px') + .borderRadius('50px') + } + } + .borderRadius('65px') + .width('414px') + .height('129px') + .backgroundColor('#26FFFFFF') + + ArcListItem() { + Row() { + Image($r('app.media.mobileData')).width('99px').height('99px') + .borderRadius('50px').margin({ left: 7 }) + Column() { + Text($r('app.string.ArcListStyles_net')).fontSize('38px').fontColor('#FFFFFFFF') + }.width('190px') + + Image($r('app.media.ic_settings_arrow')).width('92px').height('92px') + .borderRadius('50px') + } + } + .borderRadius('65px') + .width('414px') + .height('129px') + .backgroundColor('#26FFFFFF') + .autoScale(false) + + ArcListItem() { + Row() { + Image($r('app.media.ic_settings_more_connections')).width('99px').height('99px') + .borderRadius('50px').margin({ left: 7 }) + Column() { + Text($r('app.string.ArcListStyles_connect')).fontSize('38px').fontColor('#FFFFFFFF') + }.width('190px') + + Image($r('app.media.ic_settings_arrow')).width('92px').height('92px') + .borderRadius('50px') + } + } + .borderRadius('65px') + .width('414px') + .height('129px') + .backgroundColor('#26FFFFFF') + + ArcListItem() { + Row() { + Image($r('app.media.displayAndBrightness')).width('99px').height('99px') + .borderRadius('50px').margin({ left: 7 }) + Column() { + Text($r('app.string.ArcListStyles_light')).fontSize('38px').fontColor('#FFFFFFFF') + }.width('190px') + + Image($r('app.media.ic_settings_arrow')).width('92px').height('92px') + .borderRadius('50px') + } + } + .borderRadius('65px') + .width('414px') + .height('129px') + .backgroundColor('#26FFFFFF') + .autoScale(false) + } + .width('466px') + .height('466px') + .space(LengthMetrics.px(30)) + .borderRadius('233px') + .backgroundColor(Color.Black) + } + } + } + } + .width('100%') + .height('100%') + .padding({ left: 12, right: 12 }) + } + .backgroundColor('#f1f2f3') + .title($r('app.string.ArcListStyles_title')) + } +} \ No newline at end of file diff --git a/ArkUISample/ScrollableComponent/entry/src/main/ets/pages/arcList/ArcLongList.ets b/ArkUISample/ScrollableComponent/entry/src/main/ets/pages/arcList/ArcLongList.ets new file mode 100644 index 0000000000000000000000000000000000000000..a12b2467a96da83928b06e91019ad1329e851915 --- /dev/null +++ b/ArkUISample/ScrollableComponent/entry/src/main/ets/pages/arcList/ArcLongList.ets @@ -0,0 +1,151 @@ +/* + * Copyright (c) 2025 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 { ArcList, ArcListAttribute, ArcListItemAttribute, ArcListItem } from '@kit.ArkUI'; +import { LengthMetrics } from '@ohos.arkui.node'; +import { ComponentCard } from '../../common/Card'; + +class BasicDataSource implements IDataSource { + private listeners: DataChangeListener[] = []; + private originDataArray: StringData[] = []; + + public totalCount(): number { + return 0; + } + + public getData(index: number): StringData { + return this.originDataArray[index]; + } + + registerDataChangeListener(listener: DataChangeListener): void { + if (this.listeners.indexOf(listener) < 0) { + console.info('add listener'); + this.listeners.push(listener); + } + } + + unregisterDataChangeListener(listener: DataChangeListener): void { + const pos = this.listeners.indexOf(listener); + if (pos >= 0) { + console.info('remove listener'); + this.listeners.splice(pos, 1); + } + } + + notifyDataReload(): void { + this.listeners.forEach(listener => { + listener.onDataReloaded(); + }); + } + + notifyDataAdd(index: number): void { + this.listeners.forEach(listener => { + listener.onDataAdd(index); + }); + } + + notifyDataChange(index: number): void { + this.listeners.forEach(listener => { + listener.onDataChange(index); + }); + } + + notifyDataDelete(index: number): void { + this.listeners.forEach(listener => { + listener.onDataDelete(index); + }); + } + + notifyDataMove(from: number, to: number): void { + this.listeners.forEach(listener => { + listener.onDataMove(from, to); + }); + } + + notifyDatasetChange(operations: DataOperation[]): void { + this.listeners.forEach(listener => { + listener.onDatasetChange(operations); + }); + } +} + +class MyDataSource extends BasicDataSource { + private dataArray: StringData[] = []; + + public totalCount(): number { + return this.dataArray.length; + } + + public getData(index: number): StringData { + return this.dataArray[index]; + } + + public pushData(data: StringData): void { + this.dataArray.push(data); + this.notifyDataAdd(this.dataArray.length - 1); + } +} + +@Observed +class StringData { + message: string; + + constructor(message: string) { + this.message = message; + } +} + +@Entry +@Component +export struct ArcLongList { + private data: MyDataSource = new MyDataSource(); + + aboutToAppear() { + for (let i = 0; i <= 100; i++) { + this.data.pushData(new StringData(`Hello ${i}`)); + } + } + + build() { + NavDestination() { + Column({ space: 12 }) { + ComponentCard({ title: $r('app.string.ArcLongList_title') }) { + ArcList() { + LazyForEach(this.data, (item: StringData, index: number) => { + ArcListItem() { + Text(item.message).fontSize(30).fontColor(Color.White) + } + .onClick(() => { + item.message += '0'; + }) + }, (item: StringData, index: number) => JSON.stringify(item) + index.toString()) + }.cachedCount(3) + .space(LengthMetrics.px(10)) + .scrollBar(BarState.Auto) + .width('466px') + .height('466px') + .borderRadius('233px') + .backgroundColor(Color.Black) + .margin(50) + } + } + .width('100%') + .height('100%') + .padding({ left: 12, right: 12 }) + } + .backgroundColor('#f1f2f3') + .title($r('app.string.ArcLongList_title')) + } +} \ No newline at end of file diff --git a/ArkUISample/ScrollableComponent/entry/src/main/ets/pages/arcList/arcListBuiltInScrollerBar.ets b/ArkUISample/ScrollableComponent/entry/src/main/ets/pages/arcList/arcListBuiltInScrollerBar.ets new file mode 100644 index 0000000000000000000000000000000000000000..d9d8ec8cf8370dbc0aeeb058905f1c15199867b3 --- /dev/null +++ b/ArkUISample/ScrollableComponent/entry/src/main/ets/pages/arcList/arcListBuiltInScrollerBar.ets @@ -0,0 +1,129 @@ +/* + * Copyright (c) 2025 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 { ArcList, ArcListItem, ArcListAttribute, ArcListItemAttribute, LengthMetrics, ColorMetrics } from '@kit.ArkUI'; +import { ComponentCard } from '../../common/Card'; + +@Entry +@Component +export struct arcListBuiltInScrollerBar { + + build() { + NavDestination() { + Column({ space: 12 }) { + ComponentCard({ title: $r('app.string.arcListBuiltInScrollerBar_title') }) { + ArcList() { + ArcListItem() { + Row() { + Image($r('app.media.wlan')).width('99px').height('99px') + .borderRadius('50px').margin({ left: 7 }) + Column() { + Text($r('app.string.ArcListStyles_waln')).fontSize('38px').fontColor('#FFFFFFFF') + Text($r('app.string.ArcListStyles_open')).fontSize('20px').fontColor('#FFFFFFFF') + }.width('190px') + + Image($r('app.media.ic_settings_arrow')).width('92px').height('92px') + .borderRadius('50px') + } + } + .borderRadius('65px') + .width('414px') + .height('129px') + .backgroundColor('#26FFFFFF') + + ArcListItem() { + Row() { + Image($r('app.media.blueTooth')).width('99px').height('99px') + .borderRadius('50px').margin({ left: 7 }) + Column() { + Text($r('app.string.ArcListStyles_blue')).fontSize('38px').fontColor('#FFFFFFFF') + Text($r('app.string.ArcListStyles_open')).fontSize('20px').fontColor('#FFFFFFFF') + }.width('190px') + + Image($r('app.media.ic_settings_arrow')).width('92px').height('92px') + .borderRadius('50px') + } + } + .borderRadius('65px') + .width('414px') + .height('129px') + .backgroundColor('#26FFFFFF') + + ArcListItem() { + Row() { + Image($r('app.media.mobileData')).width('99px').height('99px') + .borderRadius('50px').margin({ left: 7 }) + Column() { + Text($r('app.string.ArcListStyles_net')).fontSize('38px').fontColor('#FFFFFFFF') + }.width('190px') + + Image($r('app.media.ic_settings_arrow')).width('92px').height('92px') + .borderRadius('50px') + } + } + .borderRadius('65px') + .width('414px') + .height('129px') + .backgroundColor('#26FFFFFF') + + ArcListItem() { + Row() { + Image($r('app.media.ic_settings_more_connections')).width('99px').height('99px') + .borderRadius('50px').margin({ left: 7 }) + Column() { + Text($r('app.string.ArcListStyles_connect')).fontSize('38px').fontColor('#FFFFFFFF') + }.width('190px') + + Image($r('app.media.ic_settings_arrow')).width('92px').height('92px') + .borderRadius('50px') + } + } + .borderRadius('65px') + .width('414px') + .height('129px') + .backgroundColor('#26FFFFFF') + + ArcListItem() { + Row() { + Image($r('app.media.displayAndBrightness')).width('99px').height('99px') + .borderRadius('50px').margin({ left: 7 }) + Column() { + Text($r('app.string.ArcListStyles_light')).fontSize('38px').fontColor('#FFFFFFFF') + }.width('190px') + + Image($r('app.media.ic_settings_arrow')).width('92px').height('92px') + .borderRadius('50px') + } + } + .borderRadius('65px') + .width('414px') + .height('129px') + .backgroundColor('#26FFFFFF') + } + .width('466px') + .height('466px') + .space(LengthMetrics.px(10)) + .borderRadius('233px') + .backgroundColor(Color.Black) + } + } + .width('100%') + .height('100%') + .padding({ left: 12, right: 12 }) + } + .backgroundColor('#f1f2f3') + .title($r('app.string.arcListBuiltInScrollerBar_title')) + } +} \ No newline at end of file diff --git a/ArkUISample/ScrollableComponent/entry/src/main/ets/pages/arcList/index.ets b/ArkUISample/ScrollableComponent/entry/src/main/ets/pages/arcList/index.ets new file mode 100644 index 0000000000000000000000000000000000000000..dc596f1567388839eedc27746e8bbc8a935d0a52 --- /dev/null +++ b/ArkUISample/ScrollableComponent/entry/src/main/ets/pages/arcList/index.ets @@ -0,0 +1,132 @@ +/* + * Copyright (c) 2025 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { CompletedRoutableCard } from '../../common/Card'; +import { Route } from '../../common/Route'; +import { ArcListAcrScrollBar } from './ArcListAcrScrollBar'; +import { ArcListArcIndexerBar } from './ArcListArcIndexerBar'; +import { arcListBuiltInScrollerBar } from './arcListBuiltInScrollerBar'; +import { ArcListContents } from './ArcListContents'; +import { ArcListCrown } from './ArcListCrown'; +import { ArcListShow } from './ArcListShow'; +import { ArcListSideSlip } from './ArcListSideSlip'; +import { ArcListStyles } from './ArcListStyles'; +import { ArcLongList } from './ArcLongList'; + +import resource from '../../common/resource'; + +export const ARCLIST_ROUTE_PREFIX: string = 'arcList'; + +const routes: Route[] = [ + { + name: `${ARCLIST_ROUTE_PREFIX}/ArcListShow`, + title: resource.resourceToString($r('app.string.ArcListShow_title')), + description: $r('app.string.ArcListShow_description') + }, + { + name: `${ARCLIST_ROUTE_PREFIX}/ArcListContents`, + title: resource.resourceToString($r('app.string.ArcListContents_title')), + description: $r('app.string.ArcListContents_description') + }, + { + name: `${ARCLIST_ROUTE_PREFIX}/ArcListStyles`, + title: resource.resourceToString($r('app.string.ArcListStyles_title')), + description: $r('app.string.ArcListStyles_description') + }, + { + name: `${ARCLIST_ROUTE_PREFIX}/arcListBuiltInScrollerBar`, + title: resource.resourceToString($r('app.string.arcListBuiltInScrollerBar_title')), + description: $r('app.string.arcListBuiltInScrollerBar_description') + }, + { + name: `${ARCLIST_ROUTE_PREFIX}/ArcListAcrScrollBar`, + title: resource.resourceToString($r('app.string.ArcListAcrScrollBar_title')), + description: $r('app.string.ArcListAcrScrollBar_description') + }, + { + name: `${ARCLIST_ROUTE_PREFIX}/ArcListArcIndexerBar`, + title: resource.resourceToString($r('app.string.ArcListArcIndexerBar_title')), + description: $r('app.string.ArcListArcIndexerBar_description') + }, + { + name: `${ARCLIST_ROUTE_PREFIX}/ArcListSideSlip`, + title: resource.resourceToString($r('app.string.ArcListSideSlip_title')), + description: $r('app.string.ArcListSideSlip_description') + }, + { + name: `${ARCLIST_ROUTE_PREFIX}/ArcLongList`, + title: resource.resourceToString($r('app.string.ArcLongList_title')), + description: $r('app.string.ArcLongList_description') + }, + { + name: `${ARCLIST_ROUTE_PREFIX}/ArcListCrown`, + title: resource.resourceToString($r('app.string.ArcListCrown_title')), + description: $r('app.string.ArcListCrown_description') + } +]; + +@Builder +export function arcListDestination(name: string) { + if (name === ARCLIST_ROUTE_PREFIX) { + ArcListExample(); + } else if (name === routes[0].name) { + ArcListShow(); + } else if (name === routes[1].name) { + ArcListContents(); + } else if (name === routes[2].name) { + ArcListStyles(); + } else if (name === routes[3].name) { + arcListBuiltInScrollerBar(); + } else if (name === routes[4].name) { + ArcListAcrScrollBar(); + } else if (name === routes[5].name) { + ArcListArcIndexerBar(); + } else if (name === routes[6].name) { + ArcListSideSlip(); + } else if (name === routes[7].name) { + ArcLongList(); + } else if (name === routes[8].name) { + ArcListCrown(); + } +} + +@Entry +@Component +struct ArcListExample { + @Consume pathStack: NavPathStack; + + build() { + NavDestination() { + List({ space: 12 }) { + ForEach(routes, (route: Route) => { + ListItem() { + CompletedRoutableCard({ title: route.title, description: route.description }) + } + .width('100%') + .onClick(() => { + this.pathStack.pushPath({ name: route.name }); + }) + }) + } + .contentStartOffset(56) + .padding({ left: 16, right: 16 }) + } + .backgroundColor('#f1f3f5') + .title('ArcList', { + backgroundBlurStyle: BlurStyle.COMPONENT_THICK, + barStyle: BarStyle.STACK + }) + } +} \ No newline at end of file diff --git a/ArkUISample/ScrollableComponent/entry/src/main/ets/pages/arcSwiper/ArcSwiperAction.ets b/ArkUISample/ScrollableComponent/entry/src/main/ets/pages/arcSwiper/ArcSwiperAction.ets new file mode 100644 index 0000000000000000000000000000000000000000..f205d94f020bbbf76e659b79ac623cb52ec373d4 --- /dev/null +++ b/ArkUISample/ScrollableComponent/entry/src/main/ets/pages/arcSwiper/ArcSwiperAction.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. + */ + +import { Decimal } from '@kit.ArkTS'; +import { + ArcSwiper, + ArcSwiperAttribute, +} from '@kit.ArkUI'; +import { ComponentCard } from '../../common/Card'; + +@Entry +@Component +export struct ArcSwiperAction { + private MIN_SCALE: number = 0.1; + @State backgroundColors: Color[] = [Color.Green, Color.Blue, Color.Yellow, Color.Pink, Color.Gray, Color.Orange]; + @State opacityList: number[] = []; + @State scaleList: number[] = []; + + aboutToAppear(): void { + for (let i = 0; i < this.backgroundColors.length; i++) { + this.opacityList.push(1.0); + this.scaleList.push(1.0); + } + } + + build() { + NavDestination() { + Column({ space: 12 }) { + ComponentCard({ title: $r('app.string.ArcSwiperAction_title') }) { + ArcSwiper() { + ForEach(this.backgroundColors, (backgroundColor: Color, index: number) => { + Text(index.toString()) + .width(233) + .height(233) + .fontSize(50) + .textAlign(TextAlign.Center) + .backgroundColor(backgroundColor) + .opacity(this.opacityList[index]) + .scale({ x: this.scaleList[index], y: this.scaleList[index] }) + }) + } + .customContentTransition({ + timeout: 1000, + transition: (proxy: SwiperContentTransitionProxy) => { + if (proxy.position <= -1 || proxy.position >= 1) { + // 页面完全滑出视窗外时,重置属性值 + this.opacityList[proxy.index] = 1.0; + this.scaleList[proxy.index] = 1.0; + } else { + let position: number = Decimal.abs(proxy.position).toNumber(); + this.opacityList[proxy.index] = 1 - position; + this.scaleList[proxy.index] = + this.MIN_SCALE + (1 - this.MIN_SCALE) * (1 - position); + } + } + }) + } + } + .width('100%') + .height('100%') + .padding({ left: 12, right: 12 }) + } + .backgroundColor('#f1f2f3') + .title($r('app.string.ArcSwiperAction_title')) + } +} \ No newline at end of file diff --git a/ArkUISample/ScrollableComponent/entry/src/main/ets/pages/arcSwiper/ArcSwiperHorizontal.ets b/ArkUISample/ScrollableComponent/entry/src/main/ets/pages/arcSwiper/ArcSwiperHorizontal.ets new file mode 100644 index 0000000000000000000000000000000000000000..d8c2d8e98fc95d1fddac2fe42df1aaf297f7edac --- /dev/null +++ b/ArkUISample/ScrollableComponent/entry/src/main/ets/pages/arcSwiper/ArcSwiperHorizontal.ets @@ -0,0 +1,64 @@ +/* + * Copyright (c) 2025 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { + ArcSwiper, + ArcSwiperAttribute, +} from '@kit.ArkUI'; +import { ComponentCard } from '../../common/Card'; + +@Entry +@Component +export struct ArcSwiperHorizontal { + @State message: string = 'Hello World'; + + build() { + NavDestination() { + Column({ space: 12 }) { + ComponentCard({ title: $r('app.string.ArcSwiperHorizontal_title') }) { + ArcSwiper() { + Text('0') + .width(233) + .height(233) + .backgroundColor(Color.Gray) + .textAlign(TextAlign.Center) + .fontSize(30) + + Text('1') + .width(233) + .height(233) + .backgroundColor(Color.Green) + .textAlign(TextAlign.Center) + .fontSize(30) + + Text('2') + .width(233) + .height(233) + .backgroundColor(Color.Pink) + .textAlign(TextAlign.Center) + .fontSize(30) + } + .indicator(true) + .vertical(false) + } + } + .width('100%') + .height('100%') + .padding({ left: 12, right: 12 }) + } + .backgroundColor('#f1f2f3') + .title($r('app.string.ArcSwiperHorizontal_title')) + } +} diff --git a/ArkUISample/ScrollableComponent/entry/src/main/ets/pages/arcSwiper/ArcSwiperSideSlip.ets b/ArkUISample/ScrollableComponent/entry/src/main/ets/pages/arcSwiper/ArcSwiperSideSlip.ets new file mode 100644 index 0000000000000000000000000000000000000000..5eac8d25e87264261126655031feaf5cc1826221 --- /dev/null +++ b/ArkUISample/ScrollableComponent/entry/src/main/ets/pages/arcSwiper/ArcSwiperSideSlip.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 { + ArcSwiper, + ArcSwiperAttribute, + ArcDotIndicator, + ArcDirection, + ArcSwiperController +} from '@kit.ArkUI'; +import { ComponentCard } from '../../common/Card'; + +@Entry +@Component +export struct ArcSwiperSideSlip { + @State backgroundColors: Color[] = [Color.Green, Color.Blue, Color.Yellow, Color.Pink, Color.Gray, Color.Orange]; + innerSelectedIndex: number = 0; + + build() { + NavDestination() { + Column({ space: 12 }) { + ComponentCard({ title: $r('app.string.ArcSwiperSideSlip_title') }) { + ArcSwiper() { + ForEach(this.backgroundColors, (backgroundColor: Color, index: number) => { + Text(index.toString()) + .width(233) + .height(233) + .fontSize(50) + .textAlign(TextAlign.Center) + .backgroundColor(backgroundColor) + }) + } + .onAnimationStart((index: number, targetIndex: number) => { + this.innerSelectedIndex = targetIndex; + }) + .onGestureRecognizerJudgeBegin((event: BaseGestureEvent, current: GestureRecognizer, + others: Array): GestureJudgeResult => { // 在识别器即将要成功时,根据当前组件状态,设置识别器使能状态 + if (current) { + let target = current.getEventTargetInfo(); + if (target && current.isBuiltIn() && current.getType() == GestureControl.GestureType.PAN_GESTURE) { + let swiperTarget = target as ScrollableTargetInfo; + if (swiperTarget instanceof ScrollableTargetInfo && + (swiperTarget.isBegin() || this.innerSelectedIndex === 0)) { // 此处判断swiperTarget.isBegin()或innerSelectedIndex === 0,表明ArcSwiper滑动到开头 + let panEvent = event as PanGestureEvent; + if (panEvent && panEvent.offsetX > 0 && (swiperTarget.isBegin() || this.innerSelectedIndex === 0)) { + return GestureJudgeResult.REJECT; + } + } + } + } + return GestureJudgeResult.CONTINUE; + }) + } + } + .width('100%') + .height('100%') + .padding({ left: 12, right: 12 }) + } + .backgroundColor('#f1f2f3') + .title($r('app.string.ArcSwiperSideSlip_title')) + } +} \ No newline at end of file diff --git a/ArkUISample/ScrollableComponent/entry/src/main/ets/pages/arcSwiper/ArcSwiperStyles.ets b/ArkUISample/ScrollableComponent/entry/src/main/ets/pages/arcSwiper/ArcSwiperStyles.ets new file mode 100644 index 0000000000000000000000000000000000000000..550309c79ff626676735fef66c22fc4d623f4649 --- /dev/null +++ b/ArkUISample/ScrollableComponent/entry/src/main/ets/pages/arcSwiper/ArcSwiperStyles.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 { + ArcSwiper, + ArcSwiperAttribute, + ArcDotIndicator, + ArcDirection, + ArcSwiperController +} from '@kit.ArkUI'; +import { ComponentCard } from '../../common/Card'; + +@Entry +@Component +export struct ArcSwiperStyles { + @State message: string = 'Hello World'; + + build() { + NavDestination() { + Column({ space: 12 }) { + ComponentCard({ title: $r('app.string.ArcSwiperStyles_titleDefault') }) { + ArcSwiper() { + Text('0') + .width(233) + .height(233) + .backgroundColor(Color.Gray) + .textAlign(TextAlign.Center) + .fontSize(30) + + Text('1') + .width(233) + .height(233) + .backgroundColor(Color.Green) + .textAlign(TextAlign.Center) + .fontSize(30) + + Text('2') + .width(233) + .height(233) + .backgroundColor(Color.Pink) + .textAlign(TextAlign.Center) + .fontSize(30) + } + } + + ComponentCard({ title: $r('app.string.ArcSwiperStyles_titleCustomize') }) { + ArcSwiper() { + Text('0') + .width(233) + .height(233) + .backgroundColor(Color.Gray) + .textAlign(TextAlign.Center) + .fontSize(30) + + Text('1') + .width(233) + .height(233) + .backgroundColor(Color.Green) + .textAlign(TextAlign.Center) + .fontSize(30) + + Text('2') + .width(233) + .height(233) + .backgroundColor(Color.Pink) + .textAlign(TextAlign.Center) + .fontSize(30) + } + .indicator( + new ArcDotIndicator() + .arcDirection(ArcDirection.SIX_CLOCK_DIRECTION) // 设置导航点位于6点钟方向 + .itemColor(Color.Red) // 设置导航点颜色为红色 + .selectedItemColor(Color.Blue) // 设置选中导航点颜色为蓝色 + ) + } + } + .width('100%') + .height('100%') + .padding({ left: 12, right: 12 }) + } + .backgroundColor('#f1f2f3') + .title($r('app.string.ArcSwiperStyles_title')) + } +} \ No newline at end of file diff --git a/ArkUISample/ScrollableComponent/entry/src/main/ets/pages/arcSwiper/ArcSwiperToggle.ets b/ArkUISample/ScrollableComponent/entry/src/main/ets/pages/arcSwiper/ArcSwiperToggle.ets new file mode 100644 index 0000000000000000000000000000000000000000..82548c9cd7d359b73b45f801fdc5860f52fe3c9e --- /dev/null +++ b/ArkUISample/ScrollableComponent/entry/src/main/ets/pages/arcSwiper/ArcSwiperToggle.ets @@ -0,0 +1,100 @@ +/* + * Copyright (c) 2025 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 { + ArcButton, + ArcButtonOptions, + ArcButtonStatus, + ArcButtonStyleMode, + ArcButtonPosition, + ArcSwiper, + ArcSwiperAttribute, + ArcDotIndicator, + ArcDirection, + ArcSwiperController +} from '@kit.ArkUI'; +import { ComponentCard } from '../../common/Card'; + +@Entry +@Component +export struct ArcSwiperToggle { + private wearableSwiperController: ArcSwiperController = new ArcSwiperController(); + + build() { + NavDestination() { + Column({ space: 12 }) { + ComponentCard({ title: $r('app.string.ArcSwiperToggle_title') }) { + Stack() { + ArcSwiper(this.wearableSwiperController) { + Text('0') + .width(233) + .height(233) + .backgroundColor(Color.Gray) + .textAlign(TextAlign.Center) + .fontSize(30) + + Text('1') + .width(233) + .height(233) + .backgroundColor(Color.Green) + .textAlign(TextAlign.Center) + .fontSize(30) + + Text('2') + .width(233) + .height(233) + .backgroundColor(Color.Pink) + .textAlign(TextAlign.Center) + .fontSize(30) + } + .vertical(true) + .indicator(false) + + Column() { + ArcButton({ + options: new ArcButtonOptions({ + label: 'previous', + position: ArcButtonPosition.TOP_EDGE, + styleMode: ArcButtonStyleMode.EMPHASIZED_LIGHT, + onClick: () => { + this.wearableSwiperController.showPrevious(); // 通过controller切换到前一页 + } + }) + }) + + Blank() + + ArcButton({ + options: new ArcButtonOptions({ + label: 'next', + position: ArcButtonPosition.BOTTOM_EDGE, + styleMode: ArcButtonStyleMode.EMPHASIZED_LIGHT, + onClick: () => { + this.wearableSwiperController.showNext(); // 通过controller切换到后一页 + } + }) + }) + }.width('100%').height('100%') + } + } + } + .width('100%') + .height('100%') + .padding({ left: 12, right: 12 }) + } + .backgroundColor('#f1f2f3') + .title($r('app.string.ArcSwiperToggle_title')) + } +} \ No newline at end of file diff --git a/ArkUISample/ScrollableComponent/entry/src/main/ets/pages/arcSwiper/ArcSwiperVertical.ets b/ArkUISample/ScrollableComponent/entry/src/main/ets/pages/arcSwiper/ArcSwiperVertical.ets new file mode 100644 index 0000000000000000000000000000000000000000..766faba50d80d1d0b070f2b1b0a07f2c9d57fc2b --- /dev/null +++ b/ArkUISample/ScrollableComponent/entry/src/main/ets/pages/arcSwiper/ArcSwiperVertical.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 { + ArcSwiper, + ArcSwiperAttribute, + ArcDotIndicator, + ArcDirection, + ArcSwiperController +} from '@kit.ArkUI'; +import { ComponentCard } from '../../common/Card'; + +@Entry +@Component +export struct ArcSwiperVertical { + @State message: string = 'Hello World'; + + build() { + NavDestination() { + Column({ space: 12 }) { + ComponentCard({ title: $r('app.string.ArcSwiperVertical_title') }) { + ArcSwiper() { + Text('0') + .width(233) + .height(233) + .backgroundColor(Color.Gray) + .textAlign(TextAlign.Center) + .fontSize(30) + + Text('1') + .width(233) + .height(233) + .backgroundColor(Color.Green) + .textAlign(TextAlign.Center) + .fontSize(30) + + Text('2') + .width(233) + .height(233) + .backgroundColor(Color.Pink) + .textAlign(TextAlign.Center) + .fontSize(30) + } + .indicator(new ArcDotIndicator() + .arcDirection(ArcDirection.THREE_CLOCK_DIRECTION)) + .vertical(true) + } + } + .width('100%') + .height('100%') + .padding({ left: 12, right: 12 }) + } + .backgroundColor('#f1f2f3') + .title($r('app.string.ArcSwiperVertical_title')) + } +} \ No newline at end of file diff --git a/ArkUISample/ScrollableComponent/entry/src/main/ets/pages/arcSwiper/index.ets b/ArkUISample/ScrollableComponent/entry/src/main/ets/pages/arcSwiper/index.ets new file mode 100644 index 0000000000000000000000000000000000000000..eb3ead581a1edeb13cb2c0e517b1501a32d9a698 --- /dev/null +++ b/ArkUISample/ScrollableComponent/entry/src/main/ets/pages/arcSwiper/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. + */ + +import { CompletedRoutableCard } from '../../common/Card'; +import { Route } from '../../common/Route'; +import { ArcSwiperAction } from './ArcSwiperAction'; +import { ArcSwiperHorizontal } from './ArcSwiperHorizontal'; +import { ArcSwiperSideSlip } from './ArcSwiperSideSlip'; +import { ArcSwiperStyles } from './ArcSwiperStyles'; +import { ArcSwiperToggle } from './ArcSwiperToggle'; +import { ArcSwiperVertical } from './ArcSwiperVertical'; +import resource from '../../common/resource'; + +export const ARCSWIPER_ROUTE_PREFIX: string = 'arcSwiper'; + +const routes: Route[] = [ + { + name: `${ARCSWIPER_ROUTE_PREFIX}/ArcSwiperStyles`, + title: resource.resourceToString($r('app.string.ArcSwiperStyles_title')), + description: $r('app.string.ArcSwiperStyles_description') + }, + { + name: `${ARCSWIPER_ROUTE_PREFIX}/ArcSwiperToggle`, + title: resource.resourceToString($r('app.string.ArcSwiperToggle_title')), + description: $r('app.string.ArcSwiperToggle_description') + }, + { + name: `${ARCSWIPER_ROUTE_PREFIX}/ArcSwiperHorizontal`, + title: resource.resourceToString($r('app.string.ArcSwiperHorizontal_title')), + description: $r('app.string.ArcSwiperHorizontal_description') + }, + { + name: `${ARCSWIPER_ROUTE_PREFIX}/ArcSwiperVertical`, + title: resource.resourceToString($r('app.string.ArcSwiperVertical_title')), + description: $r('app.string.ArcSwiperVertical_description') + }, + { + name: `${ARCSWIPER_ROUTE_PREFIX}/ArcSwiperAction`, + title: resource.resourceToString($r('app.string.ArcSwiperAction_title')), + description: $r('app.string.ArcSwiperAction_description') + }, + { + name: `${ARCSWIPER_ROUTE_PREFIX}/ArcSwiperSideSlip`, + title: resource.resourceToString($r('app.string.ArcSwiperSideSlip_title')), + description: $r('app.string.ArcSwiperSideSlip_description') + } +]; + +@Builder +export function arcSwiperDestination(name: string) { + if (name === ARCSWIPER_ROUTE_PREFIX) { + ArcSwiperExample(); + } else if (name === routes[0].name) { + ArcSwiperStyles(); + } else if (name === routes[1].name) { + ArcSwiperToggle(); + } else if (name === routes[2].name) { + ArcSwiperHorizontal(); + } else if (name === routes[3].name) { + ArcSwiperVertical(); + } else if (name === routes[4].name) { + ArcSwiperAction(); + } else if (name === routes[5].name) { + ArcSwiperSideSlip(); + } +} + +@Entry +@Component +struct ArcSwiperExample { + @Consume pathStack: NavPathStack; + + build() { + NavDestination() { + List({ space: 12 }) { + ForEach(routes, (route: Route) => { + ListItem() { + CompletedRoutableCard({ title: route.title, description: route.description }) + } + .width('100%') + .onClick(() => { + this.pathStack.pushPath({ name: route.name }); + }) + }) + } + .contentStartOffset(56) + .padding({ left: 16, right: 16 }) + } + .backgroundColor('#f1f3f5') + .title('ArcSwiper', { + backgroundBlurStyle: BlurStyle.COMPONENT_THICK, + barStyle: BarStyle.STACK + }) + } +} \ No newline at end of file diff --git a/ArkUISample/ScrollableComponent/entry/src/main/ets/pages/grid/DataInGrid.ets b/ArkUISample/ScrollableComponent/entry/src/main/ets/pages/grid/DataInGrid.ets new file mode 100644 index 0000000000000000000000000000000000000000..998e35a9c3588b59688047ef09b801272c69d287 --- /dev/null +++ b/ArkUISample/ScrollableComponent/entry/src/main/ets/pages/grid/DataInGrid.ets @@ -0,0 +1,91 @@ +/* + * Copyright (c) 2025 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 { ComponentCard } from '../../common/Card'; + +// [Start build_a_office_services_grid_of_foreach] +@Entry +@Component +export struct DataInGrid { + @State services: Array = ['Meeting', 'Voting', 'Check-in', 'Printing']; + + build() { + // [StartExclude build_a_office_services_grid_of_foreach] + NavDestination() { + // [EndExclude build_a_office_services_grid_of_foreach] + Column({ space: 12 }) { + // [StartExclude build_a_office_services_grid_of_foreach] + ComponentCard({ title: $r('app.string.DataInGrid_titleOfficeServices') }) { + // [EndExclude build_a_office_services_grid_of_foreach] + // [Start build_a_office_services_grid] + Grid() { + GridItem() { + Text('Meeting') + .fontSize(24) + }.backgroundColor('#FFF1F3F5') + + GridItem() { + Text('Check-in') + .fontSize(24) + }.backgroundColor('#FFF1F3F5') + + GridItem() { + Text('Voting') + .fontSize(24) + }.backgroundColor('#FFF1F3F5') + + GridItem() { + Text('Printing') + .fontSize(24) + }.backgroundColor('#FFF1F3F5') + } + // [StartExclude build_a_office_services_grid] + .height(200) + // [EndExclude build_a_office_services_grid] + .columnsGap(6) + .rowsGap(6) + .rowsTemplate('1fr 1fr') + .columnsTemplate('1fr 1fr') + // [End build_a_office_services_grid] + } + + // [StartExclude build_a_office_services_grid_of_foreach] + ComponentCard({ title: $r('app.string.DataInGrid_titleForEach') }) { + // [EndExclude build_a_office_services_grid_of_foreach] + Grid() { + ForEach(this.services, (service: string) => { + GridItem() { + Text(service) + }.backgroundColor('#FFF1F3F5') + }, (service: string): string => service) + } + // [StartExclude build_a_office_services_grid_of_foreach] + .height(200) + .columnsGap(6) + .rowsGap(6) + // [EndExclude build_a_office_services_grid_of_foreach] + .rowsTemplate(('1fr 1fr') as string) + .columnsTemplate(('1fr 1fr') as string) + } + } + // [End build_a_office_services_grid_of_foreach] + .width('100%') + .height('100%') + .padding({ left: 12, right: 12 }) + } + .backgroundColor('#f1f2f3') + .title($r('app.string.DataInGrid_title')) + } +} \ No newline at end of file diff --git a/ArkUISample/ScrollableComponent/entry/src/main/ets/pages/grid/GridDataSource.ets b/ArkUISample/ScrollableComponent/entry/src/main/ets/pages/grid/GridDataSource.ets new file mode 100644 index 0000000000000000000000000000000000000000..58db5d6fc59bd070de228131cc96901c46c6c5f9 --- /dev/null +++ b/ArkUISample/ScrollableComponent/entry/src/main/ets/pages/grid/GridDataSource.ets @@ -0,0 +1,59 @@ +/* + * Copyright (c) 2025 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 GridDataSource implements IDataSource { + private list: string[] = []; + private listeners: DataChangeListener[] = []; + + constructor(list: string[]) { + this.list = list; + } + + totalCount(): number { + return this.list.length; + } + + getData(index: number): string { + return this.list[index]; + } + + registerDataChangeListener(listener: DataChangeListener): void { + if (this.listeners.indexOf(listener) < 0) { + this.listeners.push(listener); + } + } + + unregisterDataChangeListener(listener: DataChangeListener): void { + const pos = this.listeners.indexOf(listener); + if (pos >= 0) { + this.listeners.splice(pos, 1); + } + } + + // 通知控制器数据位置变化 + notifyDataMove(from: number, to: number): void { + this.listeners.forEach(listener => { + listener.onDataMove(from, to); + }) + } + + // 交换元素位置 + public swapItem(from: number, to: number): void { + let temp: string = this.list[from]; + this.list[from] = this.list[to]; + this.list[to] = temp; + this.notifyDataMove(from, to); + } +} \ No newline at end of file diff --git a/ArkUISample/ScrollableComponent/entry/src/main/ets/pages/grid/GridLayout.ets b/ArkUISample/ScrollableComponent/entry/src/main/ets/pages/grid/GridLayout.ets new file mode 100644 index 0000000000000000000000000000000000000000..464b10d7282f3dc3b451609145686325b01240cf --- /dev/null +++ b/ArkUISample/ScrollableComponent/entry/src/main/ets/pages/grid/GridLayout.ets @@ -0,0 +1,205 @@ +/* + * Copyright (c) 2025 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 { ComponentCard } from '../../common/Card'; + +@Entry +@Component +export struct GridLayout { + @State numbers: String[] = ['0', '1', '2', '3', '4', '5', '6', '7']; + scroller: Scroller = new Scroller(); + // [Start set_rows_and_columns_occupied] + layoutOptions: GridLayoutOptions = { + regularSize: [1, 1], + irregularIndexes: [1, 3, 4], // 索引为0和7的GridItem占用的列数由onGetIrregularSizeByIndex指定 + onGetIrregularSizeByIndex: (index: number) => { + if (index === 0) { + return [1, 5]; + } + return [1, index % 6 + 1]; + } + } + + // [StartExclude set_rows_and_columns_occupied] + build() { + NavDestination() { + Column({ space: 12 }) { + ComponentCard({ title: $r('app.string.GridLayout_titleRowSpacing') }) { + // [EndExclude set_rows_and_columns_occupied] + // [Start build_a_grid] + Grid() { + // [StartExclude build_a_grid] + GridItem() { + }.backgroundColor('#ffe0e2e4') + + GridItem() { + }.backgroundColor('#ffe0e2e4') + + GridItem() { + }.backgroundColor('#ffe0e2e4') + + GridItem() { + }.backgroundColor('#ffe0e2e4') + + GridItem() { + }.backgroundColor('#ffe0e2e4') + + GridItem() { + }.backgroundColor('#ffe0e2e4') + + GridItem() { + }.backgroundColor('#ffe0e2e4') + + GridItem() { + }.backgroundColor('#ffe0e2e4') + + GridItem() { + }.backgroundColor('#ffe0e2e4') + // [EndExclude build_a_grid] + } + //设置行列间距 + // [StartExclude build_a_grid] + .columnsGap(10) + .rowsGap(15) + .height(150) + // [EndExclude build_a_grid] + //设置行列数量与占比 + .rowsTemplate('1fr 1fr 1fr') + .columnsTemplate('1fr 2fr 1fr') + // [End build_a_grid] + // [End set_rows_and_columns_occupied] + } + + ComponentCard({ title: $r('app.string.GridLayout_titleChildSpan') }) { + Grid(undefined, this.layoutOptions) { + ForEach(this.numbers, (day: string) => { + GridItem() { + Text(day) + .fontSize(16) + .backgroundColor('#ffe0e2e4') + .width('100%') + .height(60) + .textAlign(TextAlign.Center) + } + }, (day: string) => day) + } + .columnsTemplate('1fr 1fr 1fr') + .columnsGap(10) + .rowsGap(10) + .scrollBar(BarState.Off) + .width('80%') + .height(210) + } + + ComponentCard({ title: $r('app.string.GridLayout_titleMainAxis') }) { + // [Start Set_the_direction_of_the_main_axis_of_the_grid] + Grid() { + // [StartExclude Set_the_direction_of_the_main_axis_of_the_grid] + GridItem() { + Text('1') + }.backgroundColor('#ffe0e2e4').width(30).height(30) + + GridItem() { + Text('2') + }.backgroundColor('#ffe0e2e4').width(30).height(30) + + GridItem() { + Text('3') + }.backgroundColor('#ffe0e2e4').width(30).height(30) + + GridItem() { + Text('4') + }.backgroundColor('#ffe0e2e4').width(30).height(30) + + GridItem() { + Text('5') + }.backgroundColor('#ffe0e2e4').width(30).height(30) + + GridItem() { + Text('6') + }.backgroundColor('#ffe0e2e4').width(30).height(30) + + GridItem() { + Text('7') + }.backgroundColor('#ffe0e2e4').width(30).height(30) + + GridItem() { + Text('8') + }.backgroundColor('#ffe0e2e4').width(30).height(30) + + GridItem() { + Text('9') + }.backgroundColor('#ffe0e2e4').width(30).height(30) + // [EndExclude Set_the_direction_of_the_main_axis_of_the_grid] + } + .maxCount(3) + // [StartExclude Set_the_direction_of_the_main_axis_of_the_grid] + .columnsGap(4) + .rowsGap(4) + // [EndExclude Set_the_direction_of_the_main_axis_of_the_grid] + .layoutDirection(GridDirection.Row) + // [End Set_the_direction_of_the_main_axis_of_the_grid] + + Grid() { + GridItem() { + Text('1') + }.backgroundColor('#ffe0e2e4').width(30).height(30) + + GridItem() { + Text('2') + }.backgroundColor('#ffe0e2e4').width(30).height(30) + + GridItem() { + Text('3') + }.backgroundColor('#ffe0e2e4').width(30).height(30) + + GridItem() { + Text('4') + }.backgroundColor('#ffe0e2e4').width(30).height(30) + + GridItem() { + Text('5') + }.backgroundColor('#ffe0e2e4').width(30).height(30) + + GridItem() { + Text('6') + }.backgroundColor('#ffe0e2e4').width(30).height(30) + + GridItem() { + Text('7') + }.backgroundColor('#ffe0e2e4').width(30).height(30) + + GridItem() { + Text('8') + }.backgroundColor('#ffe0e2e4').width(30).height(30) + + GridItem() { + Text('9') + }.backgroundColor('#ffe0e2e4').width(30).height(30) + } + .maxCount(3) + .columnsGap(4) + .rowsGap(4) + .layoutDirection(GridDirection.Column) + } + } + .width('100%') + .height('100%') + .padding({ left: 12, right: 12 }) + } + .backgroundColor('#f1f2f3') + .title($r('app.string.GridLayout_title')) + } +} \ No newline at end of file diff --git a/ArkUISample/ScrollableComponent/entry/src/main/ets/pages/grid/GridScrollbar.ets b/ArkUISample/ScrollableComponent/entry/src/main/ets/pages/grid/GridScrollbar.ets new file mode 100644 index 0000000000000000000000000000000000000000..26baf97ee43642d2a0f38a2557ae3b0748ca8149 --- /dev/null +++ b/ArkUISample/ScrollableComponent/entry/src/main/ets/pages/grid/GridScrollbar.ets @@ -0,0 +1,80 @@ +/* + * Copyright (c) 2025 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 { GridDataSource } from './GridDataSource'; +import { ComponentCard } from '../../common/Card'; + +@Entry +@Component +export struct GridScrollbar { + numbers: GridDataSource = new GridDataSource([]); + scroller: Scroller = new Scroller(); + @State gridPosition: number = 0; //0代表滚动到grid顶部,1代表中间值,2代表滚动到grid底部。 + + aboutToAppear() { + let list: string[] = []; + for (let i = 0; i < 5; i++) { + for (let j = 0; j < 5; j++) { + list.push(j.toString()); + } + } + this.numbers = new GridDataSource(list); + } + + build() { + NavDestination() { + Column({ space: 12 }) { + ComponentCard({ title: $r('app.string.GridScrollbar_title') }) { + Row({ space: 5 }) { + Grid(this.scroller) { + LazyForEach(this.numbers, (day: string) => { + GridItem() { + Text() + .fontSize(16) + .backgroundColor(0xF9CF93) + .width('100%') + .height(80) + .textAlign(TextAlign.Center) + } + }, (index: number) => index.toString()) + } + .columnsTemplate('1fr 1fr 1fr 1fr 1fr') + .columnsGap(10) + .rowsGap(10) + .friction(0.6) + .enableScrollInteraction(true) + .supportAnimation(false) + .multiSelectable(false) + .edgeEffect(EdgeEffect.Spring) + .scrollBar(BarState.Off) + .scrollBarColor(Color.Grey) + .scrollBarWidth(4) + .width('90%') + .backgroundColor(0xFAEEE0) + .height(300) + .margin({left:10}) + ScrollBar({ scroller: this.scroller }).height(300) + + }.width('100%').margin({ top: 5 }) + } + } + .width('100%') + .height('100%') + .padding({ left: 12, right: 12 }) + } + .backgroundColor('#f1f2f3') + .title($r('app.string.GridScrollbar_title')) + } +} \ No newline at end of file diff --git a/ArkUISample/ScrollableComponent/entry/src/main/ets/pages/grid/GridSideToSide.ets b/ArkUISample/ScrollableComponent/entry/src/main/ets/pages/grid/GridSideToSide.ets new file mode 100644 index 0000000000000000000000000000000000000000..9f70e84f3462ada4f8f1aa51c42cf39912ac010c --- /dev/null +++ b/ArkUISample/ScrollableComponent/entry/src/main/ets/pages/grid/GridSideToSide.ets @@ -0,0 +1,90 @@ +/* + * Copyright (c) 2025 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 { GridDataSource } from './GridDataSource'; +import { ComponentCard } from '../../common/Card'; + +@Entry +@Component +export struct GridSideToSide { + numbers: GridDataSource = new GridDataSource([]); + scroller: Scroller = new Scroller(); + @State gridPosition: number = 0; //0代表滚动到grid顶部,1代表中间值,2代表滚动到grid底部。 + @State data: number = 1; + + aboutToAppear() { + let list: string[] = []; + for (let i = 0; i < 7; i++) { + for (let j = 0; j < 10; j++) { + list.push(this.data.toString()); + this.data += 1; + if(this.data == 32) { + this.data = 0; + } + } + } + this.numbers = new GridDataSource(list); + } + + build() { + NavDestination() { + Column({ space: 12 }) { + ComponentCard({ title: $r('app.string.GridSideToSide_title') }) { + Column(){ + Grid(this.scroller) { + LazyForEach(this.numbers, (day: string) => { + GridItem() { + Text(day) + .fontSize(16) + .backgroundColor(0xF9CF93) + .width('100%') + .height(50) + .textAlign(TextAlign.Center) + } + }, (index: number) => index.toString()) + } + .columnsTemplate('1fr 1fr 1fr 1fr 1fr 1fr 1fr') + .columnsGap(10) + .rowsGap(10) + .width('90%') + .height(300) + .scrollBar(BarState.Off) + + Row({ space: 20 }) { + Button('上一页') + .onClick(() => { + this.scroller.scrollPage({ + next: false + }); + }) + + Button('下一页') + .onClick(() => { + this.scroller.scrollPage({ + next: true + }); + }) + } + } + } + } + .width('100%') + .height('100%') + .padding({ left: 12, right: 12 }) + } + .backgroundColor('#f1f2f3') + .title($r('app.string.GridSideToSide_title')) + } +} \ No newline at end of file diff --git a/ArkUISample/ScrollableComponent/entry/src/main/ets/pages/grid/LongGrid.ets b/ArkUISample/ScrollableComponent/entry/src/main/ets/pages/grid/LongGrid.ets new file mode 100644 index 0000000000000000000000000000000000000000..87258637d6da82b8872102a426a41dfad8add552 --- /dev/null +++ b/ArkUISample/ScrollableComponent/entry/src/main/ets/pages/grid/LongGrid.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. + */ + +import { ComponentCard } from '../../common/Card'; +import { GridDataSource } from './GridDataSource'; + +@Entry +@Component +export struct LongGrid { + numbers: GridDataSource = new GridDataSource([]); + scroller: Scroller = new Scroller(); + + aboutToAppear() { + let list: string[] = []; + for (let i = 0; i <= 10; i++) { + for (let j = 0; j < 5; j++) { + list.push(j.toString()); + } + } + this.numbers = new GridDataSource(list); + } + + build() { + NavDestination() { + Column({ space: 12 }) { + ComponentCard({ title: $r('app.string.LongGrid_title') }) { + Column({ space: 5 }) { + Grid(this.scroller) { + LazyForEach(this.numbers, (day: string) => { + GridItem() { + Text(day) + .fontSize(16) + .backgroundColor(0xF9CF93) + .width('100%') + .height(80) + .textAlign(TextAlign.Center) + } + }, (index: number) => index.toString()) + } + .columnsTemplate('1fr 1fr 1fr 1fr 1fr') + .columnsGap(10) + .rowsGap(20) + .edgeEffect(EdgeEffect.Spring, { alwaysEnabled: true, effectEdge: EffectEdge.START }) + .width('90%') + .backgroundColor(0xDCDCDC) + .height('80%') + + }.width('100%').margin({ top: 5 }) + } + } + .width('100%') + .height('100%') + .padding({ left: 12, right: 12 }) + } + .backgroundColor('#f1f2f3') + .title($r('app.string.LongGrid_title')) + } +} \ No newline at end of file diff --git a/ArkUISample/ScrollableComponent/entry/src/main/ets/pages/grid/ScrollPositionGrid.ets b/ArkUISample/ScrollableComponent/entry/src/main/ets/pages/grid/ScrollPositionGrid.ets new file mode 100644 index 0000000000000000000000000000000000000000..da773f1c37ed27e85c02d98ec3db72585f7fa335 --- /dev/null +++ b/ArkUISample/ScrollableComponent/entry/src/main/ets/pages/grid/ScrollPositionGrid.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. + */ + +import { ComponentCard } from '../../common/Card'; + +@Entry +@Component +export struct ScrollPosition { + @State services: Array = ['Live Streaming', 'Imported', 'Categories', 'Recharge', + 'Membership', 'Claim Coupon', 'Lottery', 'Favorites', 'Points', 'More']; + // [Start build_a_private_scrolling_object] + private scroller: Scroller = new Scroller(); + // [End build_a_private_scrolling_object] + + + build() { + NavDestination() { + Column({ space: 12 }) { + ComponentCard({ title: $r('app.string.ScrollPosition_titleExample') }) { + // [Start control_the_grid_scroll] + Column({ space: 12 }) { + Grid(this.scroller) { + // [StartExclude control_the_grid_scroll] + ForEach(this.services, (service: string) => { + GridItem() { + Text(service) + }.backgroundColor('#FFF1F3F5').width('25%') + }, (service: string): string => service) + // [EndExclude control_the_grid_scroll] + } + // [StartExclude control_the_grid_scroll] + .height(100) + .columnsGap(10) + // [EndExclude control_the_grid_scroll] + .rowsTemplate('1fr') + + Row({ space: 20 }) { + Button('Previous') + .onClick(() => { + this.scroller.scrollPage({ next: false }); + }) + + Button('Next') + .onClick(() => { + this.scroller.scrollPage({ next: true }); + }) + } + } + // [End control_the_grid_scroll] + } + } + .width('100%') + .height('100%') + .padding({ left: 12, right: 12 }) + } + .backgroundColor('#f1f2f3') + .title($r('app.string.ScrollPosition_title')) + } +} \ No newline at end of file diff --git a/ArkUISample/ScrollableComponent/entry/src/main/ets/pages/grid/ScrollableGrid.ets b/ArkUISample/ScrollableComponent/entry/src/main/ets/pages/grid/ScrollableGrid.ets new file mode 100644 index 0000000000000000000000000000000000000000..288ed72065440598d7edf5a99e8c68c7e4bfde69 --- /dev/null +++ b/ArkUISample/ScrollableComponent/entry/src/main/ets/pages/grid/ScrollableGrid.ets @@ -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. + */ + +import { ComponentCard } from '../../common/Card'; + +// [Start build_scrollable_horizontally_grid_layouts] +@Entry +@Component +export struct ScrollableGrid { + @State services: Array = ['Live Streaming', 'Imported', 'Categories', 'Recharge', + 'Membership', 'Claim Coupon', 'Lottery', 'Favorites', 'Points', 'More']; + + build() { + NavDestination() { + Column({ space: 12 }) { + ComponentCard({ title: $r('app.string.ScrollableGrid_titleHorizontal') }) { + Grid() { + ForEach(this.services, (service: string) => { + GridItem() { + Text(service) + }.backgroundColor('#FFF1F3F5').width('25%') + }, (service: string): string => service) + } + // [StartExclude build_scrollable_horizontally_grid_layouts] + .height(200) + .columnsGap(10) + // [EndExclude build_scrollable_horizontally_grid_layouts] + .rowsGap(15) + .rowsTemplate('1fr 1fr') // 只设置rowsTemplate属性,当内容超出Grid区域时,可水平滚动。 + } + } + // [End build_scrollable_horizontally_grid_layouts] + .width('100%') + .height('100%') + .padding({ left: 12, right: 12 }) + } + .backgroundColor('#f1f2f3') + .title($r('app.string.ScrollableGrid_title')) + } +} \ No newline at end of file diff --git a/ArkUISample/ScrollableComponent/entry/src/main/ets/pages/grid/index.ets b/ArkUISample/ScrollableComponent/entry/src/main/ets/pages/grid/index.ets new file mode 100644 index 0000000000000000000000000000000000000000..99fc49c2e440fb3a2d5ed55f11157005ee7b7527 --- /dev/null +++ b/ArkUISample/ScrollableComponent/entry/src/main/ets/pages/grid/index.ets @@ -0,0 +1,115 @@ +/* + * Copyright (c) 2025 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { CompletedRoutableCard } from '../../common/Card'; +import { DataInGrid } from './DataInGrid'; +import { GridLayout } from './GridLayout'; +import { Route } from '../../common/Route'; +import { ScrollableGrid } from './ScrollableGrid'; +import { ScrollPosition } from './ScrollPositionGrid'; +import { GridSideToSide } from './GridSideToSide'; +import { GridScrollbar } from './GridScrollbar'; +import { LongGrid } from './LongGrid'; +import resource from '../../common/resource'; + +export const GRID_ROUTE_PREFIX: string = 'grid'; + +const routes: Route[] = [ + { + name: `${GRID_ROUTE_PREFIX}/GridLayout`, + title: resource.resourceToString($r('app.string.GridLayout_title')), + description: $r('app.string.GridLayout_description') + }, + { + name: `${GRID_ROUTE_PREFIX}/DataInGrid`, + title: resource.resourceToString($r('app.string.DataInGrid_title')), + description: $r('app.string.DataInGrid_description') + }, + { + name: `${GRID_ROUTE_PREFIX}/ScrollableGrid`, + title: resource.resourceToString($r('app.string.ScrollableGrid_title')), + description: $r('app.string.ScrollableGrid_description') + }, + { + name: `${GRID_ROUTE_PREFIX}/ScrollPosition`, + title: resource.resourceToString($r('app.string.ScrollPosition_title')), + description: $r('app.string.ScrollPosition_description') + }, + { + name: `${GRID_ROUTE_PREFIX}/GridSideToSide`, + title: resource.resourceToString($r('app.string.GridSideToSide_title')), + description: $r('app.string.GridSideToSide_description') + }, + { + name: `${GRID_ROUTE_PREFIX}/GridScrollbar`, + title: resource.resourceToString($r('app.string.GridScrollbar_title')), + description: $r('app.string.GridScrollbar_description') + }, + { + name: `${GRID_ROUTE_PREFIX}/LongGrid`, + title: resource.resourceToString($r('app.string.LongGrid_title')), + description: $r('app.string.LongGrid_description') + } +]; + +@Builder +export function gridDestination(name: string) { + if (name === GRID_ROUTE_PREFIX) { + GridExample(); + } else if (name === routes[0].name) { + GridLayout(); + } else if (name === routes[1].name) { + DataInGrid(); + } else if (name === routes[2].name) { + ScrollableGrid(); + } else if (name === routes[3].name) { + ScrollPosition(); + } else if (name === routes[4].name) { + GridSideToSide(); + } else if (name === routes[5].name) { + GridScrollbar(); + } else if (name === routes[6].name) { + LongGrid(); + } +} + +@Entry +@Component +struct GridExample { + @Consume pathStack: NavPathStack; + + build() { + NavDestination() { + List({ space: 12 }) { + ForEach(routes, (route: Route) => { + ListItem() { + CompletedRoutableCard({ title: route.title, description: route.description }) + } + .width('100%') + .onClick(() => { + this.pathStack.pushPath({ name: route.name }); + }) + }) + } + .contentStartOffset(56) + .padding({ left: 16, right: 16 }) + } + .backgroundColor('#f1f3f5') + .title('Grid', { + backgroundBlurStyle: BlurStyle.COMPONENT_THICK, + barStyle: BarStyle.STACK + }) + } +} \ No newline at end of file diff --git a/ArkUISample/ScrollableComponent/entry/src/main/ets/pages/list/AddListItem.ets b/ArkUISample/ScrollableComponent/entry/src/main/ets/pages/list/AddListItem.ets new file mode 100644 index 0000000000000000000000000000000000000000..befa4ca236b5c617a222d87786323ebb9fbb7cd9 --- /dev/null +++ b/ArkUISample/ScrollableComponent/entry/src/main/ets/pages/list/AddListItem.ets @@ -0,0 +1,154 @@ + /* + * Copyright (c) 2025 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 { ComponentCard } from '../../common/Card'; +// [Start define_the_data_to_be_done] +import { util } from '@kit.ArkTS'; + + +export class ToDo { + public key: string = util.generateRandomUUID(true); + public name: string; + + constructor(name: string) { + this.name = name; + } +} +// [End define_the_data_to_be_done] + +// [Start build_the_overall_list_layout_and_list_items] +@Component +export struct ToDoListItem { + @Link isEditMode: boolean; + @Link selectedItems: ToDo[]; + private toDoItem: ToDo = new ToDo(''); + + build() { + Flex({ justifyContent: FlexAlign.SpaceBetween, alignItems: ItemAlign.Center }) { + // [StartExclude build_the_overall_list_layout_and_list_items] + Text(this.toDoItem.name) + .fontSize(16) + .width('80%') + .margin({ left: 20 }) + // [EndExclude build_the_overall_list_layout_and_list_items] + } + .backgroundColor('#FFF1F3F5') + .width('100%') + .height(40) + // .padding() 根据具体使用场景设置 + .borderRadius(12) + // .linearGradient() 根据具体使用场景设置 + .gesture( + // [StartExclude build_the_overall_list_layout_and_list_items] + GestureGroup(GestureMode.Exclusive, + LongPressGesture() + // [EndExclude build_the_overall_list_layout_and_list_items] + .onAction(() => { + }) + ) + ) + } +} +// [End build_the_overall_list_layout_and_list_items] + +// [Start build_list_layouts_and_list_items] +@Entry +@Component +export struct AddListItem { + private l1 = 0; + private l2 = 0; + // [StartExclude build_list_layouts_and_list_items] + @State arr: number[] = [0, 1, 2, 3] + @State toDoData: ToDo[] = [] + // [EndExclude build_list_layouts_and_list_items] + @Watch('onEditModeChange') @State isEditMode: boolean = false + @State selectedItems: ToDo[] = [] + private availableThings: string[] = ['Reading', 'Exercise', 'Travel', 'Listening Music', 'Watching Films', 'Singing']; + + onEditModeChange() { + if (!this.isEditMode) { + this.selectedItems = []; + } + } + + build() { + // [StartExclude build_list_layouts_and_list_items] + NavDestination() { + // [EndExclude build_list_layouts_and_list_items] + Column({ space: 12 }) { + // [StartExclude build_list_layouts_and_list_items] + ComponentCard({ title: $r('app.string.AddListItem_titleExample') }) { + // [EndExclude build_list_layouts_and_list_items] + Column({ space: 12 }) { + Row() { + if (this.isEditMode) { + Text('X') + .fontSize(20) + .onClick(() => { + this.isEditMode = false; + }) + .margin({ left: 20, right: 20 }) + } else { + Text($r('app.string.TodoItem')) + .fontSize(30) + .margin({ left: 20 }) + Blank() + Text('+')// 提供新增列表项入口,即给新增按钮添加点击事件 + .fontSize(36) + .margin({ right: 20 }) + .onClick(() => { + this.getUIContext().showTextPickerDialog({ + range: this.availableThings, + onAccept: (value: TextPickerResult) => { + let arr = Array.isArray(value.index) ? value.index : [value.index]; + for (let i = 0; i < arr.length; i++) { + this.toDoData.push(new ToDo(this.availableThings[arr[i]])); // 新增列表项数据toDoData(可选事项) + } + }, + }) + }) + } + } + // [StartExclude build_list_layouts_and_list_items] + .width('100%') + .backgroundColor('#FFF1F3F5') + .borderRadius(12) + .height(45) + // [EndExclude build_list_layouts_and_list_items] + + List({ space: 12 }) { + ForEach(this.toDoData, (toDoItem: ToDo) => { + ListItem() { + // 将toDoData的每个数据放入到以model的形式放进ListItem里 + ToDoListItem({ + isEditMode: this.isEditMode, + toDoItem: toDoItem, + selectedItems: this.selectedItems + }) + } + }, (toDoItem: ToDo) => toDoItem.name.toString()) + } + } + } + } + // [End build_list_layouts_and_list_items] + .width('100%') + .height('100%') + .padding({ left: 12, right: 12 }) + } + .backgroundColor('#f1f2f3') + .title($r('app.string.AddListItem_title')) + } +} \ No newline at end of file diff --git a/ArkUISample/ScrollableComponent/entry/src/main/ets/pages/list/CollapseAndExpand.ets b/ArkUISample/ScrollableComponent/entry/src/main/ets/pages/list/CollapseAndExpand.ets new file mode 100644 index 0000000000000000000000000000000000000000..1c4cc17fd5bc5f80f79ba8cda01072ab7378e443 --- /dev/null +++ b/ArkUISample/ScrollableComponent/entry/src/main/ets/pages/list/CollapseAndExpand.ets @@ -0,0 +1,184 @@ +/* + * Copyright (c) 2025 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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'; +import { ComponentCard } from '../../common/Card'; + +interface ItemInfo { + index: number, + name: string, + label: ResourceStr, + type?: string, +} + +interface ItemGroupInfo extends ItemInfo { + children: ItemInfo[] +} + + +@Entry +@Component +export struct CollapseAndExpand { + @State routes: ItemGroupInfo[] = [ + { + index: 0, + name: 'basicInfo', + label: '个人基本资料', + children: [ + { + index: 0, + name: '昵称', + label: 'xxxx', + type: 'Text' + }, + { + index: 1, + name: '头像', + label: $r('sys.media.ohos_user_auth_icon_face'), + type: 'Image' + }, + { + index: 2, + name: '年龄', + label: 'xxxx', + type: 'Text' + }, + { + index: 3, + name: '生日', + label: 'xxxxxxxxx', + type: 'Text' + }, + { + index: 4, + name: '性别', + label: 'xxxxxxxx', + type: 'Text' + }, + ] + }, + { + index: 1, + name: 'equipInfo', + label: '设备信息', + children: [] + }, + { + index: 2, + name: 'appInfo', + label: '应用使用信息', + children: [] + }, + { + index: 3, + name: 'uploadInfo', + label: '您主动上传的数据', + children: [] + }, + { + index: 4, + name: 'tradeInfo', + label: '交易与资产信息', + children: [] + }, + { + index: 5, + name: 'otherInfo', + label: '其他资料', + children: [] + }, + ]; + + @State expandedItems: boolean[] = Array(this.routes.length).fill(false); + @State selection: string | null = null; + + @Builder + ListItemGroupHeader(itemGroup: ItemGroupInfo) { + Row() { + Text(itemGroup.label) + Blank() + Image($r('sys.media.ohos_ic_public_arrow_down')) + .fillColor($r('sys.color.ohos_id_color_fourth')) + .height(30) + .width(30) + .rotate({ angle: !!itemGroup.children.length ? (this.expandedItems[itemGroup.index] ? 180 : 0) : 180 }) + .animation({ curve: curves.interpolatingSpring(0, 1, 228, 22) }) + } + .width("100%") + .padding(10) + .animation({ curve: curves.interpolatingSpring(0, 1, 528, 39) }) + .onClick(() => { + if (itemGroup.children.length) { + this.getUIContext()?.animateTo({ curve: curves.interpolatingSpring(0, 1, 528, 39) }, () => { + this.expandedItems[itemGroup.index] = !this.expandedItems[itemGroup.index]; + }) + } + }) + } + build() { + NavDestination() { + Column({ space: 12 }) { + ComponentCard({ title: $r('app.string.CollapseAndExpand_title') }) { + Column() { + List({ space: 10 }) { + ForEach(this.routes, (itemGroup: ItemGroupInfo) => { + ListItemGroup({ + header: this.ListItemGroupHeader(itemGroup), + style: ListItemGroupStyle.CARD, + }) { + if (this.expandedItems[itemGroup.index] && itemGroup.children) { + ForEach(itemGroup.children, (item: ItemInfo) => { + ListItem({ style: ListItemStyle.CARD }) { + Row() { + Text(item.name) + Blank() + if (item.type === 'Image') { + Image(item.label) + .height(20) + .width(20) + } else { + Text(item.label) + } + Image($r('sys.media.ohos_ic_public_arrow_right')) + .fillColor($r('sys.color.ohos_id_color_fourth')) + .height(30) + .width(30) + } + .width("100%") + } + .width("100%") + .animation({ curve: curves.interpolatingSpring(0, 1, 528, 39) }) + }) + } + }.clip(true) + }) + } + .width("100%") + } + .width('100%') + .height('100%') + .justifyContent(FlexAlign.Start) + .backgroundColor($r('sys.color.ohos_id_color_sub_background')) + } + } + .width('100%') + .height('100%') + .padding({ left: 12, right: 12 }) + } + .backgroundColor('#f1f2f3') + .title($r('app.string.CollapseAndExpand_title')) + } + +} \ No newline at end of file diff --git a/ArkUISample/ScrollableComponent/entry/src/main/ets/pages/list/ControlledScrollPositionList.ets b/ArkUISample/ScrollableComponent/entry/src/main/ets/pages/list/ControlledScrollPositionList.ets new file mode 100644 index 0000000000000000000000000000000000000000..fe9700cfd7503197f185a9d8299472e3644df987 --- /dev/null +++ b/ArkUISample/ScrollableComponent/entry/src/main/ets/pages/list/ControlledScrollPositionList.ets @@ -0,0 +1,76 @@ +/* + * Copyright (c) 2025 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { ComponentCard } from '../../common/Card'; + +@Entry +@Component +export struct ControlledScrollPositionList { + // [Start create_private_list_scroller] + private listScroller: Scroller = new Scroller(); + // [End create_private_list_scroller] + private arr: number[] = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]; + + build() { + NavDestination() { + Column({ space: 12 }) { + ComponentCard({ title: $r('app.string.ControlledScrollPositionList_titleExample') }) { + // [Start control_scrolling] + Stack({ alignContent: Alignment.Bottom }) { + // 控制滚动位置示例List容器 + // 将listScroller用于初始化List组件的scroller参数,完成listScroller与列表的绑定。 + List({ space: 20, scroller: this.listScroller }) { + // ... + // [StartExclude control_scrolling] + ForEach(this.arr, (item: number) => { + ListItem() { + Text('新闻' + item) + .width('100%') + .height(100) + .fontSize(16) + .textAlign(TextAlign.Center) + .borderRadius(10) + .backgroundColor('#FFF1F3F5') + } + }, (item: number) => item.toString()) + // [EndExclude control_scrolling] + } + + Button() { + // [StartExclude control_scrolling] + // ... + Image($r('sys.media.ohos_ic_public_arrow_up')).width(40).height(40) + // [EndExclude control_scrolling] + } + // [StartExclude control_scrolling] + .backgroundColor('#FFE0E2E4') + .position({ x: '80%', y: '90%' }) + // [EndExclude control_scrolling] + .onClick(() => { + // 点击按钮时,指定跳转位置,返回列表顶部 + this.listScroller.scrollToIndex(0); + // [End control_scrolling] + }) + }.height('90%') + } + } + .width('100%') + .height('100%') + .padding({ left: 12, right: 12 }) + } + .backgroundColor('#f1f2f3') + .title($r('app.string.ControlledScrollPositionList_title')) + } +} \ No newline at end of file diff --git a/ArkUISample/ScrollableComponent/entry/src/main/ets/pages/list/CustomListStyle.ets b/ArkUISample/ScrollableComponent/entry/src/main/ets/pages/list/CustomListStyle.ets new file mode 100644 index 0000000000000000000000000000000000000000..b61ca2a29c1f41a54f6638615764c5f3f50ec91b --- /dev/null +++ b/ArkUISample/ScrollableComponent/entry/src/main/ets/pages/list/CustomListStyle.ets @@ -0,0 +1,104 @@ +/* + * Copyright (c) 2025 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { ComponentCard } from '../../common/Card'; + +// [Start set_the_divider] +class DividerTmp { + public strokeWidth: Length = 1; + public startMargin: Length = 60; + public endMargin: Length = 10; + public color: ResourceColor = '#ffe9f0f0'; + + constructor(strokeWidth: Length, startMargin: Length, endMargin: Length, color: ResourceColor) { + this.strokeWidth = strokeWidth; + this.startMargin = startMargin; + this.endMargin = endMargin; + this.color = color; + } +} + +@Entry +@Component +export struct CustomListStyle { + @State egDivider: DividerTmp = new DividerTmp(1, 60, 10, '#ffe9f0f0'); + + build() { + // [StartExclude set_the_divider] + NavDestination() { + Column({ space: 12 }) { + ComponentCard({ title: $r('app.string.CustomListStyle_titleContentSpacing') }) { + List({ space: 10 }) { + ListItem() { + Text('ListItem One') + } + + ListItem() { + Text('ListItem Two') + } + } + .backgroundColor('#FFF1F3F5') + .alignListItem(ListItemAlign.Center) + } + + ComponentCard({ title: $r('app.string.CustomListStyle_titleDividerLines') }) { + // [EndExclude set_the_divider] + List({ space: 10 }) { + ListItem() { + Text('ListItem One') + } + + ListItem() { + Text('ListItem Two') + } + } + .divider(this.egDivider) + .alignListItem(ListItemAlign.Center) + } + // [End set_the_divider] + + ComponentCard({ title: $r('app.string.CustomListStyle_titleScrollbars') }) { + // [Start add_a_scrollbar] + List({ space: 10 }) { + // [StartExclude add_a_scrollbar] + ListItem() { + Text('ListItem One') + }.height(30) + + ListItem() { + Text('ListItem Two') + }.height(30) + + ListItem() { + Text('ListItem Three') + }.height(30) + // [EndExclude add_a_scrollbar] + } + // [StartExclude add_a_scrollbar] + .height(60) + // [EndExclude add_a_scrollbar] + .scrollBar(BarState.Auto) + // [End add_a_scrollbar] + .backgroundColor('#FFF1F3F5') + } + } + .width('100%') + .height('100%') + .padding({ left: 12, right: 12 }) + } + .backgroundColor('#f1f2f3') + .title($r('app.string.CustomListStyle_title')) + } +} \ No newline at end of file diff --git a/ArkUISample/ScrollableComponent/entry/src/main/ets/pages/list/DataInList.ets b/ArkUISample/ScrollableComponent/entry/src/main/ets/pages/list/DataInList.ets new file mode 100644 index 0000000000000000000000000000000000000000..1a4832087e576b0a12b577a4543e482469b5dde2 --- /dev/null +++ b/ArkUISample/ScrollableComponent/entry/src/main/ets/pages/list/DataInList.ets @@ -0,0 +1,87 @@ + +/* + * Copyright (c) 2025 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 { ComponentCard } from '../../common/Card'; + +// [Start list_statically_creates_the_contents_of_list_item] +@Entry +@Component +export struct DataInList { + build() { + // [StartExclude list_statically_creates_the_contents_of_list_item] + NavDestination() { + Column({ space: 12 }) { + ComponentCard({ title: $r('app.string.DataInList_titleCityList') }) { + // [EndExclude list_statically_creates_the_contents_of_list_item] + List() { + ListItem() { + Text($r('app.string.city_beijing')) + .fontSize(24) + } + + ListItem() { + Text($r('app.string.city_hangzhou')) + .fontSize(24) + } + + ListItem() { + Text($r('app.string.city_shanghai')) + .fontSize(24) + } + } + .backgroundColor('#FFF1F3F5') + .alignListItem(ListItemAlign.Center) + } + // [End list_statically_creates_the_contents_of_list_item] + + ComponentCard({ title: $r('app.string.DataInList_titleContactsList') }) { + // [Start encapsulate_the_image_and_text_into_a_row] + List() { + ListItem() { + Row() { + Image($r('sys.media.ohos_ic_public_phone')) + .width(40) + .height(40) + .margin(10) + + Text($r('app.string.peopleOne')) + .fontSize(20) + } + } + + ListItem() { + Row() { + Image($r('sys.media.ohos_ic_public_phone')) + .width(40) + .height(40) + .margin(10) + + Text($r('app.string.peopleTwo')) + .fontSize(20) + } + } + } + } + } + // [End encapsulate_the_image_and_text_into_a_row] + .width('100%') + .height('100%') + .padding({ left: 12, right: 12 }) + } + .backgroundColor('#f1f2f3') + .title($r('app.string.DataInList_titlePage')) + } +} \ No newline at end of file diff --git a/ArkUISample/ScrollableComponent/entry/src/main/ets/pages/list/DeleteListItem.ets b/ArkUISample/ScrollableComponent/entry/src/main/ets/pages/list/DeleteListItem.ets new file mode 100644 index 0000000000000000000000000000000000000000..6948f3a13eb5a1a4fe63646227f8f51bf42ac8fa --- /dev/null +++ b/ArkUISample/ScrollableComponent/entry/src/main/ets/pages/list/DeleteListItem.ets @@ -0,0 +1,173 @@ +/* + * Copyright (c) 2025 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 { util } from '@kit.ArkTS'; + +// [Start structural_references] +export class ToDo { + public key: string = util.generateRandomUUID(true); + public name: string; + + constructor(name: string) { + this.name = name; + } +} +// [End structural_references] + +@Component +export struct ToDoListItem { + @Link isEditMode: boolean; + @Link selectedItems: ToDo[]; + private toDoItem: ToDo = new ToDo(''); + + build() { + // [Start enter_edit_mode] + Flex({ justifyContent: FlexAlign.SpaceBetween, alignItems: ItemAlign.Center }) { + // [StartExclude enter_edit_mode] + Text(this.toDoItem.name) + .fontSize(16) + .width('80%') + .margin({ left: 20 }) + if (this.isEditMode) { + Checkbox() + .onChange((value: boolean) => { + if (value) { + this.selectedItems.push(new ToDo(this.toDoItem.name)); + this.isEditMode = true; + } + }) + } + } + .backgroundColor('#FFF1F3F5') + .width('100%') + .height(40) + .borderRadius(12) + // [EndExclude enter_edit_mode] + .gesture( + GestureGroup(GestureMode.Exclusive, + LongPressGesture() + .onAction(() => { + this.isEditMode = true; + }) + ) + ) + } +} +// [End enter_edit_mode] + +@Entry +@Component +export struct DeleteListItem { + @State arr: number[] = [0, 1, 2, 3]; + @State toDoData: ToDo[] = []; + @Watch('onEditModeChange') @State isEditMode: boolean = false; + @State selectedItems: ToDo[] = []; + private availableThings: string[] = ['Reading', 'Exercise', 'Travel', 'Listening Music', 'Watching Films', 'Singing']; + + public deleteToDoData() { + this.toDoData = []; + } + + onEditModeChange() { + if (!this.isEditMode) { + this.selectedItems = []; + } + } + + build() { + NavDestination() { + Column({ space: 12 }) { + Column({ space: 8 }) { + Text($r('app.string.DeleteListItem_titleExample')) + .fontSize(14) + .fontColor('#666') + Column({ space: 10 }) { + Row() { + if (this.isEditMode) { + Text('X') + .fontSize(20) + .onClick(() => { + this.isEditMode = false; + }) + .margin({ left: 20, right: 20 }) + } else { + Text($r('app.string.TodoItem')) + .fontSize(30) + .margin({ left: 20 }) + Blank() + Text('+')// 提供新增列表项入口,即给新增按钮添加点击事件 + .fontSize(36) + .margin({ right: 20 }) + .onClick(() => { + this.getUIContext().showTextPickerDialog({ + range: this.availableThings, + onAccept: (value: TextPickerResult) => { + let arr = Array.isArray(value.index) ? value.index : [value.index]; + for (let i = 0; i < arr.length; i++) { + this.toDoData.push(new ToDo(this.availableThings[arr[i]])); // 新增列表项数据toDoData(可选事项) + } + }, + }) + }) + } + } + .width('100%') + .backgroundColor('#FFF1F3F5') + .borderRadius(12) + .height(45) + + List({ space: 12 }) { + ForEach(this.toDoData, (toDoItem: ToDo) => { + ListItem() { + // 将toDoData的每个数据放入到以model的形式放进ListItem里 + ToDoListItem({ + isEditMode: this.isEditMode, + toDoItem: toDoItem, + selectedItems: this.selectedItems + }) + } + }, (toDoItem: ToDo) => toDoItem.name.toString()) + } + } + } + .alignItems(HorizontalAlign.Start) + .backgroundColor('#fff') + .borderRadius(12) + .padding(12) + .width('100%') + + if (this.isEditMode) { + Column({ space: 8 }) { + // [Start implement_deletion] + Button('delete') + .width('90%') + .backgroundColor(Color.Red) + .onClick(() => { + this.toDoData = this.toDoData.filter(toDoItem => + !this.selectedItems.some(selectedItem => selectedItem.name === toDoItem.name)); + this.isEditMode = false; + }) + } + } + } + // [End implement_deletion] + .width('100%') + .height('100%') + .padding({ left: 12, right: 12 }) + } + .backgroundColor('#f1f2f3') + .title($r('app.string.DeleteListItem_title')) + } +} \ No newline at end of file diff --git a/ArkUISample/ScrollableComponent/entry/src/main/ets/pages/list/GroupedList.ets b/ArkUISample/ScrollableComponent/entry/src/main/ets/pages/list/GroupedList.ets new file mode 100644 index 0000000000000000000000000000000000000000..8bae8f53c90c81997957585aca9c3aefca5119f0 --- /dev/null +++ b/ArkUISample/ScrollableComponent/entry/src/main/ets/pages/list/GroupedList.ets @@ -0,0 +1,73 @@ +/* + * Copyright (c) 2025 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 { ComponentCard } from '../../common/Card'; + +// [Start set_the_head_component_of_the_list_grouping_by_header] +@Entry +@Component +export struct GroupedList { + @Builder + itemHead(text: string) { + // 列表分组的头部组件,对应联系人分组A、B等位置的组件 + Text(text) + .fontSize(20) + .backgroundColor('#fff1f3f5') + .width('100%') + .padding(5) + } + + build() { + NavDestination() { + Column({ space: 12 }) { + ComponentCard({ title: $r('app.string.GroupedList_titleExample') }) { + List({ space: 12 }) { + ListItemGroup({ header: this.itemHead('A') }) { + // 循环渲染分组A的ListItem + // [StartExclude set_the_head_component_of_the_list_grouping_by_header] + ListItem() { + Text('ListItem A One') + } + + ListItem() { + Text('ListItem A Two') + } + // [EndExclude set_the_head_component_of_the_list_grouping_by_header] + } + + ListItemGroup({ header: this.itemHead('B') }) { + // 循环渲染分组B的ListItem + // [StartExclude set_the_head_component_of_the_list_grouping_by_header] + ListItem() { + Text('ListItem B One') + } + + ListItem() { + Text('ListItem B Two') + } + // [EndExclude set_the_head_component_of_the_list_grouping_by_header] + } + } + } + } + // [End set_the_head_component_of_the_list_grouping_by_header] + .width('100%') + .height('100%') + .padding({ left: 12, right: 12 }) + } + .backgroundColor('#f1f2f3') + .title($r('app.string.GroupedList_title')) + } +} \ No newline at end of file diff --git a/ArkUISample/ScrollableComponent/entry/src/main/ets/pages/list/Index.ets b/ArkUISample/ScrollableComponent/entry/src/main/ets/pages/list/Index.ets new file mode 100644 index 0000000000000000000000000000000000000000..fbc9b904b59bc686e7158a4b6355c0c8091880cd --- /dev/null +++ b/ArkUISample/ScrollableComponent/entry/src/main/ets/pages/list/Index.ets @@ -0,0 +1,179 @@ +/* + * Copyright (c) 2025 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 { AddListItem } from './AddListItem'; +import { CompletedRoutableCard } from '../../common/Card'; +import { ControlledScrollPositionList } from './ControlledScrollPositionList'; +import { CustomListStyle } from './CustomListStyle'; +import { DataInList } from './DataInList'; +import { DeleteListItem } from './DeleteListItem'; +import { GroupedList } from './GroupedList'; +import { ListIteration } from './ListIteration'; +import { ListLayout } from './ListLayout'; +import { ResponsiveScrollPositionList } from './ResponsiveScrollPositionList'; +import { Route } from '../../common/Route'; +import { StickyHeaderList } from './StickyHeaderList'; +import { SwipeListItem } from './SwipeableListItem'; +import { TaggedListItems } from './TaggedListItems'; +import { CollapseAndExpand } from './CollapseAndExpand'; +import { LongList } from './LongList'; +import { ListChatRoom } from './ListChatRoom'; +import resource from '../../common/resource'; + +export const List_ROUTE_PREFIX: string = 'list'; + +const routes: Route[] = [ + { + name: `${List_ROUTE_PREFIX}/ListLayout`, + title: resource.resourceToString($r('app.string.ListLayout_title')), + description: $r('app.string.ListLayout_description') + }, + { + name: `${List_ROUTE_PREFIX}/DataInList`, + title: resource.resourceToString($r('app.string.DataInList_title')), + description: $r('app.string.DataInList_description') + }, + { + name: `${List_ROUTE_PREFIX}/ListIteration`, + title: resource.resourceToString($r('app.string.ListIteration_title')), + description: $r('app.string.ListIteration_description') + }, + { + name: `${List_ROUTE_PREFIX}/CustomListStyle`, + title: resource.resourceToString($r('app.string.CustomListStyle_title')), + description: $r('app.string.CustomListStyle_description') + }, + { + name: `${List_ROUTE_PREFIX}/GroupedList`, + title: resource.resourceToString($r('app.string.GroupedList_title')), + description: $r('app.string.GroupedList_description') + }, + { + name: `${List_ROUTE_PREFIX}/StickyHeaderList`, + title: resource.resourceToString($r('app.string.StickyHeaderList_title')), + description: $r('app.string.StickyHeaderList_description') + }, + { + name: `${List_ROUTE_PREFIX}/ControlledScrollPositionList`, + title: resource.resourceToString($r('app.string.ControlledScrollPositionList_title')), + description: $r('app.string.ControlledScrollPositionList_description') + }, + { + name: `${List_ROUTE_PREFIX}/ResponsiveScrollPositionList`, + title: resource.resourceToString($r('app.string.ResponsiveScrollPositionList_title')), + description: $r('app.string.ResponsiveScrollPositionList_description') + }, + { + name: `${List_ROUTE_PREFIX}/SwipeListItem`, + title: resource.resourceToString($r('app.string.SwipeListItem_title')), + description: $r('app.string.SwipeListItem_description') + }, + { + name: `${List_ROUTE_PREFIX}/TaggedListItems`, + title: resource.resourceToString($r('app.string.TaggedListItems_title')), + description: $r('app.string.TaggedListItems_description') + }, + { + name: `${List_ROUTE_PREFIX}/AddListItem`, + title: resource.resourceToString($r('app.string.AddListItem_title')), + description: $r('app.string.AddListItem_description') + }, + { + name: `${List_ROUTE_PREFIX}/DeleteListItem`, + title: resource.resourceToString($r('app.string.DeleteListItem_title')), + description: $r('app.string.DeleteListItem_description') + }, + { + name: `${List_ROUTE_PREFIX}/LongList`, + title: resource.resourceToString($r('app.string.LongList_title')), + description: $r('app.string.LongList_description') + }, + { + name: `${List_ROUTE_PREFIX}/CollapseAndExpand`, + title: resource.resourceToString($r('app.string.CollapseAndExpand_title')), + description: $r('app.string.CollapseAndExpand_description') + }, + { + name: `${List_ROUTE_PREFIX}/ListChatRoom`, + title: resource.resourceToString($r('app.string.ListChatRoom_title')), + description: $r('app.string.ListChatRoom_description') + } +]; + +@Builder +export function listDestination(name: string) { + if (name === List_ROUTE_PREFIX) { + ListExample(); + } else if (name === routes[0].name) { + ListLayout(); + } else if (name === routes[1].name) { + DataInList(); + } else if (name === routes[2].name) { + ListIteration(); + } else if (name === routes[3].name) { + CustomListStyle(); + } else if (name === routes[4].name) { + GroupedList(); + } else if (name === routes[5].name) { + StickyHeaderList(); + } else if (name === routes[6].name) { + ControlledScrollPositionList(); + } else if (name === routes[7].name) { + ResponsiveScrollPositionList(); + } else if (name === routes[8].name) { + SwipeListItem(); + } else if (name === routes[9].name) { + TaggedListItems(); + } else if (name === routes[10].name) { + AddListItem(); + } else if (name === routes[11].name) { + DeleteListItem(); + } else if (name === routes[12].name) { + LongList(); + } else if (name === routes[13].name) { + CollapseAndExpand(); + } else if (name === routes[14].name) { + ListChatRoom(); + } +} + +@Entry +@Component +struct ListExample { + @Consume pathStack: NavPathStack; + + build() { + NavDestination() { + List({ space: 12 }) { + ForEach(routes, (route: Route) => { + ListItem() { + CompletedRoutableCard({ title: route.title, description: route.description }) + } + .width('100%') + .onClick(() => { + this.pathStack.pushPath({ name: route.name }); + }) + }) + } + .contentStartOffset(56) + .padding({ left: 16, right: 16 }) + } + .backgroundColor('#f1f3f5') + .title('List', { + backgroundBlurStyle: BlurStyle.COMPONENT_THICK, + barStyle: BarStyle.STACK + }) + } +} \ No newline at end of file diff --git a/ArkUISample/ScrollableComponent/entry/src/main/ets/pages/list/ListChatRoom.ets b/ArkUISample/ScrollableComponent/entry/src/main/ets/pages/list/ListChatRoom.ets new file mode 100644 index 0000000000000000000000000000000000000000..7a64085db0329a882102e3217aff50a301074c4e --- /dev/null +++ b/ArkUISample/ScrollableComponent/entry/src/main/ets/pages/list/ListChatRoom.ets @@ -0,0 +1,110 @@ +/* + * Copyright (c) 2025 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 { ComponentCard } from '../../common/Card' +// 消息类型定义 +interface Message { + id: number + content: string + sender: string +} + +@Entry +@Component +export struct ListChatRoom { + // 自定义消息组件 + @Builder + MessageItem(message: Message) { + Column() { + Text(`${message.sender}: ${message.content}`) + .fontSize(16) + .textAlign(TextAlign.Start) + .padding(10) + .backgroundColor(message.sender === '系统' ? '#F0F0F0' : '#E6F3FF') + .borderRadius(8) + } + .width('100%') + .alignItems(HorizontalAlign.Start) + .margin({ bottom: 8 }) + } + + // 发送消息方法 + sendMessage() { + if (this.inputText.trim()) { + this.messages = [...this.messages, { + id: Date.now(), + content: this.inputText, + sender: '观众' + }] + this.inputText = '' + } + } + // 消息列表数据 + @State messages: Message[] = [ + { id: 1, content: '欢迎来到直播间!', sender: '系统' }, + { id: 2, content: '大家好啊~', sender: '主播' } + ] + + // 输入框内容 + @State inputText: string = '' + + build() { + NavDestination() { + Column({ space: 12 }) { + ComponentCard({ title: $r('app.string.ListChatRoom_title') }) { + Column() { + // 聊天消息区域 + List({ space: 10 }) { + ForEach(this.messages, (item: Message) => { + ListItem() { + this.MessageItem(item) + } + }, (item: Message) => item.id.toString()) + } + .layoutWeight(1) // 占据剩余空间 + .alignListItem(ListItemAlign.Center) + + // 输入区域 + Row({ space: 10 }) { + TextInput({ text: this.inputText, placeholder: '说点什么...' }) + .layoutWeight(1) + .onChange((value: string) => { + this.inputText = value + }) + .onSubmit(() => { // 回车发送 + this.sendMessage() + }) + + Button('发送', { type: ButtonType.Capsule }) + .backgroundColor('#007AFF') + .onClick(() => { + this.sendMessage() + }) + } + .padding(10) + .backgroundColor('#F5F5F5') + } + .width('100%') + .height('100%') + } + } + .width('100%') + .height('100%') + .padding({ left: 12, right: 12 }) + } + .backgroundColor('#f1f2f3') + .title($r('app.string.ListChatRoom_title')) + } +} \ No newline at end of file diff --git a/ArkUISample/ScrollableComponent/entry/src/main/ets/pages/list/ListDataSource.ets b/ArkUISample/ScrollableComponent/entry/src/main/ets/pages/list/ListDataSource.ets new file mode 100644 index 0000000000000000000000000000000000000000..c3caedf7f6c9cb4708491332c6b52eb944fc73f7 --- /dev/null +++ b/ArkUISample/ScrollableComponent/entry/src/main/ets/pages/list/ListDataSource.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. + */ + +export class ListDataSource implements IDataSource { + private list: number[] = []; + private listeners: DataChangeListener[] = []; + + constructor(list: number[]) { + this.list = list; + } + + totalCount(): number { + return this.list.length; + } + + getData(index: number): number { + return this.list[index]; + } + + registerDataChangeListener(listener: DataChangeListener): void { + if (this.listeners.indexOf(listener) < 0) { + this.listeners.push(listener); + } + } + + unregisterDataChangeListener(listener: DataChangeListener): void { + const pos = this.listeners.indexOf(listener); + if (pos >= 0) { + this.listeners.splice(pos, 1); + } + } + + // 通知控制器数据删除 + notifyDataDelete(index: number): void { + this.listeners.forEach(listener => { + listener.onDataDelete(index); + }); + } + + // 在指定索引位置删除一个元素 + public deleteItem(index: number): void { + this.list.splice(index, 1); + this.notifyDataDelete(index); + } +} \ No newline at end of file diff --git a/ArkUISample/ScrollableComponent/entry/src/main/ets/pages/list/ListIteration.ets b/ArkUISample/ScrollableComponent/entry/src/main/ets/pages/list/ListIteration.ets new file mode 100644 index 0000000000000000000000000000000000000000..9d307842428c8c410f7804c7769f4bcac1c02b2e --- /dev/null +++ b/ArkUISample/ScrollableComponent/entry/src/main/ets/pages/list/ListIteration.ets @@ -0,0 +1,73 @@ +/* + * Copyright (c) 2025 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 use_foreach_to_replace_similar_list_items] +import { util } from '@kit.ArkTS'; +// [StartExclude import_component_card] +import { ComponentCard } from '../../common/Card'; +// [EndExclude import_component_card] + +class Contact { + public key: string = util.generateRandomUUID(true); + public name: ResourceStr; + public icon: Resource; + + constructor(name: ResourceStr, icon: Resource) { + this.name = name; + this.icon = icon; + } +} + +@Entry +@Component +export struct ListIteration { + private contacts: Array = [ + new Contact($r('app.string.peopleOne'), $r('sys.media.clone_app_badge_1')), + new Contact($r('app.string.peopleTwo'), $r('sys.media.clone_app_badge_2')) + ]; + + build() { + // [StartExclude use_the_nav_destination] + NavDestination() { + Column({ space: 12 }) { + ComponentCard({ title: $r('app.string.ListIteration_titleExample') }) { + // [EndExclude use_the_nav_destination] + List() { + ForEach(this.contacts, (item: Contact) => { + ListItem() { + Row() { + Image(item.icon) + .width(40) + .height(40) + .margin(10) + Text(item.name).fontSize(20) + } + .width('100%') + .justifyContent(FlexAlign.Start) + } + }, (item: Contact) => JSON.stringify(item)) + } + .width('100%') + } + } + // [End use_foreach_to_replace_similar_list_items] + .width('100%') + .height('100%') + .padding({ left: 12, right: 12 }) + } + .backgroundColor('#f1f2f3') + .title($r('app.string.ListIteration_title')) + } +} \ No newline at end of file diff --git a/ArkUISample/ScrollableComponent/entry/src/main/ets/pages/list/ListLayout.ets b/ArkUISample/ScrollableComponent/entry/src/main/ets/pages/list/ListLayout.ets new file mode 100644 index 0000000000000000000000000000000000000000..742098ded73f871f74bbee3487d4c3d87cb93fdf --- /dev/null +++ b/ArkUISample/ScrollableComponent/entry/src/main/ets/pages/list/ListLayout.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 { ComponentCard } from '../../common/Card'; + +@Entry +@Component +export struct ListLayout { + @State egLanes: LengthConstrain = { minLength: 200, maxLength: 300 }; + + build() { + NavDestination() { + Column({ space: 12 }) { + ComponentCard({ title: $r('app.string.ListLayout_titleMainAxis') }) { + // [Start build_a_horizontal_scrolling_list] + List({ space: 8 }) { + // [StartExclude build_a_horizontal_scrolling_list] + ListItem() { + Text('ListItem one') + } + + ListItem() { + Text('ListItem two') + } + // [EndExclude build_a_horizontal_scrolling_list] + } + .listDirection(Axis.Horizontal) + // [End build_a_horizontal_scrolling_list] + .height(30) + } + + ComponentCard({ title: $r('app.string.ListLayout_titleCrossAxisLanes') }) { + // [Start build_list_by_size] + List({ space: 8 }) { + ListItem() { + // [StartExclude build_list_by_size] + Text('ListItem one') + } + + ListItem() { + Text('ListItem two') + } + + ListItem() { + Text('ListItem tree') + } + // [EndExclude build_list_by_size] + } + // 此处lanes设置主轴方向 + .lanes(this.egLanes) + // [End build_list_by_size] + } + + ComponentCard({ title: $r('app.string.ListLayout_titleCrossAxisAlignment') }) { + // [Start build_list_with_align_horizontally_in_the_center] + List({ space: 8 }) { + // [StartExclude build_list_with_align_horizontally_in_the_center] + ListItem() { + Text('ListItem one') + } + + ListItem() { + Text('ListItem two') + } + + ListItem() { + Text('ListItem tree') + } + // [EndExclude build_list_with_align_horizontally_in_the_center] + } + // 此处alignListItem设置水平方向对齐 + .alignListItem(ListItemAlign.Center) + // [End build_list_with_align_horizontally_in_the_center] + } + } + .width('100%') + .height('100%') + .padding({ left: 12, right: 12 }) + } + .backgroundColor('#f1f2f3') + .title($r('app.string.ListLayout_title')) + } +} \ No newline at end of file diff --git a/ArkUISample/ScrollableComponent/entry/src/main/ets/pages/list/LongList.ets b/ArkUISample/ScrollableComponent/entry/src/main/ets/pages/list/LongList.ets new file mode 100644 index 0000000000000000000000000000000000000000..2a69094a2210794d5cb93b7f878776190c75d4d5 --- /dev/null +++ b/ArkUISample/ScrollableComponent/entry/src/main/ets/pages/list/LongList.ets @@ -0,0 +1,67 @@ +/* + * Copyright (c) 2025 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 { ComponentCard } from '../../common/Card'; +import { ListDataSource } from './ListDataSource'; + +@Entry +@Component +export struct LongList { + private arr: ListDataSource = new ListDataSource([0, 1, 2, 3, 4, 5, 6, 7, 8, 9]); + + build() { + NavDestination() { + Column({ space: 12 }) { + ComponentCard({ title: $r('app.string.LongList_title') }) { + List({ space: 20, initialIndex: 0 }) { + LazyForEach(this.arr, (item: number) => { + ListItem() { + Text('' + item) + .width('100%').height(100).fontSize(16) + .textAlign(TextAlign.Center).borderRadius(10).backgroundColor(0xFFFFFF) + } + }, (item: string) => item) + } + .listDirection(Axis.Vertical) // 排列方向 + .scrollBar(BarState.Off) + .friction(0.6) + .divider({ strokeWidth: 2, color: 0xFFFFFF, startMargin: 20, endMargin: 20 }) // 每行之间的分界线 + .edgeEffect(EdgeEffect.Spring) // 边缘效果设置为Spring + .onScrollIndex((firstIndex: number, lastIndex: number, centerIndex: number) => { + console.info('first' + firstIndex); + console.info('last' + lastIndex); + console.info('center' + centerIndex); + }) + .onScrollVisibleContentChange((start: VisibleListContentInfo, end: VisibleListContentInfo) => { + console.log(' start index: ' + start.index + + ' start item group area: ' + start.itemGroupArea + + ' start index in group: ' + start.itemIndexInGroup); + console.log(' end index: ' + end.index + + ' end item group area: ' + end.itemGroupArea + + ' end index in group: ' + end.itemIndexInGroup); + }) + .onDidScroll((scrollOffset: number, scrollState: ScrollState) => { + console.info(`onScroll scrollState = ScrollState` + scrollState + `, scrollOffset = ` + scrollOffset); + }) + .width('90%') + } + } + .backgroundColor(0xDCDCDC) + .width('100%') + .height('100%') + } + .title($r('app.string.LongList_title')) + } +} \ No newline at end of file diff --git a/ArkUISample/ScrollableComponent/entry/src/main/ets/pages/list/ResponsiveScrollPositionList.ets b/ArkUISample/ScrollableComponent/entry/src/main/ets/pages/list/ResponsiveScrollPositionList.ets new file mode 100644 index 0000000000000000000000000000000000000000..06c536cdbd230d39acab2ff89c16e21b37debfbb --- /dev/null +++ b/ArkUISample/ScrollableComponent/entry/src/main/ets/pages/list/ResponsiveScrollPositionList.ets @@ -0,0 +1,176 @@ +/* + * Copyright (c) 2025 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 { util } from '@kit.ArkTS'; +import { ComponentCard } from '../../common/Card'; + +// [Start respond_to_scroll_position] +const alphabets = ['#', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', + 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z']; + +// [StartExclude respond_to_scroll_position] +class Contact { + public key: string = util.generateRandomUUID(true); + public name: string | Resource; + public icon: Resource; + + constructor(name: string | Resource, icon: Resource) { + this.name = name; + this.icon = icon; + } +} + +class ContactsGroup { + public title: string = ''; + public contacts: Array | null = null; + public key: string = ''; +} + +export let contactsGroups: object[] = [ + { + title: 'A', + contacts: [ + new Contact($r('app.string.contacts_A_one'), $r('sys.media.clone_app_badge_1')), + new Contact($r('app.string.contacts_A_two'), $r('sys.media.clone_app_badge_2')) + ], + key: util.generateRandomUUID(true) + } as ContactsGroup, + { + title: 'B', + contacts: [ + new Contact($r('app.string.contacts_B_one'), $r('sys.media.clone_app_badge_3')), + new Contact($r('app.string.contacts_B_two'), $r('sys.media.clone_app_badge_4')), + new Contact($r('app.string.contacts_B_three'), $r('sys.media.clone_app_badge_5')) + ], + key: util.generateRandomUUID(true) + } as ContactsGroup, + { + title: 'D', + contacts: [ + new Contact($r('app.string.contacts_D_one'), $r('sys.media.clone_app_badge_3')), + new Contact($r('app.string.contacts_D_two'), $r('sys.media.clone_app_badge_4')), + new Contact($r('app.string.contacts_D_three'), $r('sys.media.clone_app_badge_5')) + ], + key: util.generateRandomUUID(true) + } as ContactsGroup, + { + title: 'F', + contacts: [ + new Contact($r('app.string.contacts_F_one'), $r('sys.media.clone_app_badge_3')), + new Contact($r('app.string.contacts_F_two'), $r('sys.media.clone_app_badge_4')) + ], + key: util.generateRandomUUID(true) + } as ContactsGroup, + { + title: 'G', + contacts: [ + new Contact($r('app.string.contacts_G_one'), $r('sys.media.clone_app_badge_3')), + new Contact($r('app.string.contacts_G_two'), $r('sys.media.clone_app_badge_4')) + ], + key: util.generateRandomUUID(true) + } as ContactsGroup, + { + title: 'H', + contacts: [ + new Contact($r('app.string.contacts_H_one'), $r('sys.media.clone_app_badge_3')), + new Contact($r('app.string.contacts_H_two'), $r('sys.media.clone_app_badge_4')), + new Contact($r('app.string.contacts_H_three'), $r('sys.media.clone_app_badge_5')) + ], + key: util.generateRandomUUID(true) + } as ContactsGroup, + { + title: 'X', + contacts: [ + new Contact($r('app.string.contacts_X_one'), $r('sys.media.clone_app_badge_3')), + new Contact($r('app.string.contacts_X_two'), $r('sys.media.clone_app_badge_4')), + new Contact($r('app.string.contacts_X_three'), $r('sys.media.clone_app_badge_5')) + ], + key: util.generateRandomUUID(true) + } as ContactsGroup +]; +// [EndExclude respond_to_scroll_position] + +@Entry +@Component +export struct ResponsiveScrollPositionList { + @State selectedIndex: number = 0; + private listScroller: Scroller = new Scroller(); + private currentGroupTitle: string = ''; // 用于跟踪当前显示的分组标题 + + // [StartExclude respond_to_scroll_position] + @Builder + itemHead(text: string) { + // 列表分组的头部组件,对应联系人分组A、B等位置的组件 + Text(text) + .fontSize(20) + .backgroundColor('#fff1f3f5') + .width('100%') + .padding(5) + } + // [EndExclude respond_to_scroll_position] + + build() { + // [StartExclude respond_to_scroll_position] + NavDestination() { + Column({ space: 12 }) { + ComponentCard({ title: $r('app.string.ResponsiveScrollPositionList_titleExample') }) { + // [EndExclude use_stack] + Stack({ alignContent: Alignment.End }) { + // 此为响应滚动位置示例List容器 + List({ scroller: this.listScroller }) { + // [StartExclude use_foreach] + ForEach(contactsGroups, (itemGroup: ContactsGroup) => { + ListItemGroup({ header: this.itemHead(itemGroup.title) }) { + // 循环渲染ListItem + if (itemGroup.contacts) { + ForEach(itemGroup.contacts, (item: Contact) => { + ListItem() { + Row() { + Image(item.icon).width(40).height(40).margin(10) + Text(item.name).fontSize(20) + }.width('100%').justifyContent(FlexAlign.Start) + // [EndExclude respond_to_scroll_position] + } + // [StartExclude respond_to_scroll_position] + }, (item: Contact) => JSON.stringify(item)) + } + } + }, (itemGroup: ContactsGroup) => JSON.stringify(itemGroup)) + } + // [EndExclude respond_to_scroll_position] + .onScrollIndex((firstIndex: number) => { + // [StartExclude respond_to_scroll_position] + // 根据列表滚动到的索引值,重新计算对应联系人索引栏的位置this.selectedIndex + let group = contactsGroups[firstIndex] as ContactsGroup; + this.currentGroupTitle = group.title; + this.selectedIndex = alphabets.indexOf(this.currentGroupTitle); + // [EndExclude respond_to_scroll_position] + }) + + // 字母表索引组件 + AlphabetIndexer({ arrayValue: alphabets, selected: 0 }) + .selected(this.selectedIndex) + // [End respond_to_scroll_position] + }.height('90%') + } + } + .width('100%') + .height('100%') + .padding({ left: 12, right: 12 }) + } + .backgroundColor('#f1f2f3') + .title($r('app.string.ResponsiveScrollPositionList_title')) + } +} \ No newline at end of file diff --git a/ArkUISample/ScrollableComponent/entry/src/main/ets/pages/list/StickyHeaderList.ets b/ArkUISample/ScrollableComponent/entry/src/main/ets/pages/list/StickyHeaderList.ets new file mode 100644 index 0000000000000000000000000000000000000000..4c2194578b28197f2c27a07dedb2a094ceb44908 --- /dev/null +++ b/ArkUISample/ScrollableComponent/entry/src/main/ets/pages/list/StickyHeaderList.ets @@ -0,0 +1,111 @@ +/* + * Copyright (c) 2025 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 { ComponentCard } from '../../common/Card'; +// [Start Add_sticky_titles] +import { util } from '@kit.ArkTS'; + +class Contact { + public key: string = util.generateRandomUUID(true); + public name: string | Resource; + public icon: Resource; + + constructor(name: string | Resource, icon: Resource) { + this.name = name; + this.icon = icon; + } +} + +class ContactsGroup { + public title: string = ''; + public contacts: Array | null = null; + public key: string = ''; +} + +export let contactsGroups: object[] = [ + { + title: 'A', + contacts: [ + new Contact($r('app.string.contacts_A_one'), $r('sys.media.clone_app_badge_1')), + new Contact($r('app.string.contacts_A_two'), $r('sys.media.clone_app_badge_2')) + ], + key: util.generateRandomUUID(true) + } as ContactsGroup, + { + title: 'B', + contacts: [ + new Contact($r('app.string.contacts_B_one'), $r('sys.media.clone_app_badge_3')), + new Contact($r('app.string.contacts_B_two'), $r('sys.media.clone_app_badge_4')), + new Contact($r('app.string.contacts_B_three'), $r('sys.media.clone_app_badge_5')) + ], + key: util.generateRandomUUID(true) + } as ContactsGroup +]; + +@Entry +@Component +export struct StickyHeaderList { + // 定义分组联系人数据集合contactsGroups数组 + @Builder + itemHead(text: string) { + // 列表分组的头部组件,对应联系人分组A、B等位置的组件 + Text(text) + .fontSize(20) + .backgroundColor('#fff1f3f5') + .width('100%') + .padding(5) + } + + build() { + // [StartExclude add_sticky_titles] + NavDestination() { + Column({ space: 12 }) { + ComponentCard({ title: $r('app.string.StickyHeaderList_titleExample') }) { + // [EndExclude add_sticky_titles] + List() { + // 循环渲染ListItemGroup,contactsGroups为多个分组联系人contacts和标题title的数据集合 + ForEach(contactsGroups, (itemGroup: ContactsGroup) => { + ListItemGroup({ header: this.itemHead(itemGroup.title) }) { + // 循环渲染ListItem + if (itemGroup.contacts) { + ForEach(itemGroup.contacts, (item: Contact) => { + ListItem() { + // [StartExclude add_sticky_titles] + Row() { + Image(item.icon).width(40).height(40).margin(10) + Text(item.name).fontSize(20) + }.width('100%').justifyContent(FlexAlign.Start) + // [EndExclude add_sticky_titles] + } + }, (item: Contact) => JSON.stringify(item)) + } + } + }, (itemGroup: ContactsGroup) => JSON.stringify(itemGroup)) + } + // [StartExclude add_sticky_titles] + .height(230) + // [EndExclude add_sticky_titles] + .sticky(StickyStyle.Header) // 设置吸顶,实现粘性标题效果 + } + // [End add_sticky_titles] + } + .width('100%') + .height('100%') + .padding({ left: 12, right: 12 }) + } + .backgroundColor('#f1f2f3') + .title($r('app.string.StickyHeaderList_title')) + } +} \ No newline at end of file diff --git a/ArkUISample/ScrollableComponent/entry/src/main/ets/pages/list/SwipeableListItem.ets b/ArkUISample/ScrollableComponent/entry/src/main/ets/pages/list/SwipeableListItem.ets new file mode 100644 index 0000000000000000000000000000000000000000..7f6454c43ba480fbeadaa8a56232f3f3edc202b6 --- /dev/null +++ b/ArkUISample/ScrollableComponent/entry/src/main/ets/pages/list/SwipeableListItem.ets @@ -0,0 +1,81 @@ +/* + * Copyright (c) 2025 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { ComponentCard } from '../../common/Card'; + +@Entry +@Component +export struct SwipeListItem { + private index: number = 0; + @State arr: number[] = [0, 1, 2, 3]; + + // [Start build_the_tail_slide_out_component] + @Builder + itemEnd(index: number) { + // 构建尾端滑出组件 + Button({ type: ButtonType.Circle }) { + Image($r('sys.media.ohos_ic_bottomsheet_close')) + .width(40) + .height(40) + } + // [StartExclude build_the_tail_slide_out_component] + .backgroundColor('#FFE1E2E3') + // [EndExclude build_the_tail_slide_out_component] + .onClick(() => { + // this.messages为列表数据源,可根据实际场景构造。点击后从数据源删除指定数据项。 + this.arr.splice(index, 1); + }) + } + // [End build_the_tail_slide_out_component] + + build() { + NavDestination() { + Column({ space: 12 }) { + ComponentCard({ title: $r('app.string.SwipeListItem_titleExample') }) { + List({ space: 12 }) { + ForEach(this.arr, (item: number) => { + // [Start bind_the_swipeAction_property_to_left_swipe_list_item] + ListItem() { + // [StartExclude bind_the_swipeAction_property_to_left_swipe_list_item] + Text('Message ' + item) + .width('100%') + .height(50) + .fontSize(16) + .textAlign(TextAlign.Center) + .borderRadius(10) + .backgroundColor('#FFF1F3F5') + // [EndExclude bind_the_swipeAction_property_to_left_swipe_list_item] + }.swipeAction({ + end: { + // index为该ListItem在List中的索引值。 + builder: () => { + this.index = this.arr.indexOf(item); + this.itemEnd(this.index); + }, + } + // [End bind_the_swipeAction_property_to_left_swipe_list_item] + }) + }, (item: number) => item.toString()) + } + } + } + .width('100%') + .height('100%') + .padding({ left: 12, right: 12 }) + } + .backgroundColor('#f1f2f3') + .title($r('app.string.SwipeListItem_title')) + } +} \ No newline at end of file diff --git a/ArkUISample/ScrollableComponent/entry/src/main/ets/pages/list/TaggedListItems.ets b/ArkUISample/ScrollableComponent/entry/src/main/ets/pages/list/TaggedListItems.ets new file mode 100644 index 0000000000000000000000000000000000000000..bee859a3324828758ef49b72468a59988752ed16 --- /dev/null +++ b/ArkUISample/ScrollableComponent/entry/src/main/ets/pages/list/TaggedListItems.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. + */ + +import { ComponentCard } from '../../common/Card'; + +@Entry +@Component +export struct TaggedListItems { + @State arr: number[] = [0, 1, 2, 3]; + + build() { + NavDestination() { + Column({ space: 12 }) { + ComponentCard({ title: $r('app.string.TaggedListItems_titleExample') }) { + List() { + ForEach(this.arr, (item: number) => { + // [Start add_tags_to_list_items] + ListItem() { + // Badge组件实现消息右上角添加标记功能 + Badge({ + count: 1, + position: BadgePosition.RightTop, + style: { badgeSize: 16, badgeColor: '#FA2A2D' } + }) { + // [StartExclude add_tags_to_list_items] + Text('消息' + item) + .width('95%') + .height(50) + .fontSize(16) + .textAlign(TextAlign.Center) + .borderRadius(10) + .backgroundColor('#FFF1F3F5') + // [EndExclude add_tags_to_list_items] + } + // [End add_tags_to_list_items] + }.margin({ top: 12 }) + }, (item: number) => item.toString()) + } + } + } + .width('100%') + .height('100%') + .padding({ left: 12, right: 12 }) + } + .backgroundColor('#f1f2f3') + .title($r('app.string.TaggedListItems_title')) + } +} \ No newline at end of file diff --git a/ArkUISample/ScrollableComponent/entry/src/main/ets/pages/swiper/SwiperAndTabsLinkage.ets b/ArkUISample/ScrollableComponent/entry/src/main/ets/pages/swiper/SwiperAndTabsLinkage.ets new file mode 100644 index 0000000000000000000000000000000000000000..9ce261ca5840791dfd6d40c9b8e55b91c007e2d5 --- /dev/null +++ b/ArkUISample/ScrollableComponent/entry/src/main/ets/pages/swiper/SwiperAndTabsLinkage.ets @@ -0,0 +1,125 @@ +/* + * Copyright (c) 2025 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 { ComponentCard } from "../../common/Card"; + +// xxx.ets +class MyDataSource implements IDataSource { + private list: number[] = []; + + constructor(list: number[]) { + this.list = list; + } + + totalCount(): number { + return this.list.length; + } + + getData(index: number): number { + return this.list[index]; + } + + registerDataChangeListener(listener: DataChangeListener): void { + } + + unregisterDataChangeListener() { + } +} + +@Entry +@Component +export struct SwiperAndTabsLinkage { + @State fontColor: string = '#182431'; + @State selectedFontColor: string = '#007DFF'; + @State currentIndex: number = 0; + private list: number[] = []; + private tabsController: TabsController = new TabsController(); + private swiperController: SwiperController = new SwiperController(); + private swiperData: MyDataSource = new MyDataSource([]); + + aboutToAppear(): void { + for (let i = 0; i <= 9; i++) { + this.list.push(i); + } + this.swiperData = new MyDataSource(this.list); + } + + @Builder tabBuilder(index: number, name: string) { + Column() { + Text(name) + .fontColor(this.currentIndex === index ? this.selectedFontColor : this.fontColor) + .fontSize(16) + .fontWeight(this.currentIndex === index ? 500 : 400) + .lineHeight(22) + .margin({ top: 17, bottom: 7 }) + Divider() + .strokeWidth(2) + .color('#007DFF') + .opacity(this.currentIndex === index ? 1 : 0) + }.width('20%') + } + + build() { + NavDestination() { + Column({ space: 12 }) { + ComponentCard({ title: $r('app.string.SwiperAndTabsLinkage_title') }) { + Column() { + Tabs({ barPosition: BarPosition.Start, controller: this.tabsController }) { + ForEach(this.list, (index: number) =>{ + TabContent().tabBar(this.tabBuilder(index, '页签 ' + this.list[index])) + }) + } + .onTabBarClick((index: number) => { + this.currentIndex = index; + this.swiperController.changeIndex(index, true); + }) + .barMode(BarMode.Scrollable) + .backgroundColor('#F1F3F5') + .height(56) + .width('100%') + + Swiper(this.swiperController) { + LazyForEach(this.swiperData, (item: string) => { + Text(item.toString()) + .onAppear(()=>{ + console.info('onAppear ' + item.toString()); + }) + .onDisAppear(()=>{ + console.info('onDisAppear ' + item.toString()); + }) + .width('100%') + .height('40%') + .backgroundColor(0xAFEEEE) + .textAlign(TextAlign.Center) + .fontSize(30) + }, (item: string) => item) + } + .loop(false) + .onSelected((index: number) => { + console.info("onSelected:" + index); + this.currentIndex = index; + this.tabsController.changeIndex(index); + }) + } + } + } + .width('100%') + .height('100%') + .padding({ left: 12, right: 12 }) + } + .backgroundColor('#f1f2f3') + .title($r('app.string.SwiperAndTabsLinkage_title')) + } +} \ No newline at end of file diff --git a/ArkUISample/ScrollableComponent/entry/src/main/ets/pages/swiper/SwiperAutoPlay.ets b/ArkUISample/ScrollableComponent/entry/src/main/ets/pages/swiper/SwiperAutoPlay.ets new file mode 100644 index 0000000000000000000000000000000000000000..9900409f00f30ae6fb66be820cfe3e89faf4eb21 --- /dev/null +++ b/ArkUISample/ScrollableComponent/entry/src/main/ets/pages/swiper/SwiperAutoPlay.ets @@ -0,0 +1,66 @@ +/* + * Copyright (c) 2025 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { ComponentCard } from '../../common/Card'; + +@Entry +@Component +export struct SwiperAutoPlay { + build() { + NavDestination() { + Column({ space: 12 }) { + ComponentCard({ title: $r('app.string.SwiperAutoPlay_title') }) { + // [Start autoplay_loop_true] + Swiper() { + // [StartExclude autoplay_loop_true] + Text('0') + .width('90%') + .height('100%') + .backgroundColor(Color.Gray) + .textAlign(TextAlign.Center) + .fontSize(30) + + Text('1') + .width('90%') + .height('100%') + .backgroundColor(Color.Green) + .textAlign(TextAlign.Center) + .fontSize(30) + + Text('2') + .width('90%') + .height('100%') + .backgroundColor(Color.Pink) + .textAlign(TextAlign.Center) + .fontSize(30) + // [EndExclude autoplay_loop_true] + } + // [StartExclude autoplay_loop_true] + .height(200) + // [EndExclude autoplay_loop_true] + .loop(true) + .autoPlay(true) + .interval(1000) + // [End autoplay_loop_true] + } + } + .width('100%') + .height('100%') + .padding({ left: 12, right: 12 }) + } + .backgroundColor('#f1f2f3') + .title($r('app.string.SwiperAutoPlay_title')) + } +} \ No newline at end of file diff --git a/ArkUISample/ScrollableComponent/entry/src/main/ets/pages/swiper/SwiperCustomAnimation.ets b/ArkUISample/ScrollableComponent/entry/src/main/ets/pages/swiper/SwiperCustomAnimation.ets new file mode 100644 index 0000000000000000000000000000000000000000..43bab941cd801286eb7f8f6afd7c01304e384702 --- /dev/null +++ b/ArkUISample/ScrollableComponent/entry/src/main/ets/pages/swiper/SwiperCustomAnimation.ets @@ -0,0 +1,103 @@ +/* + * Copyright (c) 2025 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 { ComponentCard } from '../../common/Card'; + +// [Start customize_transition_animations] +@Entry +@Component +export struct SwiperCustomAnimation { + private DISPLAY_COUNT: number = 2; + private MIN_SCALE: number = 0.75; + @State backgroundColors: Color[] = [Color.Green, Color.Blue, Color.Yellow, Color.Pink, Color.Gray, Color.Orange]; + @State opacityList: number[] = []; + @State scaleList: number[] = []; + @State translateList: number[] = []; + @State zIndexList: number[] = []; + + aboutToAppear(): void { + for (let i = 0; i < this.backgroundColors.length; i++) { + this.opacityList.push(1.0); + this.scaleList.push(1.0); + this.translateList.push(0.0); + this.zIndexList.push(0); + } + } + + build() { + // [StartExclude customize_transition_animations] + NavDestination() { + // [EndExclude customize_transition_animations] + Column({ space: 12 }) { + // [StartExclude customize_transition_animations] + ComponentCard({ title: $r('app.string.SwiperCustomAnimation_titleExample') }) { + // [EndExclude customize_transition_animations] + Swiper() { + ForEach(this.backgroundColors, (backgroundColor: Color, index: number) => { + Text(index.toString()) + .width('100%') + .height('100%') + .fontSize(50) + .textAlign(TextAlign.Center) + .backgroundColor(backgroundColor) + .opacity(this.opacityList[index]) + .scale({ x: this.scaleList[index], y: this.scaleList[index] }) + .translate({ x: this.translateList[index] }) + .zIndex(this.zIndexList[index]) + }) + } + .height(200) + .indicator(false) + .displayCount(this.DISPLAY_COUNT, true) + .customContentTransition({ + timeout: 1000, + transition: (proxy: SwiperContentTransitionProxy) => { + if (proxy.position <= proxy.index % this.DISPLAY_COUNT || + proxy.position >= this.DISPLAY_COUNT + proxy.index % this.DISPLAY_COUNT) { + // 同组页面完全滑出视窗外时,重置属性值 + this.opacityList[proxy.index] = 1.0; + this.scaleList[proxy.index] = 1.0; + this.translateList[proxy.index] = 0.0; + this.zIndexList[proxy.index] = 0; + } else { + // 同组页面未滑出视窗外时,对同组中左右两个页面,逐帧根据position修改属性值 + if (proxy.index % this.DISPLAY_COUNT === 0) { + this.opacityList[proxy.index] = 1 - proxy.position / this.DISPLAY_COUNT; + this.scaleList[proxy.index] = + this.MIN_SCALE + (1 - this.MIN_SCALE) * (1 - proxy.position / this.DISPLAY_COUNT); + this.translateList[proxy.index] = -proxy.position * proxy.mainAxisLength + + (1 - this.scaleList[proxy.index]) * proxy.mainAxisLength / 2.0; + } else { + this.opacityList[proxy.index] = 1 - (proxy.position - 1) / this.DISPLAY_COUNT; + this.scaleList[proxy.index] = + this.MIN_SCALE + (1 - this.MIN_SCALE) * (1 - (proxy.position - 1) / this.DISPLAY_COUNT); + this.translateList[proxy.index] = -(proxy.position - 1) * proxy.mainAxisLength - + (1 - this.scaleList[proxy.index]) * proxy.mainAxisLength / 2.0; + } + this.zIndexList[proxy.index] = -1; + } + } + }) + } + } + .width('100%') + // [End customize_transition_animations] + .height('100%') + .padding({ left: 12, right: 12 }) + } + .backgroundColor('#f1f2f3') + .title($r('app.string.SwiperCustomAnimation_title')) + } +} \ No newline at end of file diff --git a/ArkUISample/ScrollableComponent/entry/src/main/ets/pages/swiper/SwiperDirection.ets b/ArkUISample/ScrollableComponent/entry/src/main/ets/pages/swiper/SwiperDirection.ets new file mode 100644 index 0000000000000000000000000000000000000000..e8c8e2d9cdb23d69cce3cb5a9b826e56110c1bd3 --- /dev/null +++ b/ArkUISample/ScrollableComponent/entry/src/main/ets/pages/swiper/SwiperDirection.ets @@ -0,0 +1,128 @@ +/* + * Copyright (c) 2025 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 { ComponentCard } from '../../common/Card'; + +@Entry +@Component +export struct SwiperDirection { + private swiperHorizontalController: SwiperController = new SwiperController(); + private swiperVerticalController: SwiperController = new SwiperController(); + + build() { + NavDestination() { + Column({ space: 12 }) { + ComponentCard({ title: $r('app.string.SwiperPageSwitchMethod_titleHorizontal') }) { + Column({ space: 8 }) { + // [Start rotate_horizontally] + Swiper(this.swiperHorizontalController) { + // [StartExclude rotate_horizontally] + Text('0') + .width('90%') + .height('100%') + .backgroundColor(Color.Gray) + .textAlign(TextAlign.Center) + .fontSize(30) + + Text('1') + .width('90%') + .height('100%') + .backgroundColor(Color.Green) + .textAlign(TextAlign.Center) + .fontSize(30) + + Text('2') + .width('90%') + .height('100%') + .backgroundColor(Color.Pink) + .textAlign(TextAlign.Center) + .fontSize(30) + // [EndExclude rotate_horizontally] + } + // [StartExclude rotate_horizontally] + .height(200) + // [EndExclude rotate_horizontally] + .indicator(true) + .vertical(false) + // [End rotate_horizontally] + + Row({ space: 12 }) { + Button('showNext') + .onClick(() => { + this.swiperHorizontalController.showNext(); // 通过controller切换到后一页 + }) + Button('showPrevious') + .onClick(() => { + this.swiperHorizontalController.showPrevious(); // 通过controller切换到前一页 + }) + }.margin(5) + } + } + + ComponentCard({ title: $r('app.string.SwiperPageSwitchMethod_titleVertical') }) { + Column({ space: 8 }) { + // [Start rotate_vertically] + Swiper(this.swiperVerticalController) { + // [StartExclude rotate_vertically] + Text('0') + .width('90%') + .height('100%') + .backgroundColor(Color.Gray) + .textAlign(TextAlign.Center) + .fontSize(30) + + Text('1') + .width('90%') + .height('100%') + .backgroundColor(Color.Green) + .textAlign(TextAlign.Center) + .fontSize(30) + + Text('2') + .width('90%') + .height('100%') + .backgroundColor(Color.Pink) + .textAlign(TextAlign.Center) + .fontSize(30) + // [EndExclude rotate_vertically] + } + // [StartExclude rotate_vertically] + .height(200) + // [EndExclude rotate_vertically] + .indicator(true) + .vertical(true) + // [End rotate_vertically] + + Row({ space: 12 }) { + Button('showNext') + .onClick(() => { + this.swiperVerticalController.showNext(); // 通过controller切换到后一页 + }) + Button('showPrevious') + .onClick(() => { + this.swiperVerticalController.showPrevious(); // 通过controller切换到前一页 + }) + }.margin(5) + } + } + } + .width('100%') + .height('100%') + .padding({ left: 12, right: 12 }) + } + .backgroundColor('#f1f2f3') + .title($r('app.string.SwiperDirection_title')) + } +} \ No newline at end of file diff --git a/ArkUISample/ScrollableComponent/entry/src/main/ets/pages/swiper/SwiperIgnoreComponentSize.ets b/ArkUISample/ScrollableComponent/entry/src/main/ets/pages/swiper/SwiperIgnoreComponentSize.ets new file mode 100644 index 0000000000000000000000000000000000000000..29314df3340938b2d9ce339d1d4f2ee4074727f4 --- /dev/null +++ b/ArkUISample/ScrollableComponent/entry/src/main/ets/pages/swiper/SwiperIgnoreComponentSize.ets @@ -0,0 +1,121 @@ +/* + * Copyright (c) 2025 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { LengthMetrics } from '@kit.ArkUI'; +import { ComponentCard } from '../../common/Card'; + + +class MyDataSource implements IDataSource { + private list: number[] = []; + + constructor(list: number[]) { + this.list = list; + } + + totalCount(): number { + return this.list.length; + } + + getData(index: number): number { + return this.list[index]; + } + + registerDataChangeListener(listener: DataChangeListener): void { + } + + unregisterDataChangeListener() { + } +} + +@Entry +@Component +export struct SwiperIgnoreComponentSize { + + @State space: LengthMetrics = LengthMetrics.vp(0); + @State spacePool: LengthMetrics[] = [LengthMetrics.vp(0), LengthMetrics.px(3), LengthMetrics.vp(10)]; + @State spaceIndex: number = 0; + + @State ignoreSize: boolean = false; + @State ignoreSizePool: boolean[] = [false, true]; + @State ignoreSizeIndex: number = 0; + + private swiperController1: SwiperController = new SwiperController(); + private data1: MyDataSource = new MyDataSource([]); + + aboutToAppear(): void { + let list1: number[] = []; + for (let i = 1; i <= 10; i++) { + list1.push(i); + } + this.data1 = new MyDataSource(list1); + } + + build() { + NavDestination() { + Column({ space: 12 }) { + ComponentCard({ title: $r('app.string.SwiperIgnoreComponentSize_title') }) { + Scroll() { + Column({ space: 20 }) { + Swiper(this.swiperController1) { + LazyForEach(this.data1, (item: string) => { + Text(item.toString()) + .width('90%') + .height(120) + .backgroundColor(0xAFEEEE) + .textAlign(TextAlign.Center) + .fontSize(30) + }, (item: string) => item) + } + .indicator(new DotIndicator() + .space(this.space) + .bottom(LengthMetrics.vp(0), this.ignoreSize) + .itemWidth(15) + .itemHeight(15) + .selectedItemWidth(15) + .selectedItemHeight(15) + .color(Color.Gray) + .selectedColor(Color.Blue)) + .displayArrow({ + showBackground: true, + isSidebarMiddle: true, + backgroundSize: 24, + backgroundColor: Color.White, + arrowSize: 18, + arrowColor: Color.Blue + }, false) + + Column({ space: 4 }) { + Button('spaceIndex:' + this.spaceIndex).onClick(() => { + this.spaceIndex = (this.spaceIndex + 1) % this.spacePool.length; + this.space = this.spacePool[this.spaceIndex]; + }).margin(10) + + Button('ignoreSizeIndex:' + this.ignoreSizeIndex).onClick(() => { + this.ignoreSizeIndex = (this.ignoreSizeIndex + 1) % this.ignoreSizePool.length; + this.ignoreSize = this.ignoreSizePool[this.ignoreSizeIndex]; + }).margin(10) + }.margin(2) + }.width('100%') + } + } + } + .width('100%') + .height('100%') + .padding({ left: 12, right: 12 }) + } + .backgroundColor('#f1f2f3') + .title($r('app.string.SwiperIgnoreComponentSize_title')) + } +} \ No newline at end of file diff --git a/ArkUISample/ScrollableComponent/entry/src/main/ets/pages/swiper/SwiperIndicatorStyle.ets b/ArkUISample/ScrollableComponent/entry/src/main/ets/pages/swiper/SwiperIndicatorStyle.ets new file mode 100644 index 0000000000000000000000000000000000000000..b38d27d167c886bc92ed0d5dc59418bb7604991b --- /dev/null +++ b/ArkUISample/ScrollableComponent/entry/src/main/ets/pages/swiper/SwiperIndicatorStyle.ets @@ -0,0 +1,173 @@ +/* + * Copyright (c) 2025 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 { ComponentCard } from '../../common/Card'; + +@Entry +@Component +export struct SwiperIndicatorStyle { + build() { + NavDestination() { + Column({ space: 12 }) { + + ComponentCard({ title: $r('app.string.SwiperIndicatorStyle_titleDefault') }) { + // [Start default_navigation_point_style] + Swiper() { + Text('0') + .width('90%') + .height('100%') + .backgroundColor(Color.Gray) + .textAlign(TextAlign.Center) + .fontSize(30) + + Text('1') + .width('90%') + .height('100%') + .backgroundColor(Color.Green) + .textAlign(TextAlign.Center) + .fontSize(30) + + Text('2') + .width('90%') + .height('100%') + .backgroundColor(Color.Pink) + .textAlign(TextAlign.Center) + .fontSize(30) + } + // [End default_navigation_point_style] + .height(100) + } + + ComponentCard({ title: $r('app.string.SwiperIndicatorStyle_titleCustom') }) { + // [Start customize_navigation_point_styles] + Swiper() { + // [StartExclude customize_navigation_point_styles] + Text('0') + .width('90%') + .height('100%') + .backgroundColor(Color.Gray) + .textAlign(TextAlign.Center) + .fontSize(30) + + Text('1') + .width('90%') + .height('100%') + .backgroundColor(Color.Green) + .textAlign(TextAlign.Center) + .fontSize(30) + + Text('2') + .width('90%') + .height('100%') + .backgroundColor(Color.Pink) + .textAlign(TextAlign.Center) + .fontSize(30) + // [EndExclude customize_navigation_point_styles] + } + .height(100) + .indicator( + Indicator.dot() + .left(0) + .itemWidth(15) + .itemHeight(15) + .selectedItemWidth(30) + .selectedItemHeight(15) + .color(Color.Red) + .selectedColor(Color.Blue) + ) + } + // [End customize_navigation_point_styles] + + ComponentCard({ title: $r('app.string.SwiperIndicatorStyle_titleDefaultArrows') }) { + // [Start default_arrow_style] + Swiper() { + // [StartExclude default_arrow_style] + Text('0') + .width('90%') + .height('100%') + .backgroundColor(Color.Gray) + .textAlign(TextAlign.Center) + .fontSize(30) + + Text('1') + .width('90%') + .height('100%') + .backgroundColor(Color.Green) + .textAlign(TextAlign.Center) + .fontSize(30) + + Text('2') + .width('90%') + .height('100%') + .backgroundColor(Color.Pink) + .textAlign(TextAlign.Center) + .fontSize(30) + // [EndExclude default_arrow_style] + } + // [StartExclude default_arrow_style] + .height(100) + // [EndExclude default_arrow_style] + .displayArrow(true, false) + // [End default_arrow_style] + } + + ComponentCard({ title: $r('app.string.SwiperIndicatorStyle_titleCustomArrows') }) { + // [Start customize_the_arrow_style] + Swiper() { + // [StartExclude customize_the_arrow_style] + Text('0') + .width('90%') + .height('100%') + .backgroundColor(Color.Gray) + .textAlign(TextAlign.Center) + .fontSize(30) + + Text('1') + .width('90%') + .height('100%') + .backgroundColor(Color.Green) + .textAlign(TextAlign.Center) + .fontSize(30) + + Text('2') + .width('90%') + .height('100%') + .backgroundColor(Color.Pink) + .textAlign(TextAlign.Center) + .fontSize(30) + // [EndExclude customize_the_arrow_style] + } + // [StartExclude customize_the_arrow_style] + .height(100) + // [EndExclude customize_the_arrow_style] + .displayArrow({ + showBackground: true, + isSidebarMiddle: true, + backgroundSize: 24, + backgroundColor: Color.White, + arrowSize: 18, + arrowColor: Color.Blue + }, false) + // [End customize_the_arrow_style] + } + } + .width('100%') + .height('100%') + .padding({ left: 12, right: 12 }) + } + .backgroundColor('#f1f2f3') + .title($r('app.string.SwiperIndicatorStyle_title')) + } +} \ No newline at end of file diff --git a/ArkUISample/ScrollableComponent/entry/src/main/ets/pages/swiper/SwiperLoop.ets b/ArkUISample/ScrollableComponent/entry/src/main/ets/pages/swiper/SwiperLoop.ets new file mode 100644 index 0000000000000000000000000000000000000000..10c4945f09b7966c2b10ed4abfed524fdef03f9c --- /dev/null +++ b/ArkUISample/ScrollableComponent/entry/src/main/ets/pages/swiper/SwiperLoop.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 { ComponentCard } from '../../common/Card'; + +@Entry +@Component +export struct SwiperLoop { + build() { + NavDestination() { + Column({ space: 12 }) { + ComponentCard({ title: $r('app.string.SwiperLoop_titleTrue') }) { + // [Start loop_with_true] + Swiper() { + Text('0') + .width('90%') + .height('100%') + .backgroundColor(Color.Gray) + .textAlign(TextAlign.Center) + .fontSize(30) + + Text('1') + .width('90%') + .height('100%') + .backgroundColor(Color.Green) + .textAlign(TextAlign.Center) + .fontSize(30) + + Text('2') + .width('90%') + .height('100%') + .backgroundColor(Color.Pink) + .textAlign(TextAlign.Center) + .fontSize(30) + } + // [StartExclude loop_with_true] + .height(200) + // [EndExclude loop_with_true] + .loop(true) + // [End loop_with_true] + } + + ComponentCard({ title: $r('app.string.SwiperLoop_titleFalse') }) { + // [Start loop_with_false] + Swiper() { + // [StartExclude loop_with_false] + Text('0') + .width('90%') + .height('100%') + .backgroundColor(Color.Gray) + .textAlign(TextAlign.Center) + .fontSize(30) + + Text('1') + .width('90%') + .height('100%') + .backgroundColor(Color.Green) + .textAlign(TextAlign.Center) + .fontSize(30) + + Text('2') + .width('90%') + .height('100%') + .backgroundColor(Color.Pink) + .textAlign(TextAlign.Center) + .fontSize(30) + // [EndExclude loop_with_false] + } + // [StartExclude loop_with_false] + .height(200) + // [EndExclude loop_with_false] + .loop(false) + // [End loop_with_false] + } + } + .width('100%') + .height('100%') + .padding({ left: 12, right: 12 }) + } + .backgroundColor('#f1f2f3') + .title($r('app.string.SwiperLoop_title')) + } +} \ No newline at end of file diff --git a/ArkUISample/ScrollableComponent/entry/src/main/ets/pages/swiper/SwiperMultiPage.ets b/ArkUISample/ScrollableComponent/entry/src/main/ets/pages/swiper/SwiperMultiPage.ets new file mode 100644 index 0000000000000000000000000000000000000000..e534dd9f1002254fcb9f1ea0edc4455ac892f2c9 --- /dev/null +++ b/ArkUISample/ScrollableComponent/entry/src/main/ets/pages/swiper/SwiperMultiPage.ets @@ -0,0 +1,67 @@ +/* + * Copyright (c) 2025 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 { ComponentCard } from '../../common/Card'; + +@Entry +@Component +export struct SwiperMultiPage { + build() { + NavDestination() { + Column({ space: 12 }) { + ComponentCard({ title: $r('app.string.SwiperMultiPage_titleExample') }) { + // [Start each_page_displays_multiple_subpages] + Swiper() { + Text('0') + .width('90%') + .height('100%') + .backgroundColor(Color.Gray) + .textAlign(TextAlign.Center) + .fontSize(30) + Text('1') + .width('90%') + .height('100%') + .backgroundColor(Color.Green) + .textAlign(TextAlign.Center) + .fontSize(30) + Text('2') + .width('90%') + .height('100%') + .backgroundColor(Color.Pink) + .textAlign(TextAlign.Center) + .fontSize(30) + Text('3') + .width('90%') + .height('100%') + .backgroundColor(Color.Yellow) + .textAlign(TextAlign.Center) + .fontSize(30) + } + // [StartExclude each_page_displays_multiple_subpages] + .height(200) + // [EndExclude each_page_displays_multiple_subpages] + .indicator(true) + .displayCount(2) + } + // [End each_page_displays_multiple_subpages] + } + .width('100%') + .height('100%') + .padding({ left: 12, right: 12 }) + } + .backgroundColor('#f1f2f3') + .title($r('app.string.SwiperMultiPage_title')) + } +} \ No newline at end of file diff --git a/ArkUISample/ScrollableComponent/entry/src/main/ets/pages/swiper/SwiperPageSwitchMethod.ets b/ArkUISample/ScrollableComponent/entry/src/main/ets/pages/swiper/SwiperPageSwitchMethod.ets new file mode 100644 index 0000000000000000000000000000000000000000..64ae9a299941977d3e3bdf1ffbff1f994838cfde --- /dev/null +++ b/ArkUISample/ScrollableComponent/entry/src/main/ets/pages/swiper/SwiperPageSwitchMethod.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. + */ + +import { ComponentCard } from '../../common/Card'; + +// [Start switch_pages] +@Entry +@Component +export struct SwiperPageSwitchMethod { + private swiperController: SwiperController = new SwiperController(); + + build() { + // [StartExclude switch_pages] + NavDestination() { + Column({ space: 12 }) { + ComponentCard({ title: $r('app.string.SwiperPageSwitchMethod_title') }) { + // [EndExclude switch_pages] + Column({ space: 8 }) { + Swiper(this.swiperController) { + Text('0') + .width('90%') + .height('100%') + .backgroundColor(Color.Gray) + .textAlign(TextAlign.Center) + .fontSize(30) + Text('1') + .width('90%') + .height('100%') + .backgroundColor(Color.Green) + .textAlign(TextAlign.Center) + .fontSize(30) + Text('2') + .width('90%') + .height('100%') + .backgroundColor(Color.Pink) + .textAlign(TextAlign.Center) + .fontSize(30) + } + // [StartExclude switch_pages] + .height(200) + // [EndExclude switch_pages] + .indicator(true) + + Row({ space: 12 }) { + Button('showNext') + .onClick(() => { + this.swiperController.showNext(); // 通过controller切换到后一页 + }) + Button('showPrevious') + .onClick(() => { + this.swiperController.showPrevious(); // 通过controller切换到前一页 + }) + }.margin(5) + } + } + } + // [End switch_pages] + .width('100%') + .height('100%') + .padding({ left: 12, right: 12 }) + } + .backgroundColor('#f1f2f3') + .title($r('app.string.SwiperPageSwitchMethod_title')) + } +} \ No newline at end of file diff --git a/ArkUISample/ScrollableComponent/entry/src/main/ets/pages/swiper/index.ets b/ArkUISample/ScrollableComponent/entry/src/main/ets/pages/swiper/index.ets new file mode 100644 index 0000000000000000000000000000000000000000..37aa2ea07443fc9bb7f149c03d90906f217a4379 --- /dev/null +++ b/ArkUISample/ScrollableComponent/entry/src/main/ets/pages/swiper/index.ets @@ -0,0 +1,123 @@ +/* + * Copyright (c) 2025 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { CompletedRoutableCard } from '../../common/Card'; +import { Route } from '../../common/Route'; +import { SwiperAutoPlay } from './SwiperAutoPlay'; +import { SwiperCustomAnimation } from './SwiperCustomAnimation'; +import { SwiperDirection } from './SwiperDirection'; +import { SwiperIndicatorStyle } from './SwiperIndicatorStyle'; +import { SwiperLoop } from './SwiperLoop'; +import { SwiperMultiPage } from './SwiperMultiPage'; +import { SwiperPageSwitchMethod } from './SwiperPageSwitchMethod'; +import { SwiperAndTabsLinkage } from './SwiperAndTabsLinkage'; +import resource from '../../common/resource'; + +export const SWIPER_ROUTE_PREFIX: string = 'swiper'; + +const routes: Route[] = [ + { + name: `${SWIPER_ROUTE_PREFIX}/SwiperLoop`, + title: resource.resourceToString($r('app.string.SwiperLoop_title')), + description: $r('app.string.SwiperLoop_description') + }, + { + name: `${SWIPER_ROUTE_PREFIX}/SwiperAutoPlay`, + title: resource.resourceToString($r('app.string.SwiperAutoPlay_title')), + description: $r('app.string.SwiperAutoPlay_description') + }, + { + name: `${SWIPER_ROUTE_PREFIX}/SwiperIndicatorStyle`, + title: resource.resourceToString($r('app.string.SwiperIndicatorStyle_title')), + description: $r('app.string.SwiperIndicatorStyle_description') + }, + { + name: `${SWIPER_ROUTE_PREFIX}/SwiperPageSwitchMethod`, + title: resource.resourceToString($r('app.string.SwiperPageSwitchMethod_title')), + description: $r('app.string.SwiperPageSwitchMethod_description') + }, + { + name: `${SWIPER_ROUTE_PREFIX}/SwiperDirection`, + title: resource.resourceToString($r('app.string.SwiperDirection_title')), + description: $r('app.string.SwiperDirection_description') + }, + { + name: `${SWIPER_ROUTE_PREFIX}/SwiperMultiPage`, + title: resource.resourceToString($r('app.string.SwiperMultiPage_title')), + description: $r('app.string.SwiperMultiPage_description') + }, + { + name: `${SWIPER_ROUTE_PREFIX}/SwiperCustomAnimation`, + title: resource.resourceToString($r('app.string.SwiperCustomAnimation_title')), + description: $r('app.string.SwiperCustomAnimation_description') + }, + { + name: `${SWIPER_ROUTE_PREFIX}/SwiperAndTabsLinkage`, + title: resource.resourceToString($r('app.string.SwiperAndTabsLinkage_title')), + description: $r('app.string.SwiperAndTabsLinkage_description') + } +]; + +@Builder +export function swiperDestination(name: string) { + if (name === SWIPER_ROUTE_PREFIX) { + SwiperExample(); + } else if (name === routes[0].name) { + SwiperLoop(); + } else if (name === routes[1].name) { + SwiperAutoPlay(); + } else if (name === routes[2].name) { + SwiperIndicatorStyle(); + } else if (name === routes[3].name) { + SwiperPageSwitchMethod(); + } else if (name === routes[4].name) { + SwiperDirection(); + } else if (name === routes[5].name) { + SwiperMultiPage(); + } else if (name === routes[6].name) { + SwiperCustomAnimation(); + } else if (name === routes[7].name) { + SwiperAndTabsLinkage(); + } +} + +@Entry +@Component +struct SwiperExample { + @Consume pathStack: NavPathStack; + + build() { + NavDestination() { + List({ space: 12 }) { + ForEach(routes, (route: Route) => { + ListItem() { + CompletedRoutableCard({ title: route.title, description: route.description }) + } + .width('100%') + .onClick(() => { + this.pathStack.pushPath({ name: route.name }); + }) + }) + } + .contentStartOffset(56) + .padding({ left: 16, right: 16 }) + } + .backgroundColor('#f1f3f5') + .title('Swiper', { + backgroundBlurStyle: BlurStyle.COMPONENT_THICK, + barStyle: BarStyle.STACK + }) + } +} \ No newline at end of file diff --git a/ArkUISample/ScrollableComponent/entry/src/main/ets/pages/tabs/AgeFriendlyTabs.ets b/ArkUISample/ScrollableComponent/entry/src/main/ets/pages/tabs/AgeFriendlyTabs.ets new file mode 100644 index 0000000000000000000000000000000000000000..74d7a869758a332660676805b3cd1b699fd5035f --- /dev/null +++ b/ArkUISample/ScrollableComponent/entry/src/main/ets/pages/tabs/AgeFriendlyTabs.ets @@ -0,0 +1,185 @@ +/* + * Copyright (c) 2025 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 age_friendly_tab] +import { abilityManager, Configuration } from '@kit.AbilityKit'; +import { BusinessError } from '@kit.BasicServicesKit'; +import { promptAction, uiAppearance } from '@kit.ArkUI'; + +@Entry +@Component +export struct AgeFriendlyTabs { + @State fontColor: string = '#182431'; + @State selectedFontColor: string = '#007DFF'; + @State currentIndex: number = 0; + @State currentFontSizeScale: string = ''; + @State showBuilderTab: boolean = false; + @State fontSize: number = 15; + private darkModeKey: string[] = Object.keys(uiAppearance.DarkMode).filter( + key => typeof uiAppearance.DarkMode[key] === 'number'); + + async setFontScale(scale: number): Promise { + let configInit: Configuration = { + fontSizeScale: scale, + }; + abilityManager.updateConfiguration(configInit, (err: BusinessError) => { + if (err) { + console.error(`updateConfiguration fail, err: ${JSON.stringify(err)}`); + promptAction.showToast({ message: `scale:${scale}, err:${JSON.stringify(err)}` }); + } else { + this.currentFontSizeScale = String(scale); + if (scale > 1) { + this.fontSize = 8; + } else { + this.fontSize = 15; + } + console.log('updateConfiguration success.'); + promptAction.showToast({ message: `scale:${scale}, updateConfiguration success.` }); + } + }); + } + + darkMode(isDarkMode: boolean): void { + let mode: uiAppearance.DarkMode = uiAppearance.DarkMode.ALWAYS_LIGHT; + if (isDarkMode) { + mode = uiAppearance.DarkMode.ALWAYS_DARK; + } + if (mode == uiAppearance.getDarkMode()) { + console.info(`TitleDarkMode Set ${this.darkModeKey[mode]} successfully.`); + return; + } + try { + uiAppearance.setDarkMode(mode).then(() => { + console.info(`TitleDarkMode Set ${this.darkModeKey[mode]} successfully.`); + }).catch((error: Error) => { + console.error(`TitleDarkMode Set ${this.darkModeKey[mode]} failed, ${error.message}`); + }); + } catch (error) { + let message = (error as BusinessError).message; + console.error(`TitleDarkMode Set dark-mode failed, ${message}`); + } + } + + build() { + // [StartExclude age_friendly_tab] + NavDestination() { + // [EndExclude age_friendly_tab] + Column() { + Column() { + Row() { + Text(`current fontSizeScale:${this.currentFontSizeScale}`) + .margin({ top: 5, bottom: 5 }) + .fontSize(this.fontSize) + } + + Row() { + Button('1.75') + .margin({ top: 5, bottom: 5 }) + .fontSize(this.fontSize) + .width('40%') + .onClick(async () => { + await this.setFontScale(1.75); + }) + Button('2') + .margin({ top: 5, bottom: 5 }) + .fontSize(this.fontSize) + .width('40%') + .onClick(async () => { + await this.setFontScale(2); + }) + }.margin({ top: 25 }) + + Row() { + Button('3.2') + .margin({ top: 5, bottom: 5 }) + .fontSize(this.fontSize) + .width('40%') + .onClick(async () => { + await this.setFontScale(3.2); + }) + Button('1') + .margin({ top: 5, bottom: 5 }) + .fontSize(this.fontSize) + .width('40%') + .onClick(async () => { + await this.setFontScale(1); + }) + } + + Row() { + Button('深色模式') + .margin({ top: 5, bottom: 5 }) + .fontSize(this.fontSize) + .width('40%') + .onClick(async () => { + this.darkMode(true); + }) + Button('浅色模式') + .margin({ top: 5, bottom: 5 }) + .fontSize(this.fontSize) + .width('40%') + .onClick(async () => { + this.darkMode(false); + }) + } + }.alignItems(HorizontalAlign.Start) + + Column() { + Tabs({ barPosition: BarPosition.End }) { + TabContent() { + Column() + .width('100%') + .height('100%') + .backgroundColor(Color.Pink) + }.tabBar(new BottomTabBarStyle($r('sys.media.ohos_app_icon'), 'OverLength')) + + TabContent() { + Column() + .width('100%') + .height('100%') + .backgroundColor(Color.Yellow) + }.tabBar(new BottomTabBarStyle($r('sys.media.ohos_app_icon'), 'SixLine')) + + TabContent() { + Column() + .width('100%') + .height('100%') + .backgroundColor(Color.Blue) + }.tabBar(new BottomTabBarStyle($r('sys.media.ohos_app_icon'), 'Blue')) + + TabContent() { + Column() + .width('100%') + .height('100%') + .backgroundColor(Color.Green) + }.tabBar(new BottomTabBarStyle($r('sys.media.ohos_app_icon'), 'Green')) + } + .vertical(false) + .scrollable(true) + .barMode(BarMode.Fixed) + .onChange((index: number) => { + console.info(index.toString()); + }) + .width('100%') + .backgroundColor(0xF1F3F5) + }.width('80%').height(200) + .margin({ top: 200 }) + }.width('100%') + } + // [End age_friendly_tab] + .backgroundColor('#f1f2f3') + .title($r('app.string.AgeFriendlyTabs_title')) + } +} \ No newline at end of file diff --git a/ArkUISample/ScrollableComponent/entry/src/main/ets/pages/tabs/BottomTabBar.ets b/ArkUISample/ScrollableComponent/entry/src/main/ets/pages/tabs/BottomTabBar.ets new file mode 100644 index 0000000000000000000000000000000000000000..9a3a5b4215532191af05cdcf796c450451076814 --- /dev/null +++ b/ArkUISample/ScrollableComponent/entry/src/main/ets/pages/tabs/BottomTabBar.ets @@ -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. + */ + +import { ComponentCard } from '../../common/Card'; + +@Entry +@Component +export struct BottomTabBar { + build() { + NavDestination() { + Column({ space: 12 }) { + ComponentCard({ title: $r('app.string.BottomTabBar_titleExample') }) { + // [Start bottom_navigation] + Tabs({ barPosition: BarPosition.End }) { + // [StartExclude bottom_navigation] + TabContent() { + Text($r('app.string.homepage_content')) + .fontSize(30) + + } + .backgroundColor(Color.Blue) + .tabBar($r('app.string.homepage')) + + TabContent() { + Text($r('app.string.recommend_content')) + .fontSize(30) + } + .backgroundColor(Color.Green) + .tabBar($r('app.string.recommend')) + + TabContent() { + Text($r('app.string.discover_content')) + .fontSize(30) + } + .backgroundColor(Color.Yellow) + .tabBar($r('app.string.discover')) + + TabContent() { + Text($r('app.string.mine_content')) + .fontSize(30) + } + .backgroundColor(Color.Orange) + .tabBar($r('app.string.mine')) + // [EndExclude bottom_navigation] + } + // [End bottom_navigation] + .height(500) + } + } + .width('100%') + .height('100%') + .padding({ left: 12, right: 12 }) + } + .backgroundColor('#f1f2f3') + .title($r('app.string.BottomTabBar_title')) + } +} \ No newline at end of file diff --git a/ArkUISample/ScrollableComponent/entry/src/main/ets/pages/tabs/ContentWillChange.ets b/ArkUISample/ScrollableComponent/entry/src/main/ets/pages/tabs/ContentWillChange.ets new file mode 100644 index 0000000000000000000000000000000000000000..a414fd27b1237f0e2c65060567d6c0802ceabf1c --- /dev/null +++ b/ArkUISample/ScrollableComponent/entry/src/main/ets/pages/tabs/ContentWillChange.ets @@ -0,0 +1,234 @@ +/* + * Copyright (c) 2025 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 { ComponentCard } from '../../common/Card'; + +// [Start switch_the_tab_to_a_specific_tab] +@Entry +@Component +export struct ContentWillChange { + scroller: Scroller = new Scroller(); + @State currentIndex: number = 2; + // [StartExclude switch_the_tab_to_a_specific_tab] + @State currentIndexTwo: number = 2; + @State currentIndexThree: number = 2; + private controller: TabsController = new TabsController(); + private controllerTwo: TabsController = new TabsController(); + // [EndExclude switch_the_tab_to_a_specific_tab] + + @Builder + tabBuilder(title: ResourceStr, targetIndex: number) { + Column() { + Text(title) + .fontColor(this.currentIndex === targetIndex ? '#F111C1' : '#6B6B6B') + } + } + + // [StartExclude switch_the_tab_to_a_specific_tab] + @Builder + tabBuilderTwo(title: ResourceStr, targetIndex: number) { + Column() { + Text(title) + .fontColor(this.currentIndexTwo === targetIndex ? '#F111C1' : '#6B6B6B') + } + } + + @Builder + tabBuilderThree(title: ResourceStr, targetIndex: number) { + Column() { + Text(title) + .fontColor(this.currentIndexThree === targetIndex ? '#F111C1' : '#6B6B6B') + } + } + // [EndExclude switch_the_tab_to_a_specific_tab] + + build() { + // [StartExclude switch_the_tab_to_a_specific_tab] + NavDestination() { + Scroll(this.scroller) { + // [EndExclude switch_the_tab_to_a_specific_tab] + Column({ space: 12 }) { + // [StartExclude switch_the_tab_to_a_specific_tab] + ComponentCard({ title: $r('app.string.ContentWillChange_titleContentAndTabSync') }) { + // [EndExclude switch_the_tab_to_a_specific_tab] + Tabs({ barPosition: BarPosition.End }) { + TabContent() { + // [StartExclude switch_the_tab_to_a_specific_tab] + Text($r('app.string.homepage_content')) + .fontSize(30) + // [EndExclude switch_the_tab_to_a_specific_tab] + } + .backgroundColor(Color.Blue) + .tabBar(this.tabBuilder($r('app.string.homepage'), 0)) + + TabContent() { + // [StartExclude switch_the_tab_to_a_specific_tab] + Text($r('app.string.discover_content')) + .fontSize(30) + // [EndExclude switch_the_tab_to_a_specific_tab] + } + .backgroundColor(Color.Green) + .tabBar(this.tabBuilder($r('app.string.discover'), 1)) + + TabContent() { + // [StartExclude switch_the_tab_to_a_specific_tab] + Text($r('app.string.recommend_content')) + .fontSize(30) + // [EndExclude switch_the_tab_to_a_specific_tab] + } + .backgroundColor(Color.Yellow) + .tabBar(this.tabBuilder($r('app.string.recommend'), 2)) + + TabContent() { + // [StartExclude switch_the_tab_to_a_specific_tab] + Text($r('app.string.mine_content')) + .fontSize(30) + // [EndExclude switch_the_tab_to_a_specific_tab] + } + .backgroundColor(Color.Orange) + .tabBar(this.tabBuilder($r('app.string.mine'), 3)) + } + .animationDuration(0) + .height(300) + .onChange((index: number) => { + this.currentIndex = index; + }) + } + + ComponentCard({ title: $r('app.string.ContentWillChange_titleSpecifiedTab') }) { + Column({ space: 8 }) { + // [Start content_associated_with_tab] + Tabs({ barPosition: BarPosition.End, index: this.currentIndexTwo, controller: this.controller }) { + // [StartExclude content_associated_with_tab] + TabContent() { + Text($r('app.string.homepage_content')) + .fontSize(30) + } + .backgroundColor(Color.Blue) + .tabBar(this.tabBuilderTwo($r('app.string.homepage'), 0)) + + TabContent() { + Text($r('app.string.discover_content')) + .fontSize(30) + } + .backgroundColor(Color.Green) + .tabBar(this.tabBuilderTwo($r('app.string.discover'), 1)) + + TabContent() { + Text($r('app.string.recommend_content')) + .fontSize(30) + } + .backgroundColor(Color.Yellow) + .tabBar(this.tabBuilderTwo($r('app.string.recommend'), 2)) + + TabContent() { + Text($r('app.string.mine_content')) + .fontSize(30) + } + .backgroundColor(Color.Orange) + .tabBar(this.tabBuilderTwo($r('app.string.mine'), 3)) + // [EndExclude content_associated_with_tab] + } + .animationDuration(0) + .height(300) + .onChange((index: number) => { + this.currentIndexTwo = index; + }) + + Button($r('app.string.ContentWillChange_changeIndex')).width('50%') + .onClick(() => { + this.currentIndexTwo = (this.currentIndexTwo + 1) % 4; + }) + + Button('changeIndex').width('50%') + .onClick(() => { + let index = (this.currentIndexTwo + 1) % 4; + this.controller.changeIndex(index); + }) + // [End content_associated_with_tab] + } + } + + ComponentCard({ title: $r('app.string.ContentWillChange_titleInterception') }) { + Column({ space: 8 }) { + // [Start custom_page_toggle_interception_events] + Tabs({ barPosition: BarPosition.End, index: this.currentIndexThree, controller: this.controllerTwo }) { + // [StartExclude custom_page_toggle_interception_events] + TabContent() { + Text($r('app.string.homepage_content')) + .fontSize(30) + } + .backgroundColor(Color.Blue) + .tabBar(this.tabBuilderThree($r('app.string.homepage'), 0)) + + TabContent() { + Text($r('app.string.discover_content')) + .fontSize(30) + } + .backgroundColor(Color.Green) + .tabBar(this.tabBuilderThree($r('app.string.discover'), 1)) + + TabContent() { + Text($r('app.string.recommend_content')) + .fontSize(30) + } + .backgroundColor(Color.Yellow) + .tabBar(this.tabBuilderThree($r('app.string.recommend'), 2)) + + TabContent() { + Text($r('app.string.mine_content')) + .fontSize(30) + } + .backgroundColor(Color.Orange) + .tabBar(this.tabBuilderThree($r('app.string.mine'), 3)) + // [EndExclude custom_page_toggle_interception_events] + } + // [StartExclude custom_page_toggle_interception_events] + .animationDuration(0) + .height(300) + // [EndExclude custom_page_toggle_interception_events] + .onChange((index: number) => { + this.currentIndexThree = index; + }) + .onContentWillChange((currentIndex, comingIndex) => { + if (comingIndex == 2) { + return false; + } + return true; + }) + // [End custom_page_toggle_interception_events] + + Button($r('app.string.ContentWillChange_changeIndex')).width('50%') + .onClick(() => { + this.currentIndexThree = (this.currentIndexThree + 1) % 4; + }) + + Button('changeIndex').width('50%') + .onClick(() => { + let index = (this.currentIndexThree + 1) % 4; + this.controllerTwo.changeIndex(index); + }) + } + } + } + .width('100%') + .padding({ left: 12, right: 12 }) + } + } + .backgroundColor('#f1f2f3') + .title($r('app.string.ContentWillChange_title')) + } +} +// [End switch_the_tab_to_a_specific_tab] \ No newline at end of file diff --git a/ArkUISample/ScrollableComponent/entry/src/main/ets/pages/tabs/CustomTabBar.ets b/ArkUISample/ScrollableComponent/entry/src/main/ets/pages/tabs/CustomTabBar.ets new file mode 100644 index 0000000000000000000000000000000000000000..de0d4c16d7d5f6af6b3eb05f724c3e9b1c2809c7 --- /dev/null +++ b/ArkUISample/ScrollableComponent/entry/src/main/ets/pages/tabs/CustomTabBar.ets @@ -0,0 +1,97 @@ +/* + * Copyright (c) 2025 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { ComponentCard } from '../../common/Card'; + +@Entry +@Component +export struct CustomTabBar { + // [Start custom_tab_bar_style] + @State currentIndex: number = 0; + + @Builder + tabBuilder(title: ResourceStr, targetIndex: number, selectedImg: Resource, normalImg: Resource) { + Column() { + Image(this.currentIndex === targetIndex ? selectedImg : normalImg) + .size({ width: 25, height: 25 }) + Text(title) + .fontColor(this.currentIndex === targetIndex ? '#1698CE' : '#6B6B6B') + } + .width('100%') + .height(50) + .justifyContent(FlexAlign.Center) + } + // [End custom_tab_bar_style] + + build() { + NavDestination() { + Column({ space: 12 }) { + ComponentCard({ title: $r('app.string.CustomTabBar_titleExample') }) { + Tabs({ barPosition: BarPosition.End }) { + TabContent() { + Text($r('app.string.internet_content')) + .fontSize(30) + } + .backgroundColor(Color.Blue) + .tabBar(this.tabBuilder($r('app.string.internet'), + 0, + $r('sys.media.ohos_ic_public_web'), + $r('sys.media.ohos_ic_public_web'))) + + TabContent() { + Text($r('app.string.album_content')) + .fontSize(30) + } + .backgroundColor(Color.Green) + .tabBar(this.tabBuilder($r('app.string.album'), + 1, + $r('sys.media.ohos_ic_public_albums'), + $r('sys.media.ohos_ic_public_albums'))) + + TabContent() { + Text($r('app.string.video_content')) + .fontSize(30) + } + .backgroundColor(Color.Yellow) + .tabBar(this.tabBuilder($r('app.string.video'), + 2, + $r('sys.media.ohos_ic_public_video'), + $r('sys.media.ohos_ic_public_video'))) + + // [Start set_custom_tab_bar_style] + TabContent() { + Text($r('app.string.more_content')) + .fontSize(30) + } + .backgroundColor(Color.Orange) + .tabBar(this.tabBuilder($r('app.string.more'), + 3, + $r('sys.media.ohos_ic_public_drawer_open'), + $r('sys.media.ohos_ic_public_drawer_open'))) + // [End set_custom_tab_bar_style] + }.height(500) + .onChange((index: number) => { + this.currentIndex = index; // 监听索引index的变化,实现页签内容的切换。 + }) + } + } + .width('100%') + .height('100%') + .padding({ left: 12, right: 12 }) + } + .backgroundColor('#f1f2f3') + .title($r('app.string.CustomTabBar_title')) + } +} \ No newline at end of file diff --git a/ArkUISample/ScrollableComponent/entry/src/main/ets/pages/tabs/FixedTabBar.ets b/ArkUISample/ScrollableComponent/entry/src/main/ets/pages/tabs/FixedTabBar.ets new file mode 100644 index 0000000000000000000000000000000000000000..a786d084a857b391180a9d90a75183ba0414f435 --- /dev/null +++ b/ArkUISample/ScrollableComponent/entry/src/main/ets/pages/tabs/FixedTabBar.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. + */ + +import { ComponentCard } from '../../common/Card'; + +@Entry +@Component +export struct FixedTabBar { + build() { + NavDestination() { + Column({ space: 12 }) { + ComponentCard({ title: $r('app.string.FixedTabBar_titleExample') }) { + // [Start fixed_tab_bar] + Tabs({ barPosition: BarPosition.End }) { + // [StartExclude fixed_tab_bar] + TabContent() { + Text($r('app.string.homepage_content')) + .fontSize(30) + } + .backgroundColor(Color.Blue) + .tabBar($r('app.string.homepage')) + + TabContent() { + Text($r('app.string.recommend_content')) + .fontSize(30) + } + .backgroundColor(Color.Green) + .tabBar($r('app.string.recommend')) + + TabContent() { + Text($r('app.string.discover_content')) + .fontSize(30) + } + .backgroundColor(Color.Yellow) + .tabBar($r('app.string.discover')) + + TabContent() { + Text($r('app.string.mine_content')) + .fontSize(30) + } + .backgroundColor(Color.Orange) + .tabBar($r('app.string.mine')) + // [EndExclude fixed_tab_bar] + } + // [StartExclude fixed_tab_bar] + .height(500) + // [EndExclude fixed_tab_bar] + .barMode(BarMode.Fixed) + // [End fixed_tab_bar] + } + } + .width('100%') + .height('100%') + .padding({ left: 12, right: 12 }) + } + .backgroundColor('#f1f2f3') + .title($r('app.string.FixedTabBar_title')) + } +} \ No newline at end of file diff --git a/ArkUISample/ScrollableComponent/entry/src/main/ets/pages/tabs/ScrollableTabBar.ets b/ArkUISample/ScrollableComponent/entry/src/main/ets/pages/tabs/ScrollableTabBar.ets new file mode 100644 index 0000000000000000000000000000000000000000..ef93f632f6f18c893105e7fb735219eddd5f55cb --- /dev/null +++ b/ArkUISample/ScrollableComponent/entry/src/main/ets/pages/tabs/ScrollableTabBar.ets @@ -0,0 +1,100 @@ +/* + * Copyright (c) 2025 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 { ComponentCard } from '../../common/Card'; + +@Entry +@Component +export struct ScrollableTabBar { + build() { + NavDestination() { + Column({ space: 12 }) { + ComponentCard({ title: $r('app.string.ScrollableTabBar_titleExample') }) { + // [Start scrollable_tab_bar] + Tabs({ barPosition: BarPosition.Start }) { + // [StartExclude scrollable_tab_bar] + TabContent() { + Text($r('app.string.FocusOn_content')) + .fontSize(30) + } + .backgroundColor(Color.Blue) + .tabBar($r('app.string.FocusOn')) + + TabContent() { + Text($r('app.string.video_content')) + .fontSize(30) + } + .backgroundColor(Color.Green) + .tabBar($r('app.string.video')) + + TabContent() { + Text($r('app.string.game_content')) + .fontSize(30) + } + .backgroundColor(Color.Yellow) + .tabBar($r('app.string.game')) + + TabContent() { + Text($r('app.string.digit_content')) + .fontSize(30) + } + .backgroundColor(Color.Orange) + .tabBar($r('app.string.digit')) + + TabContent() { + Text($r('app.string.technology_content')) + .fontSize(30) + } + .backgroundColor(Color.Pink) + .tabBar($r('app.string.technology')) + + TabContent() { + Text($r('app.string.sport_content')) + .fontSize(30) + } + .backgroundColor(Color.Gray) + .tabBar($r('app.string.sport')) + + TabContent() { + Text($r('app.string.film_content')) + .fontSize(30) + } + .backgroundColor(Color.Brown) + .tabBar($r('app.string.film')) + + TabContent() { + Text($r('app.string.humanities_content')) + .fontSize(30) + } + .backgroundColor(Color.Red) + .tabBar($r('app.string.humanities')) + // [EndExclude scrollable_tab_bar] + } + // [StartExclude scrollable_tab_bar] + .barWidth(250) + .height(500) + // [EndExclude scrollable_tab_bar] + .barMode(BarMode.Scrollable) + // [End scrollable_tab_bar] + } + } + .width('100%') + .height('100%') + .padding({ left: 12, right: 12 }) + } + .backgroundColor('#f1f2f3') + .title($r('app.string.ScrollableTabBar_title')) + } +} \ No newline at end of file diff --git a/ArkUISample/ScrollableComponent/entry/src/main/ets/pages/tabs/SideTabBar.ets b/ArkUISample/ScrollableComponent/entry/src/main/ets/pages/tabs/SideTabBar.ets new file mode 100644 index 0000000000000000000000000000000000000000..70f2bedb836d1787b542c25a3a40a207943121c7 --- /dev/null +++ b/ArkUISample/ScrollableComponent/entry/src/main/ets/pages/tabs/SideTabBar.ets @@ -0,0 +1,73 @@ +/* + * Copyright (c) 2025 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 { ComponentCard } from '../../common/Card'; + +@Entry +@Component +export struct SideTabBar { + build() { + NavDestination() { + Column({ space: 12 }) { + ComponentCard({ title: $r('app.string.SideTabBar_titleExample') }) { + // [Start side_navigation] + Tabs({ barPosition: BarPosition.Start }) { + // [StartExclude side_navigation] + TabContent() { + Text($r('app.string.homepage_content')) + .fontSize(30) + } + .backgroundColor(Color.Blue) + .tabBar($r('app.string.homepage')) + + TabContent() { + Text($r('app.string.recommend_content')) + .fontSize(30) + } + .backgroundColor(Color.Green) + .tabBar($r('app.string.recommend')) + + TabContent() { + Text($r('app.string.discover_content')) + .fontSize(30) + } + .backgroundColor(Color.Yellow) + .tabBar($r('app.string.discover')) + + TabContent() { + Text($r('app.string.mine_content')) + .fontSize(30) + } + .backgroundColor(Color.Orange) + .tabBar($r('app.string.mine')) + // [EndExclude side_navigation] + } + // [StartExclude side_navigation] + .height(200) + // [EndExclude side_navigation] + .vertical(true) + .barWidth(100) + .barHeight(200) + // [End side_navigation] + } + } + .width('100%') + .height('100%') + .padding({ left: 12, right: 12 }) + } + .backgroundColor('#f1f2f3') + .title($r('app.string.SideTabBar_title')) + } +} \ No newline at end of file diff --git a/ArkUISample/ScrollableComponent/entry/src/main/ets/pages/tabs/SwipeLockedTabBar.ets b/ArkUISample/ScrollableComponent/entry/src/main/ets/pages/tabs/SwipeLockedTabBar.ets new file mode 100644 index 0000000000000000000000000000000000000000..abb21c01b947663fde1ec16839c73dd40b0912c0 --- /dev/null +++ b/ArkUISample/ScrollableComponent/entry/src/main/ets/pages/tabs/SwipeLockedTabBar.ets @@ -0,0 +1,104 @@ +/* + * Copyright (c) 2025 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { ComponentCard } from '../../common/Card'; + +@Entry +@Component +export struct SwipeLockedTabBar { + build() { + NavDestination() { + Column({ space: 12 }) { + ComponentCard({ title: $r('app.string.SwipeLockedTabBar_titleExample') }) { + // [Start swipe_locked_tab_bar] + Tabs({ barPosition: BarPosition.End }) { + TabContent() { + Column() { + Tabs() { + // 顶部导航栏内容 + // [StartExclude swipe_locked_tab_bar] + TabContent() { + Text($r('app.string.FocusOn_content')) + .fontSize(30) + } + .tabBar($r('app.string.FocusOn')) + + TabContent() { + Text($r('app.string.video_content')) + .fontSize(30) + } + .tabBar($r('app.string.video')) + + TabContent() { + Text($r('app.string.game_content')) + .fontSize(30) + } + .tabBar($r('app.string.game')) + + TabContent() { + Text($r('app.string.digit_content')) + .fontSize(30) + } + .tabBar($r('app.string.digit')) + + TabContent() { + Text($r('app.string.technology_content')) + .fontSize(30) + } + .tabBar($r('app.string.technology')) + } + } + .backgroundColor('#ffffc6d1') + .width('100%') + } + .tabBar($r('app.string.homepage')) + + TabContent() { + Text($r('app.string.recommend_content')) + .fontSize(30) + } + .backgroundColor(Color.Green) + .tabBar($r('app.string.recommend')) + + TabContent() { + Text($r('app.string.discover_content')) + .fontSize(30) + } + .backgroundColor(Color.Yellow) + .tabBar($r('app.string.discover')) + + TabContent() { + Text($r('app.string.mine_content')) + .fontSize(30) + } + .backgroundColor(Color.Orange) + .tabBar($r('app.string.mine')) + // [EndExclude swipe_locked_tab_bar] + } + // [StartExclude swipe_locked_tab_bar] + .height(500) + // [EndExclude swipe_locked_tab_bar] + .scrollable(false) + // [End swipe_locked_tab_bar] + } + } + .width('100%') + .height('100%') + .padding({ left: 12, right: 12 }) + } + .backgroundColor('#f1f2f3') + .title($r('app.string.SwipeLockedTabBar_title')) + } +} \ No newline at end of file diff --git a/ArkUISample/ScrollableComponent/entry/src/main/ets/pages/tabs/TabsLayout.ets b/ArkUISample/ScrollableComponent/entry/src/main/ets/pages/tabs/TabsLayout.ets new file mode 100644 index 0000000000000000000000000000000000000000..2ab0bde038280cc905ab9ff1b135dbf3d21deae8 --- /dev/null +++ b/ArkUISample/ScrollableComponent/entry/src/main/ets/pages/tabs/TabsLayout.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. + */ + +import { ComponentCard } from '../../common/Card'; + +@Entry +@Component +export struct TabsLayout { + build() { + NavDestination() { + Column({ space: 12 }) { + ComponentCard({ title: $r('app.string.TabsLayout_titleExample') }) { + // [Start basic_layout_displays_many_contents] + Tabs() { + // [Start basic_layout_displays_one_content] + TabContent() { + Text($r('app.string.homepage_content')) + .fontSize(30) + } + .tabBar($r('app.string.homepage')) + // [End basic_layout_displays_one_content] + + TabContent() { + Text($r('app.string.recommend_content')) + .fontSize(30) + } + .tabBar($r('app.string.recommend')) + + TabContent() { + Text($r('app.string.discover_content')) + .fontSize(30) + } + .tabBar($r('app.string.discover')) + + TabContent() { + Text($r('app.string.mine_content')) + .fontSize(30) + } + .tabBar($r('app.string.mine')) + // [StartExclude basic_layout_displays_many_contents] + }.height(300) + // [EndExclude basic_layout_displays_many_contents] + } + // [End basic_layout_displays_many_contents] + } + .width('100%') + .height('100%') + .padding({ left: 12, right: 12 }) + } + .backgroundColor('#f1f2f3') + .title($r('app.string.TabsLayout_title')) + } +} \ No newline at end of file diff --git a/ArkUISample/ScrollableComponent/entry/src/main/ets/pages/tabs/TopTabBar.ets b/ArkUISample/ScrollableComponent/entry/src/main/ets/pages/tabs/TopTabBar.ets new file mode 100644 index 0000000000000000000000000000000000000000..ac40d162d18cf06d0ecfae41db5afd64839dd0b2 --- /dev/null +++ b/ArkUISample/ScrollableComponent/entry/src/main/ets/pages/tabs/TopTabBar.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 { ComponentCard } from '../../common/Card'; + +@Entry +@Component +export struct TopTabBar { + build() { + NavDestination() { + Column({ space: 12 }) { + ComponentCard({ title: $r('app.string.TopTabBar_titleExample') }) { + // [Start top_navigation] + Tabs({ barPosition: BarPosition.Start }) { + // [StartExclude top_navigation] + TabContent() { + Text($r('app.string.FocusOn_content')) + .fontSize(30) + } + .backgroundColor(Color.Blue) + .tabBar($r('app.string.FocusOn')) + + TabContent() { + Text($r('app.string.video_content')) + .fontSize(30) + } + .backgroundColor(Color.Green) + .tabBar($r('app.string.video')) + + TabContent() { + Text($r('app.string.game_content')) + .fontSize(30) + } + .backgroundColor(Color.Yellow) + .tabBar($r('app.string.game')) + + TabContent() { + Text($r('app.string.digit_content')) + .fontSize(30) + } + .backgroundColor(Color.Orange) + .tabBar($r('app.string.digit')) + + TabContent() { + Text($r('app.string.technology_content')) + .fontSize(30) + } + .backgroundColor(Color.Pink) + .tabBar($r('app.string.technology')) + }.height(500) + // [EndExclude top_navigation] + } + // [End top_navigation] + } + .width('100%') + .height('100%') + .padding({ left: 12, right: 12 }) + } + .backgroundColor('#f1f2f3') + .title($r('app.string.TopTabBar_title')) + } +} \ No newline at end of file diff --git a/ArkUISample/ScrollableComponent/entry/src/main/ets/pages/tabs/index.ets b/ArkUISample/ScrollableComponent/entry/src/main/ets/pages/tabs/index.ets new file mode 100644 index 0000000000000000000000000000000000000000..b601f6080cca995f0b2a9c9f1acdb62245de2a22 --- /dev/null +++ b/ArkUISample/ScrollableComponent/entry/src/main/ets/pages/tabs/index.ets @@ -0,0 +1,139 @@ +/* + * Copyright (c) 2025 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 { AgeFriendlyTabs } from './AgeFriendlyTabs'; +import { BottomTabBar } from './BottomTabBar'; +import { CompletedRoutableCard } from '../../common/Card'; +import { ContentWillChange } from './ContentWillChange'; +import { CustomTabBar } from './CustomTabBar'; +import { FixedTabBar } from './FixedTabBar'; +import { Route } from '../../common/Route'; +import { ScrollableTabBar } from './ScrollableTabBar'; +import { SideTabBar } from './SideTabBar'; +import { SwipeLockedTabBar } from './SwipeLockedTabBar'; +import { TabsLayout } from './TabsLayout'; +import { TopTabBar } from './TopTabBar'; +import resource from '../../common/resource'; + +export const TABS_ROUTE_PREFIX: string = 'tabs'; + +const routes: Route[] = [ + { + name: `${TABS_ROUTE_PREFIX}/TabsLayout`, + title: resource.resourceToString($r('app.string.TabsLayout_title')), + description: $r('app.string.TabsLayout_description') + }, + { + name: `${TABS_ROUTE_PREFIX}/BottomTabBar`, + title: resource.resourceToString($r('app.string.BottomTabBar_title')), + description: $r('app.string.BottomTabBar_description') + }, + { + name: `${TABS_ROUTE_PREFIX}/TopTabBar`, + title: resource.resourceToString($r('app.string.TopTabBar_title')), + description: $r('app.string.TopTabBar_description') + }, + { + name: `${TABS_ROUTE_PREFIX}/SideTabBar`, + title: resource.resourceToString($r('app.string.SideTabBar_title')), + description: $r('app.string.SideTabBar_description') + }, + { + name: `${TABS_ROUTE_PREFIX}/SwipeLockedTabBar`, + title: resource.resourceToString($r('app.string.SwipeLockedTabBar_title')), + description: $r('app.string.SwipeLockedTabBar_description') + }, + { + name: `${TABS_ROUTE_PREFIX}/FixedTabBar`, + title: resource.resourceToString($r('app.string.FixedTabBar_title')), + description: $r('app.string.FixedTabBar_description') + }, + { + name: `${TABS_ROUTE_PREFIX}/ScrollableTabBar`, + title: resource.resourceToString($r('app.string.ScrollableTabBar_title')), + description: $r('app.string.ScrollableTabBar_description') + }, + { + name: `${TABS_ROUTE_PREFIX}/CustomTabBar`, + title: resource.resourceToString($r('app.string.CustomTabBar_title')), + description: $r('app.string.CustomTabBar_description') + }, + { + name: `${TABS_ROUTE_PREFIX}/ContentWillChange`, + title: resource.resourceToString($r('app.string.ContentWillChange_title')), + description: $r('app.string.ContentWillChange_description') + }, + { + name: `${TABS_ROUTE_PREFIX}/AgeFriendlyTabs`, + title: resource.resourceToString($r('app.string.AgeFriendlyTabs_title')), + description: $r('app.string.AgeFriendlyTabs_description') + } +]; + +@Builder +export function tabsDestination(name: string) { + if (name === TABS_ROUTE_PREFIX) { + TabsExample(); + } else if (name === routes[0].name) { + TabsLayout(); + } else if (name === routes[1].name) { + BottomTabBar(); + } else if (name === routes[2].name) { + TopTabBar(); + } else if (name === routes[3].name) { + SideTabBar(); + } else if (name === routes[4].name) { + SwipeLockedTabBar(); + } else if (name === routes[5].name) { + FixedTabBar(); + } else if (name === routes[6].name) { + ScrollableTabBar(); + } else if (name === routes[7].name) { + CustomTabBar(); + } else if (name === routes[8].name) { + ContentWillChange(); + } else if (name === routes[9].name) { + AgeFriendlyTabs(); + } +} + +@Entry +@Component +struct TabsExample { + @Consume pathStack: NavPathStack; + + build() { + NavDestination() { + List({ space: 12 }) { + ForEach(routes, (route: Route) => { + ListItem() { + CompletedRoutableCard({ title: route.title, description: route.description }) + } + .width('100%') + .onClick(() => { + this.pathStack.pushPath({ name: route.name }); + }) + }) + } + .contentStartOffset(56) + .padding({ left: 16, right: 16 }) + } + .backgroundColor('#f1f3f5') + .title('Tabs', { + backgroundBlurStyle: BlurStyle.COMPONENT_THICK, + barStyle: BarStyle.STACK + }) + } +} diff --git a/ArkUISample/ScrollableComponent/entry/src/main/ets/pages/waterFlow/WaterFlowDataSource.ets b/ArkUISample/ScrollableComponent/entry/src/main/ets/pages/waterFlow/WaterFlowDataSource.ets new file mode 100644 index 0000000000000000000000000000000000000000..7b3da71291ad3baec05975d0dfc0ee7a26d57813 --- /dev/null +++ b/ArkUISample/ScrollableComponent/entry/src/main/ets/pages/waterFlow/WaterFlowDataSource.ets @@ -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. + */ + +// 实现IDataSource接口的对象,用于瀑布流组件加载数据 +export class WaterFlowDataSource implements IDataSource { + private dataArray: number[] = []; + private listeners: DataChangeListener[] = []; + + constructor(count: number) { + for (let i = 0; i < count; i++) { + this.dataArray.push(i); + } + } + + // 获取索引对应的数据 + public getData(index: number): number { + return this.dataArray[index]; + } + + // 通知控制器数据重新加载 + notifyDataReload(): void { + this.listeners.forEach(listener => { + listener.onDataReloaded(); + }) + } + + // 通知控制器数据增加 + notifyDataAdd(index: number): void { + this.listeners.forEach(listener => { + listener.onDataAdd(index); + }) + } + + // 通知控制器数据变化 + notifyDataChange(index: number): void { + this.listeners.forEach(listener => { + listener.onDataChange(index); + }) + } + + // 通知控制器数据删除 + notifyDataDelete(index: number): void { + this.listeners.forEach(listener => { + listener.onDataDelete(index); + }) + } + + // 通知控制器数据位置变化 + notifyDataMove(from: number, to: number): void { + this.listeners.forEach(listener => { + listener.onDataMove(from, to); + }) + } + + // 获取数据总数 + public totalCount(): number { + return this.dataArray.length; + } + + // 注册改变数据的控制器 + registerDataChangeListener(listener: DataChangeListener): void { + if (this.listeners.indexOf(listener) < 0) { + this.listeners.push(listener); + } + } + + // 注销改变数据的控制器 + unregisterDataChangeListener(listener: DataChangeListener): void { + const pos = this.listeners.indexOf(listener) + if (pos >= 0) { + this.listeners.splice(pos, 1); + } + } + + // 增加数据 + public add1stItem(): void { + this.dataArray.splice(0, 0, this.dataArray.length); + this.notifyDataAdd(0); + } + + // 在数据尾部增加一个元素 + public addLastItem(): void { + this.dataArray.splice(this.dataArray.length, 0, this.dataArray.length); + this.notifyDataAdd(this.dataArray.length - 1); + } + + public addNewItems(count: number): void { + for (let i = 0; i < count; i++) { + this.dataArray.push(this.dataArray.length); + this.notifyDataAdd(this.dataArray.length - 1); + } + } + + // 在指定索引位置增加一个元素 + public addItem(index: number): void { + this.dataArray.splice(index, 0, this.dataArray.length); + this.notifyDataAdd(index); + } + + // 删除第一个元素 + public delete1stItem(): void { + this.dataArray.splice(0, 1); + this.notifyDataDelete(0); + } + + // 删除第二个元素 + public delete2ndItem(): void { + this.dataArray.splice(1, 1); + this.notifyDataDelete(1); + } + + // 删除最后一个元素 + public deleteLastItem(): void { + this.dataArray.splice(-1, 1); + this.notifyDataDelete(this.dataArray.length); + } + + // 在指定索引位置增加一个元素 + public deleteItem(index: number): void { + this.dataArray.splice(index, 1); + this.notifyDataDelete(index); + } + + // 重新加载数据 + public reload(): void { + this.dataArray.splice(1, 1); + this.dataArray.splice(3, 2); + this.notifyDataReload(); + } +} diff --git a/ArkUISample/ScrollableComponent/entry/src/main/ets/pages/waterFlow/WaterFlowDynamicSwitchover.ets b/ArkUISample/ScrollableComponent/entry/src/main/ets/pages/waterFlow/WaterFlowDynamicSwitchover.ets new file mode 100644 index 0000000000000000000000000000000000000000..c29d63a200626cd65b586fe914976c14bf68e067 --- /dev/null +++ b/ArkUISample/ScrollableComponent/entry/src/main/ets/pages/waterFlow/WaterFlowDynamicSwitchover.ets @@ -0,0 +1,179 @@ +/* + * Copyright (c) 2025 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 { ComponentCard } from '../../common/Card'; +import { WaterFlowDataSource } from './WaterFlowDataSource' +import { image } from '@kit.ImageKit'; + +@Reusable +@Component +struct ReusableFlowItem { + @State item: number = 0; + + // 从复用缓存中加入到组件树之前调用,可在此处更新组件的状态变量以展示正确的内容 + aboutToReuse(params: Record) { + this.item = params.item; + } + + build() { + Column() { + Text('FlowItem' + this.item).fontSize(16).height('16') + Image('res/waterFlow(' + this.item % 5 + ').JPG') + .objectFit(ImageFit.Fill) + .width('100%') + .layoutWeight(1) + } + } +} + +@Reusable +@Component +struct ReusableListItem { + @State item: number = 0; + + aboutToReuse(params: Record) { + this.item = params.item; + } + + build() { + Row() { + Image('res/waterFlow(' + this.item % 5 + ').JPG') + .objectFit(ImageFit.Fill) + .height(100) + .aspectRatio(1) + Text('N' + this.item).fontSize(12).height('16').layoutWeight(1).textAlign(TextAlign.Center) + } + } +} + +@Entry +@Component +export struct WaterFlowDynamicSwitchover { + minSize: number = 80; + maxSize: number = 180; + colors: number[] = [0xFFC0CB, 0xDA70D6, 0x6B8E23, 0x6A5ACD, 0x00FFFF, 0x00FF7F]; + dataSource: WaterFlowDataSource = new WaterFlowDataSource(100); + private itemWidthArray: number[] = []; + private itemHeightArray: number[] = []; + @State columns: number = 2; + @State waterflowScale: number = 1; + @State imageScale: number = 1; + @State waterFlowOpacity: number = 1; + @State waterflowSnapshot: image.PixelMap | undefined = undefined; + private columnChanged: boolean = false; + private oldColumn: number = this.columns; + private pinchTime: number = 0; + private gridItems: number[] = []; + + // 计算FlowItem宽/高 + getSize() { + let ret = Math.floor(Math.random() * this.maxSize); + return (ret > this.minSize ? ret : this.minSize); + } + + // 设置FlowItem的宽/高数组 + setItemSizeArray() { + for (let i = 0; i < 100; i++) { + this.itemWidthArray.push(this.getSize()); + this.itemHeightArray.push(this.getSize()); + } + } + + aboutToAppear() { + // 读取上次最后切换到到列数 + let lastCount = AppStorage.get('columnsCount'); + if (typeof lastCount != 'undefined') { + this.columns = lastCount; + } + this.setItemSizeArray(); + for (let i = 0; i < 15; ++i) { + this.gridItems.push(i); + } + } + + // 根据缩放阈值改变列数,触发WaterFlow重新布局 + changeColumns(scale: number) { + if (scale > (this.columns / (this.columns - 0.5)) && this.columns > 1) { + this.columns--; + this.columnChanged = true; + } else if (scale < 1 && this.columns < 4) { + this.columns++; + this.columnChanged = true; + } + } + + @Builder + itemFoot() { + Row() { + LoadingProgress() + .color(Color.Blue).height(50).aspectRatio(1).width('20%') + Text(`正在加载`) + .fontSize(20) + .width('30%') + .height(50) + .align(Alignment.Center) + .margin({ top: 2 }) + }.width('100%').justifyContent(FlexAlign.Center) + } + + build() { + NavDestination() { + Column({ space: 12 }) { + ComponentCard({ title: $r('app.string.WaterFlowDynamicSwitchover_title') }) { + Column({ space: 2 }) { + Button('切换列数').fontSize(20).onClick(() => { + if (this.columns === 2) { + this.columns = 1; + } else { + this.columns = 2; + } + }) + WaterFlow({ layoutMode: WaterFlowLayoutMode.SLIDING_WINDOW }) { + LazyForEach(this.dataSource, (item: number) => { + FlowItem() { + if (this.columns === 1) { + ReusableListItem({ item: item }) + } else { + ReusableFlowItem({ item: item }) + } + } + .width('100%') + .aspectRatio(this.columns === 2 ? this.itemHeightArray[item % 100] / this.itemWidthArray[item % 100] : 0) + .backgroundColor(this.colors[item % 5]) + }, (item: string) => item) + } + .columnsTemplate('1fr '.repeat(this.columns)) + .backgroundColor(0xFAEEE0) + .width('100%') + .height('100%') + .layoutWeight(1) + // 即将触底时提前增加数据 + .onScrollIndex((first: number, last: number) => { + if (last + 20 >= this.dataSource.totalCount()) { + setTimeout(() => { + this.dataSource.addNewItems(100); + }, 1000); + } + }) + } + } + } + .width('100%') + .height('100%') + } + .backgroundColor('#f1f2f3') + .title($r('app.string.WaterFlowDynamicSwitchover_title')) + } +} diff --git a/ArkUISample/ScrollableComponent/entry/src/main/ets/pages/waterFlow/WaterFlowGroupingMixing.ets b/ArkUISample/ScrollableComponent/entry/src/main/ets/pages/waterFlow/WaterFlowGroupingMixing.ets new file mode 100644 index 0000000000000000000000000000000000000000..7c0059d37dd6751cc978abce4d67f1adaadfb5e4 --- /dev/null +++ b/ArkUISample/ScrollableComponent/entry/src/main/ets/pages/waterFlow/WaterFlowGroupingMixing.ets @@ -0,0 +1,180 @@ +/* + * Copyright (c) 2025 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 { ComponentCard } from '../../common/Card'; +import { WaterFlowDataSource } from './WaterFlowDataSource' +import { image } from '@kit.ImageKit'; + +@Reusable +@Component +struct ReusableFlowItem { + @State item: number = 0; + + // 从复用缓存中加入到组件树之前调用,可在此处更新组件的状态变量以展示正确的内容 + aboutToReuse(params: Record) { + this.item = params.item; + } + + build() { + Stack({ alignContent: Alignment.Center }) { + Text('FlowItem' + this.item).fontSize(14).height('16') + Image('res/waterFlow (' + this.item % 5 + ').JPG') + .objectFit(ImageFit.Fill) + .width('100%') + .layoutWeight(1) + } + } +} + +@Entry +@Component +export struct WaterFlowGroupingMixing { + minSize: number = 80; + maxSize: number = 180; + colors: number[] = [0xFFC0CB, 0xDA70D6, 0x6B8E23, 0x6A5ACD, 0x00FFFF, 0x00FF7F]; + dataSource: WaterFlowDataSource = new WaterFlowDataSource(100); + private itemWidthArray: number[] = []; + private itemHeightArray: number[] = []; + @State columns: number = 2; + @State waterflowScale: number = 1; + @State imageScale: number = 1; + @State waterFlowOpacity: number = 1; + @State waterflowSnapshot: image.PixelMap | undefined = undefined; + private columnChanged: boolean = false; + private oldColumn: number = this.columns; + private pinchTime: number = 0; + private gridItems: number[] = []; + + // 计算FlowItem宽/高 + getSize() { + let ret = Math.floor(Math.random() * this.maxSize); + return (ret > this.minSize ? ret : this.minSize); + } + + // 设置FlowItem的宽/高数组 + setItemSizeArray() { + for (let i = 0; i < 100; i++) { + this.itemWidthArray.push(this.getSize()); + this.itemHeightArray.push(this.getSize()); + } + } + + aboutToAppear() { + // 读取上次最后切换到到列数 + let lastCount = AppStorage.get('columnsCount'); + if (typeof lastCount != 'undefined') { + this.columns = lastCount; + } + this.setItemSizeArray(); + for (let i = 0; i < 15; ++i) { + this.gridItems.push(i); + } + } + + // 根据缩放阈值改变列数,触发WaterFlow重新布局 + changeColumns(scale: number) { + if (scale > (this.columns / (this.columns - 0.5)) && this.columns > 1) { + this.columns--; + this.columnChanged = true; + } else if (scale < 1 && this.columns < 4) { + this.columns++; + this.columnChanged = true; + } + } + + @Builder + itemFoot() { + Row() { + LoadingProgress() + .color(Color.Blue).height(50).aspectRatio(1).width('20%') + Text(`正在加载`) + .fontSize(20) + .width('30%') + .height(50) + .align(Alignment.Center) + .margin({ top: 2 }) + }.width('100%').justifyContent(FlexAlign.Center) + } + + build() { + NavDestination() { + Column({ space: 12 }) { + ComponentCard({ title: $r('app.string.WaterFlowGroupingMixing_title') }) { + List({ space: 10 }) { + ListItem() { + Text('List').fontSize(14).height(16).margin(3) + } + + ListItem() { + Column() { + Text('Grid in ListItem').fontSize(12).height(16).margin(3) + + Grid() { + ForEach(this.gridItems, (day: number) => { + GridItem() { + Text('GridItem').fontSize(10).height(16) + }.backgroundColor(0xFFC0CB) + }, (day: number) => day.toString()) + } + .height('30%') + .rowsGap(5) + .columnsGap(5) + .columnsTemplate('1fr '.repeat(5)) + .rowsTemplate('1fr '.repeat(3)) + .width('95%') + }.borderWidth(3) + } + + ListItem() { + Column() { + Text('WaterFlow in ListItem').fontSize(14).height(16).margin(3) + WaterFlow({ layoutMode: WaterFlowLayoutMode.SLIDING_WINDOW }) { + LazyForEach(this.dataSource, (item: number) => { + FlowItem() { + ReusableFlowItem({ item: item }) + } + .width('100%') + .aspectRatio(this.columns === 2 ? this.itemHeightArray[item % 100] / this.itemWidthArray[item % 100] : 0) + .backgroundColor(this.colors[item % 5]) + }, (item: string) => item) + } + .columnsTemplate('1fr '.repeat(this.columns)) + .backgroundColor(0xFAEEE0) + .height('100%') + .layoutWeight(1) + // 即将触底时提前增加数据 + .onScrollIndex((first: number, last: number) => { + if (last + 20 >= this.dataSource.totalCount()) { + setTimeout(() => { + this.dataSource.addNewItems(100); + }, 1000) + } + }) + .width('95%') + }.borderWidth(3) + } + }.borderWidth(3) + .width('98%') + .alignListItem(ListItemAlign.Center).scrollBar(BarState.Off) + } + } + .width('100%') + .height('100%') + .padding({ left: 12, right: 12 }) + } + .backgroundColor('#f1f2f3') + .title($r('app.string.WaterFlowGroupingMixing_title')) + } +} diff --git a/ArkUISample/ScrollableComponent/entry/src/main/ets/pages/waterFlow/WaterFlowInfiniteScrolling.ets b/ArkUISample/ScrollableComponent/entry/src/main/ets/pages/waterFlow/WaterFlowInfiniteScrolling.ets new file mode 100644 index 0000000000000000000000000000000000000000..d5a726b1e8ce7a1b2cba8967b87f2c0aa2d9856a --- /dev/null +++ b/ArkUISample/ScrollableComponent/entry/src/main/ets/pages/waterFlow/WaterFlowInfiniteScrolling.ets @@ -0,0 +1,147 @@ +/* + * Copyright (c) 2025 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 { ComponentCard } from '../../common/Card'; +import { WaterFlowDataSource } from './WaterFlowDataSource' +import { image } from '@kit.ImageKit'; + +@Reusable +@Component +struct ReusableFlowItem { + @State item: number = 0; + + // 从复用缓存中加入到组件树之前调用,可在此处更新组件的状态变量以展示正确的内容 + aboutToReuse(params: Record) { + this.item = params.item; + } + + build() { + Column() { + Text('FlowItem' + this.item).fontSize(16).height('16') + Image('res/waterFlow(' + this.item % 5 + ').JPG') + .objectFit(ImageFit.Fill) + .width('100%') + .layoutWeight(1) + } + } +} + +@Entry +@Component +export struct WaterFlowInfiniteScrolling { + minSize: number = 80; + maxSize: number = 180; + colors: number[] = [0xFFC0CB, 0xDA70D6, 0x6B8E23, 0x6A5ACD, 0x00FFFF, 0x00FF7F]; + dataSource: WaterFlowDataSource = new WaterFlowDataSource(100); + private itemWidthArray: number[] = []; + private itemHeightArray: number[] = []; + @State columns: number = 2; + @State waterflowScale: number = 1; + @State imageScale: number = 1; + @State waterFlowOpacity: number = 1; + @State waterflowSnapshot: image.PixelMap | undefined = undefined; + private columnChanged: boolean = false; + private oldColumn: number = this.columns; + private pinchTime: number = 0; + private gridItems: number[] = []; + + // 计算FlowItem宽/高 + getSize() { + let ret = Math.floor(Math.random() * this.maxSize); + return (ret > this.minSize ? ret : this.minSize); + } + + // 设置FlowItem的宽/高数组 + setItemSizeArray() { + for (let i = 0; i < 100; i++) { + this.itemWidthArray.push(this.getSize()); + this.itemHeightArray.push(this.getSize()); + } + } + + aboutToAppear() { + // 读取上次最后切换到到列数 + let lastCount = AppStorage.get('columnsCount'); + if (typeof lastCount != 'undefined') { + this.columns = lastCount; + } + this.setItemSizeArray(); + for (let i = 0; i < 15; ++i) { + this.gridItems.push(i); + } + } + + // 根据缩放阈值改变列数,触发WaterFlow重新布局 + changeColumns(scale: number) { + if (scale > (this.columns / (this.columns - 0.5)) && this.columns > 1) { + this.columns--; + this.columnChanged = true; + } else if (scale < 1 && this.columns < 4) { + this.columns++; + this.columnChanged = true; + } + } + + @Builder + itemFoot() { + Row() { + LoadingProgress() + .color(Color.Blue).height(50).aspectRatio(1).width('20%') + Text(`正在加载`) + .fontSize(20) + .width('30%') + .height(50) + .align(Alignment.Center) + .margin({ top: 2 }) + }.width('100%').justifyContent(FlexAlign.Center) + } + + build() { + NavDestination() { + Column({ space: 12 }) { + ComponentCard({ title: $r('app.string.WaterFlowInfiniteScrolling_title') }) { + WaterFlow({ footer: this.itemFoot(), layoutMode: WaterFlowLayoutMode.SLIDING_WINDOW }) { + LazyForEach(this.dataSource, (item: number) => { + FlowItem() { + ReusableFlowItem({ item: item }) + } + .width('100%') + .aspectRatio(this.itemHeightArray[item % 100] / this.itemWidthArray[item%100]) + .backgroundColor(this.colors[item % 5]) + }, (item: string) => item) + } + .columnsTemplate('1fr '.repeat(this.columns)) + .backgroundColor(0xFAEEE0) + .width('100%') + .height('100%') + .layoutWeight(1) + // 触底加载数据 + .onReachEnd(() => { + setTimeout(() => { + for (let i = 0; i < 100; i++) { + this.dataSource.addLastItem(); + } + }, 1000) + }) + } + } + .width('100%') + .height('100%') + .padding({ left: 12, right: 12 }) + } + .backgroundColor('#f1f2f3') + .title($r('app.string.WaterFlowInfiniteScrolling_title')) + } +} diff --git a/ArkUISample/ScrollableComponent/entry/src/main/ets/pages/waterFlow/WaterFlowInfiniteScrollingEarly.ets b/ArkUISample/ScrollableComponent/entry/src/main/ets/pages/waterFlow/WaterFlowInfiniteScrollingEarly.ets new file mode 100644 index 0000000000000000000000000000000000000000..2862877a8551535664813f50471c033084e304b5 --- /dev/null +++ b/ArkUISample/ScrollableComponent/entry/src/main/ets/pages/waterFlow/WaterFlowInfiniteScrollingEarly.ets @@ -0,0 +1,147 @@ +/* + * Copyright (c) 2025 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 { ComponentCard } from '../../common/Card'; +import { WaterFlowDataSource } from './WaterFlowDataSource' +import { image } from '@kit.ImageKit'; + +@Reusable +@Component +struct ReusableFlowItem { + @State item: number = 0; + + // 从复用缓存中加入到组件树之前调用,可在此处更新组件的状态变量以展示正确的内容 + aboutToReuse(params: Record) { + this.item = params.item; + } + + build() { + Column() { + Text('FlowItem' + this.item).fontSize(16).height('16') + Image('res/waterFlow(' + this.item % 5 + ').JPG') + .objectFit(ImageFit.Fill) + .width('100%') + .layoutWeight(1) + } + } +} + +@Entry +@Component +export struct WaterFlowInfiniteScrollingEarly { + minSize: number = 80; + maxSize: number = 180; + colors: number[] = [0xFFC0CB, 0xDA70D6, 0x6B8E23, 0x6A5ACD, 0x00FFFF, 0x00FF7F]; + dataSource: WaterFlowDataSource = new WaterFlowDataSource(100); + private itemWidthArray: number[] = []; + private itemHeightArray: number[] = []; + @State columns: number = 2; + @State waterflowScale: number = 1; + @State imageScale: number = 1; + @State waterFlowOpacity: number = 1; + @State waterflowSnapshot: image.PixelMap | undefined = undefined; + private columnChanged: boolean = false; + private oldColumn: number = this.columns; + private pinchTime: number = 0; + private gridItems: number[] = []; + + // 计算FlowItem宽/高 + getSize() { + let ret = Math.floor(Math.random() * this.maxSize); + return (ret > this.minSize ? ret : this.minSize); + } + + // 设置FlowItem的宽/高数组 + setItemSizeArray() { + for (let i = 0; i < 100; i++) { + this.itemWidthArray.push(this.getSize()); + this.itemHeightArray.push(this.getSize()); + } + } + + aboutToAppear() { + // 读取上次最后切换到到列数 + let lastCount = AppStorage.get('columnsCount'); + if (typeof lastCount != 'undefined') { + this.columns = lastCount; + } + this.setItemSizeArray(); + for (let i = 0; i < 15; ++i) { + this.gridItems.push(i); + } + } + + // 根据缩放阈值改变列数,触发WaterFlow重新布局 + changeColumns(scale: number) { + if (scale > (this.columns / (this.columns - 0.5)) && this.columns > 1) { + this.columns--; + this.columnChanged = true; + } else if (scale < 1 && this.columns < 4) { + this.columns++; + this.columnChanged = true; + } + } + + @Builder + itemFoot() { + Row() { + LoadingProgress() + .color(Color.Blue).height(50).aspectRatio(1).width('20%') + Text(`正在加载`) + .fontSize(20) + .width('30%') + .height(50) + .align(Alignment.Center) + .margin({ top: 2 }) + }.width('100%').justifyContent(FlexAlign.Center) + } + + build() { + NavDestination() { + Column({ space: 12 }) { + ComponentCard({ title: $r('app.string.WaterFlowInfiniteScrollingEarly_title') }) { + WaterFlow({ layoutMode: WaterFlowLayoutMode.SLIDING_WINDOW }) { + LazyForEach(this.dataSource, (item: number) => { + FlowItem() { + ReusableFlowItem({ item: item }) + } + .width('100%') + .aspectRatio(this.itemHeightArray[item % 100] / this.itemWidthArray[item%100]) + .backgroundColor(this.colors[item % 5]) + }, (item: string) => item) + } + .columnsTemplate('1fr '.repeat(this.columns)) + .backgroundColor(0xFAEEE0) + .width('100%') + .height('100%') + .layoutWeight(1) + // 即将触底时提前增加数据 + .onScrollIndex((first: number, last: number) => { + if (last + 20 >= this.dataSource.totalCount()) { + setTimeout(() => { + this.dataSource.addNewItems(100); + }, 1000); + } + }) + } + } + .width('100%') + .height('100%') + .padding({ left: 12, right: 12 }) + } + .backgroundColor('#f1f2f3') + .title($r('app.string.WaterFlowInfiniteScrollingEarly_title')) + } +} \ No newline at end of file diff --git a/ArkUISample/ScrollableComponent/entry/src/main/ets/pages/waterFlow/index.ets b/ArkUISample/ScrollableComponent/entry/src/main/ets/pages/waterFlow/index.ets new file mode 100644 index 0000000000000000000000000000000000000000..d01ac386128fa796e232f882df4c2dc424073b59 --- /dev/null +++ b/ArkUISample/ScrollableComponent/entry/src/main/ets/pages/waterFlow/index.ets @@ -0,0 +1,92 @@ +/* + * Copyright (c) 2025 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { CompletedRoutableCard } from '../../common/Card'; +import { Route } from '../../common/Route'; +import { WaterFlowInfiniteScrolling } from './WaterFlowInfiniteScrolling'; +import { WaterFlowInfiniteScrollingEarly } from './WaterFlowInfiniteScrollingEarly'; +import { WaterFlowGroupingMixing } from './WaterFlowGroupingMixing'; +import { WaterFlowDynamicSwitchover } from './WaterFlowDynamicSwitchover'; +import resource from '../../common/resource'; + +export const WATERFLOW_ROUTE_PREFIX: string = 'waterFlow'; + +const routes: Route[] = [ + { + name: `${WATERFLOW_ROUTE_PREFIX}/WaterFlowInfiniteScrolling`, + title: resource.resourceToString($r('app.string.WaterFlowInfiniteScrolling_title')), + description: $r('app.string.WaterFlowInfiniteScrolling_description') + }, + { + name: `${WATERFLOW_ROUTE_PREFIX}/WaterFlowInfiniteScrollingEarly`, + title: resource.resourceToString($r('app.string.WaterFlowInfiniteScrollingEarly_title')), + description: $r('app.string.WaterFlowInfiniteScrollingEarly_description') + }, + { + name: `${WATERFLOW_ROUTE_PREFIX}/WaterFlowGroupingMixing`, + title: resource.resourceToString($r('app.string.WaterFlowGroupingMixing_title')), + description: $r('app.string.WaterFlowGroupingMixing_description') + }, + { + name: `${WATERFLOW_ROUTE_PREFIX}/WaterFlowDynamicSwitchover`, + title: resource.resourceToString($r('app.string.WaterFlowDynamicSwitchover_title')), + description: $r('app.string.WaterFlowDynamicSwitchover_description') + } + +]; + +@Builder +export function waterFlowDestination(name: string) { + if (name === WATERFLOW_ROUTE_PREFIX) { + WaterFlowExample(); + } else if (name === routes[0].name) { + WaterFlowInfiniteScrolling(); + } else if (name === routes[1].name) { + WaterFlowInfiniteScrollingEarly(); + } else if (name === routes[2].name) { + WaterFlowGroupingMixing(); + } else if (name === routes[3].name) { + WaterFlowDynamicSwitchover(); + } +} + +@Entry +@Component +struct WaterFlowExample { + @Consume pathStack: NavPathStack; + + build() { + NavDestination() { + List({ space: 12 }) { + ForEach(routes, (route: Route) => { + ListItem() { + CompletedRoutableCard({ title: route.title, description: route.description }) + } + .width('100%') + .onClick(() => { + this.pathStack.pushPath({ name: route.name }); + }) + }) + } + .contentStartOffset(56) + .padding({ left: 16, right: 16 }) + } + .backgroundColor('#f1f3f5') + .title('WaterFlow', { + backgroundBlurStyle: BlurStyle.COMPONENT_THICK, + barStyle: BarStyle.STACK + }) + } +} \ No newline at end of file diff --git a/ArkUISample/ScrollableComponent/entry/src/main/ets/res/waterFlow(0).JPG b/ArkUISample/ScrollableComponent/entry/src/main/ets/res/waterFlow(0).JPG new file mode 100644 index 0000000000000000000000000000000000000000..fc503bbffd260e135a6d1b8050ae8270b5b7b334 Binary files /dev/null and b/ArkUISample/ScrollableComponent/entry/src/main/ets/res/waterFlow(0).JPG differ diff --git a/ArkUISample/ScrollableComponent/entry/src/main/ets/res/waterFlow(1).JPG b/ArkUISample/ScrollableComponent/entry/src/main/ets/res/waterFlow(1).JPG new file mode 100644 index 0000000000000000000000000000000000000000..1085f839befca033a2687c554a47d535d589dc59 Binary files /dev/null and b/ArkUISample/ScrollableComponent/entry/src/main/ets/res/waterFlow(1).JPG differ diff --git a/ArkUISample/ScrollableComponent/entry/src/main/ets/res/waterFlow(2).JPG b/ArkUISample/ScrollableComponent/entry/src/main/ets/res/waterFlow(2).JPG new file mode 100644 index 0000000000000000000000000000000000000000..680348896f729a6b7d3860613403485a5a3090b7 Binary files /dev/null and b/ArkUISample/ScrollableComponent/entry/src/main/ets/res/waterFlow(2).JPG differ diff --git a/ArkUISample/ScrollableComponent/entry/src/main/ets/res/waterFlow(3).JPG b/ArkUISample/ScrollableComponent/entry/src/main/ets/res/waterFlow(3).JPG new file mode 100644 index 0000000000000000000000000000000000000000..0805dade041dc79b2dbc336f104fbaa8c86186e7 Binary files /dev/null and b/ArkUISample/ScrollableComponent/entry/src/main/ets/res/waterFlow(3).JPG differ diff --git a/ArkUISample/ScrollableComponent/entry/src/main/ets/res/waterFlow(4).JPG b/ArkUISample/ScrollableComponent/entry/src/main/ets/res/waterFlow(4).JPG new file mode 100644 index 0000000000000000000000000000000000000000..1ee3676323ab5637c00f5d486e72f5d6776e85a7 Binary files /dev/null and b/ArkUISample/ScrollableComponent/entry/src/main/ets/res/waterFlow(4).JPG differ diff --git a/ArkUISample/ScrollableComponent/entry/src/main/ets/res/waterFlow(5).JPG b/ArkUISample/ScrollableComponent/entry/src/main/ets/res/waterFlow(5).JPG new file mode 100644 index 0000000000000000000000000000000000000000..f1488adf937caeaf3b70a6d43d5fb228e15e1d37 Binary files /dev/null and b/ArkUISample/ScrollableComponent/entry/src/main/ets/res/waterFlow(5).JPG differ diff --git a/ArkUISample/ScrollableComponent/entry/src/main/module.json5 b/ArkUISample/ScrollableComponent/entry/src/main/module.json5 new file mode 100644 index 0000000000000000000000000000000000000000..4144486d1af4c03b0d767cce1cda86fc0d697f91 --- /dev/null +++ b/ArkUISample/ScrollableComponent/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": [ + "action.system.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/ArkUISample/ScrollableComponent/entry/src/main/resources/base/element/color.json b/ArkUISample/ScrollableComponent/entry/src/main/resources/base/element/color.json new file mode 100644 index 0000000000000000000000000000000000000000..3c712962da3c2751c2b9ddb53559afcbd2b54a02 --- /dev/null +++ b/ArkUISample/ScrollableComponent/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/ArkUISample/ScrollableComponent/entry/src/main/resources/base/element/string.json b/ArkUISample/ScrollableComponent/entry/src/main/resources/base/element/string.json new file mode 100644 index 0000000000000000000000000000000000000000..70ae02de85d68365db31274ceac2430cd53d9ff6 --- /dev/null +++ b/ArkUISample/ScrollableComponent/entry/src/main/resources/base/element/string.json @@ -0,0 +1,980 @@ +{ + "string": [ + { + "name": "module_desc", + "value": "module description" + }, + { + "name": "EntryAbility_desc", + "value": "description" + }, + { + "name": "EntryAbility_label", + "value": "ScrollableComponent" + }, + { + "name": "pageIndex_List", + "value": "列表/List" + }, + { + "name": "pageIndex_ArcList", + "value": "弧形列表/ArcList" + }, + { + "name": "pageIndex_Grid", + "value": "网格/Grid" + }, + { + "name": "pageIndex_Swiper", + "value": "轮播/Swiper" + }, + { + "name": "pageIndex_ArcSwiper", + "value": "弧形轮播/ArcSwiper" + }, + { + "name": "pageIndex_Tabs", + "value": "选项卡/Tabs" + }, + { + "name": "GridLayout_title", + "value": "网格开发布局" + }, + { + "name": "GridLayout_titleRowSpacing", + "value": "设置行列数量占比和行间距示例" + }, + { + "name": "GridLayout_titleChildSpan", + "value": "设置子组件所占行列数示例" + }, + { + "name": "GridLayout_titleMainAxis", + "value": "设置主轴方向示例" + }, + { + "name": "GridLayout_description", + "value": "示例设置了网格中子组件行列数量占比、行列间距和主轴方向。" + }, + { + "name": "DataInGrid_title", + "value": "网格显示数据" + }, + { + "name": "DataInGrid_titleOfficeServices", + "value": "办公服务网格示例" + }, + { + "name": "DataInGrid_titleForEach", + "value": "办公服务网格ForEach语句示例" + }, + { + "name": "DataInGrid_description", + "value": "示例采用二维布局的方式组织其内部元素,显示通用办公服务网格。" + }, + { + "name": "ScrollableGrid_title", + "value": "可滚动的网格布局" + }, + { + "name": "ScrollableGrid_titleHorizontal", + "value": "横向可滚动网格布局示例" + }, + { + "name": "ScrollableGrid_description", + "value": "示例通过仅设置行、列数量与占比中的一个实现横向可滚动网格布局。" + }, + { + "name": "ScrollPosition_title", + "value": "控制滚动位置的网格布局" + }, + { + "name": "ScrollPosition_titleExample", + "value": "控制滚动位置示例" + }, + { + "name": "ScrollPosition_description", + "value": "示例通过添加Scroller对象的scrollPage方法,实现滚动网格布局翻页滚动的功能。" + }, + { + "name": "SwiperLoop_title", + "value": "循环播放" + }, + { + "name": "SwiperLoop_titleTrue", + "value": "循环播放loop为true的示例" + }, + { + "name": "SwiperLoop_titleFalse", + "value": "循环播放loop为false的示例" + }, + { + "name": "SwiperLoop_description", + "value": "通过设置loop属性控制是否循环播放。" + }, + { + "name": "SwiperAutoPlay_title", + "value": "自动轮播" + }, + { + "name": "SwiperAutoPlay_titleExample", + "value": "自动轮播示例" + }, + { + "name": "SwiperAutoPlay_description", + "value": "通过设置autoPlay属性控制是否自动轮播子组件。" + }, + { + "name": "SwiperIndicatorStyle_title", + "value": "自定义导航点样式" + }, + { + "name": "SwiperIndicatorStyle_titleDefault", + "value": "默认导航点样式示例" + }, + { + "name": "SwiperIndicatorStyle_titleCustom", + "value": "自定义导航点样式示例" + }, + { + "name": "SwiperIndicatorStyle_titleDefaultArrows", + "value": "默认箭头样式导航点样式示例" + }, + { + "name": "SwiperIndicatorStyle_titleCustomArrows", + "value": "自定义箭头样式导航点样式示例" + }, + { + "name": "SwiperIndicatorStyle_description", + "value": "通过indicator属性和displayArrow属性对导航点样式和导航点箭头样式进行设置。" + }, + { + "name": "SwiperPageSwitchMethod_title", + "value": "页面切换方式" + }, + { + "name": "SwiperPageSwitchMethod_titleHorizontal", + "value": "水平方向上轮播示例" + }, + { + "name": "SwiperPageSwitchMethod_titleVertical", + "value": "垂直方向上轮播示例" + }, + { + "name": "SwiperPageSwitchMethod_description", + "value": "Swiper支持手指滑动、点击导航点和通过控制器三种方式切换页面,示例展示通过控制器切换页面的方法。" + }, + { + "name": "SwiperDirection_title", + "value": "轮播方向" + }, + { + "name": "SwiperDirection_description", + "value": "Swiper支持水平和垂直方向上进行轮播,主要通过vertical属性控制。" + }, + { + "name": "SwiperMultiPage_title", + "value": "每页显示多个子页面" + }, + { + "name": "SwiperMultiPage_titleExample", + "value": "每页显示多个子页面示例" + }, + { + "name": "SwiperMultiPage_description", + "value": "Swiper支持在一个页面内同时显示多个子组件,通过displayCount属性设置。" + }, + { + "name": "SwiperCustomAnimation_title", + "value": "自定义切换动画" + }, + { + "name": "SwiperCustomAnimation_titleExample", + "value": "自定义切换动画示例" + }, + { + "name": "SwiperCustomAnimation_description", + "value": "Swiper支持通过customContentTransition设置自定义切换动画。" + }, + { + "name": "TabsLayout_title", + "value": "基本布局" + }, + { + "name": "TabsLayout_titleExample", + "value": "基本布局示例" + }, + { + "name": "TabsLayout_description", + "value": "示例展示Tabs组件页面组成的两个部分,分别是内容页TabContent和导航页签栏TabBar。" + }, + { + "name": "BottomTabBar_title", + "value": "底部导航" + }, + { + "name": "BottomTabBar_titleExample", + "value": "底部导航示例" + }, + { + "name": "homepage", + "value": "首页" + }, + { + "name": "homepage_content", + "value": "首页的内容" + }, + { + "name": "recommend", + "value": "推荐" + }, + { + "name": "recommend_content", + "value": "推荐的内容" + }, + { + "name": "discover", + "value": "发现" + }, + { + "name": "discover_content", + "value": "发现的内容" + }, + { + "name": "mine", + "value": "我的" + }, + { + "name": "mine_content", + "value": "我的内容" + }, + { + "name": "BottomTabBar_description", + "value": "示例展示导航页签栏TabBar在底部的情景。" + }, + { + "name": "TopTabBar_title", + "value": "顶部导航" + }, + { + "name": "TopTabBar_titleExample", + "value": "顶部导航示例" + }, + { + "name": "TopTabBar_description", + "value": "示例展示导航页签栏TabBar在顶部的情景。" + }, + { + "name": "SideTabBar_title", + "value": "侧边导航" + }, + { + "name": "SideTabBar_titleExample", + "value": "侧边导航示例" + }, + { + "name": "SideTabBar_description", + "value": "示例展示导航页签栏TabBar在侧边的情景。" + }, + { + "name": "SwipeLockedTabBar_title", + "value": "限制导航栏的滑动切换" + }, + { + "name": "SwipeLockedTabBar_titleExample", + "value": "限制导航栏的滑动切换示例" + }, + { + "name": "SwipeLockedTabBar_description", + "value": "示例展示在底部导航+顶部导航组合的情况下,限制底部导航栏滑动的情景。" + }, + { + "name": "FixedTabBar_title", + "value": "固定导航栏" + }, + { + "name": "FixedTabBar_titleExample", + "value": "固定导航栏示例" + }, + { + "name": "FixedTabBar_description", + "value": "示例展示底部导航内容分类一般固定,分类数量一般在3-5个,使用固定导航栏的情景。" + }, + { + "name": "ScrollableTabBar_title", + "value": "滚动导航栏" + }, + { + "name": "ScrollableTabBar_titleExample", + "value": "滚动导航栏示例" + }, + { + "name": "FocusOn_content", + "value": "关注的内容" + }, + { + "name": "game_content", + "value": "游戏的内容" + }, + { + "name": "digit_content", + "value": "数码的内容" + }, + { + "name": "technology_content", + "value": "科技的内容" + }, + { + "name": "sport_content", + "value": "体育的内容" + }, + { + "name": "film_content", + "value": "影视的内容" + }, + { + "name": "humanities_content", + "value": "人文的内容" + }, + { + "name": "FocusOn", + "value": "关注" + }, + { + "name": "game", + "value": "游戏" + }, + { + "name": "digit", + "value": "数码" + }, + { + "name": "technology", + "value": "科技" + }, + { + "name": "sport", + "value": "体育" + }, + { + "name": "film", + "value": "影视" + }, + { + "name": "humanities", + "value": "人文" + }, + { + "name": "ScrollableTabBar_description", + "value": "示例展示内容分类较多,屏幕宽度无法容纳所有分类页签的情况下,需要使用可滚动的导航栏的情景。" + }, + { + "name": "CustomTabBar_title", + "value": "自定义导航栏" + }, + { + "name": "CustomTabBar_titleExample", + "value": "自定义导航栏示例" + }, + { + "name": "internet_content", + "value": "网络的内容" + }, + { + "name": "album_content", + "value": "相册的内容" + }, + { + "name": "video_content", + "value": "视频的内容" + }, + { + "name": "more_content", + "value": "更多的内容" + }, + { + "name": "internet", + "value": "网络" + }, + { + "name": "album", + "value": "相册" + }, + { + "name": "video", + "value": "视频" + }, + { + "name": "more", + "value": "更多" + }, + { + "name": "CustomTabBar_description", + "value": "示例展示通过组合文字以及对应语义图标表示页签内容,自定义导航栏样式的情景。" + }, + { + "name": "ContentWillChange_title", + "value": "切换至指定页签" + }, + { + "name": "ContentWillChange_titleContentAndTabSync", + "value": "内容页和页签联动示例" + }, + { + "name": "ContentWillChange_titleSpecifiedTab", + "value": "切换指定页签示例" + }, + { + "name": "ContentWillChange_titleInterception", + "value": "支持开发者自定义页面切换拦截事件示例" + }, + { + "name": "ContentWillChange_changeIndex", + "value": "动态修改index" + }, + { + "name": "ContentWillChange_description", + "value": "示例展示使用了自定义导航栏后,自行实现页签切换逻辑。" + }, + { + "name": "AgeFriendlyTabs_title", + "value": "支持适老化" + }, + { + "name": "AgeFriendlyTabs_description", + "value": "示例展示在适老化大字体场景下,底部页签提供大字体弹窗显示内容。" + }, + { + "name": "ListLayout_title", + "value": "列表开发布局" + }, + { + "name": "ListLayout_titleMainAxis", + "value": "设置主轴方向布局" + }, + { + "name": "ListLayout_titleCrossAxisLanes", + "value": "设置交叉轴布局lanes属性" + }, + { + "name": "ListLayout_titleCrossAxisAlignment", + "value": "设置交叉轴布局alignListItem属性" + }, + { + "name": "ListLayout_description", + "value": "展示列表主轴和交叉轴布局的各种示例。" + }, + { + "name": "DataInList_title", + "value": "列表显示数据" + }, + { + "name": "DataInList_titlePage", + "value": "在列表中显示数据" + }, + { + "name": "DataInList_titleCityList", + "value": "城市列表示例" + }, + { + "name": "city_beijing", + "value": "北京" + }, + { + "name": "city_hangzhou", + "value": "杭州" + }, + { + "name": "city_shanghai", + "value": "上海" + }, + { + "name": "peopleOne", + "value": "小明" + }, + { + "name": "peopleTwo", + "value": "小红" + }, + { + "name": "DataInList_titleContactsList", + "value": "联系人列表示例" + }, + { + "name": "DataInList_description", + "value": "示例模拟显示城市列表,以及图片和文字一起显示的联系人列表。" + }, + { + "name": "ListIteration_title", + "value": "迭代列表内容" + }, + { + "name": "ListIteration_titleExample", + "value": "迭代列表内容示例" + }, + { + "name": "ListIteration_description", + "value": "示例通过数据集合动态地创建列表。" + }, + { + "name": "CustomListStyle_title", + "value": "自定义列表样式" + }, + { + "name": "CustomListStyle_titleContentSpacing", + "value": "设置内容间距" + }, + { + "name": "CustomListStyle_titleDividerLines", + "value": "添加分隔线" + }, + { + "name": "CustomListStyle_titleScrollbars", + "value": "添加滚动条" + }, + { + "name": "CustomListStyle_description", + "value": "示例通过属性自定义设置列表的内容间距、分隔线、滚动条等样式。" + }, + { + "name": "GroupedList_title", + "value": "支持分组列表" + }, + { + "name": "GroupedList_titleExample", + "value": "支持分组列表示例" + }, + { + "name": "GroupedList_description", + "value": "示例在列表中支持数据分组展示,可以使列表显示结构清晰,查找方便,从而提高使用效率。" + }, + { + "name": "StickyHeaderList_title", + "value": "添加粘性标题" + }, + { + "name": "StickyHeaderList_titleExample", + "value": "添加粘性标题示例" + }, + { + "name": "StickyHeaderList_description", + "value": "粘性标题常用于定位字母列表的头部元素,有助于阐明列表中数据的表示形式和用途,帮助用户进行数据定位。" + }, + { + "name": "ControlledScrollPositionList_title", + "value": "控制滚动位置" + }, + { + "name": "ControlledScrollPositionList_titleExample", + "value": "控制滚动位置示例" + }, + { + "name": "ControlledScrollPositionList_description", + "value": "当列表中新闻页列表项数量庞大时,可以快速滚动到列表底部或返回列表顶部。" + }, + { + "name": "ResponsiveScrollPositionList_title", + "value": "响应滚动位置" + }, + { + "name": "ResponsiveScrollPositionList_titleExample", + "value": "响应滚动位置示例" + }, + { + "name": "contacts_A_one", + "value": "艾佳" + }, + { + "name": "contacts_A_two", + "value": "安安" + }, + { + "name": "contacts_B_one", + "value": "白叶" + }, + { + "name": "contacts_B_two", + "value": "伯伯" + }, + { + "name": "contacts_B_three", + "value": "伯明" + }, + { + "name": "contacts_D_one", + "value": "大白" + }, + { + "name": "contacts_D_two", + "value": "大伯" + }, + { + "name": "contacts_D_three", + "value": "大明" + }, + { + "name": "contacts_F_one", + "value": "帆帆" + }, + { + "name": "contacts_F_two", + "value": "芳芳" + }, + { + "name": "contacts_G_one", + "value": "刚刚" + }, + { + "name": "contacts_G_two", + "value": "哥哥" + }, + { + "name": "contacts_H_one", + "value": "花花" + }, + { + "name": "contacts_H_two", + "value": "华华" + }, + { + "name": "contacts_H_three", + "value": "欢欢" + }, + { + "name": "contacts_X_one", + "value": "小李" + }, + { + "name": "contacts_X_two", + "value": "小王" + }, + { + "name": "contacts_X_three", + "value": "小张" + }, + { + "name": "ResponsiveScrollPositionList_description", + "value": "在联系人列表滚动时,如果跨越了不同字母开头的分组,则侧边字母索引栏也需要更新到对应的字母位置。" + }, + { + "name": "SwipeListItem_title", + "value": "响应列表项侧滑" + }, + { + "name": "SwipeListItem_titleExample", + "value": "响应列表项侧滑示例" + }, + { + "name": "SwipeListItem_description", + "value": "在消息列表中,给消息列表提供侧滑删除功能。" + }, + { + "name": "TaggedListItems_title", + "value": "给列表项添加标记" + }, + { + "name": "TaggedListItems_titleExample", + "value": "给列表项添加标记示例" + }, + { + "name": "TaggedListItems_description", + "value": "在消息列表中,给消息信息右上角添加标记。" + }, + { + "name": "AddListItem_title", + "value": "新增列表项" + }, + { + "name": "AddListItem_titleExample", + "value": "新增列表项示例" + }, + { + "name": "TodoItem", + "value": "待办" + }, + { + "name": "AddListItem_description", + "value": "在示例中击添加按钮,列表项内容选择或填写的交互界面,用户点击确定后,列表中新增对应的项目。" + }, + { + "name": "DeleteListItem_title", + "value": "删除列表项" + }, + { + "name": "DeleteListItem_titleExample", + "value": "删除列表项示例" + }, + { + "name": "DeleteListItem_description", + "value": "在示例中用户长按列表项进入删除模式,提供用户删除列表项选择的交互界面,勾选完成后点击删除按钮,列表中删除对应的项目。" + }, + { + "name": "pageIndex_WaterFlow", + "value": "创建瀑布流/WaterFlow" + }, + { + "name": "WaterFlowInfiniteScrolling_title", + "value": "无限滚动(到达末尾时新增数据)" + }, + { + "name": "WaterFlowInfiniteScrolling_description", + "value": "在瀑布流组件到达末尾位置时触发事件回调,增加新数据。" + }, + { + "name": "WaterFlowInfiniteScrollingEarly_title", + "value": "无限滚动(提前新增数据)" + }, + { + "name": "WaterFlowInfiniteScrollingEarly_description", + "value": "为了实现更加流畅的无限滑动,需要调整增加新数据的时机。可以在还剩余若干个数据未遍历的情况下提前加载新数据。" + }, + { + "name": "WaterFlowGroupingMixing_title", + "value": "分组混合布局" + }, + { + "name": "WaterFlowGroupingMixing_description", + "value": "许多应用界面在瀑布流上方包含其他内容,这类场景可通过在Scroll或List内部嵌套WaterFlow来实现。" + }, + { + "name": "WaterFlowDynamicSwitchover_title", + "value": "动态切换列数" + }, + { + "name": "WaterFlowDynamicSwitchover_description", + "value": "通过动态调整瀑布流的列数,应用能够实现在列表模式与瀑布流模式间的切换,或适应屏幕宽度的变化。" + }, + { + "name": "GridSideToSide_title", + "value": "控制滚动位置" + }, + { + "name": "GridSideToSide_description", + "value": "与新闻列表的返回顶部场景类似,控制滚动位置功能在网格布局中也很常用,例如下图所示日历的翻页功能。" + }, + { + "name": "GridScrollbar_title", + "value": "添加外置滚动条" + }, + { + "name": "GridScrollbar_description", + "value": "网格组件Grid可与ScrollBar组件配合使用,为网格添加外置滚动条。" + }, + { + "name": "ArcSwiperHorizontal_title", + "value": "水平方向轮播" + }, + { + "name": "ArcSwiperHorizontal_description", + "value": "设置水平方向上轮播。" + }, + { + "name": "ArcSwiperVertical_title", + "value": "垂直方向轮播" + }, + { + "name": "ArcSwiperVertical_description", + "value": "设置垂直方向轮播,导航点设为3点钟方向。。" + }, + { + "name": "ArcSwiperAction_title", + "value": "自定义切换动画" + }, + { + "name": "ArcSwiperAction_description", + "value": "ArcSwiper支持设置自定义切换动画,可以在回调中对视窗内所有页面逐帧设置透明度、缩放比例、位移、渲染层级等属性,从而实现自定义切换动画效果。" + }, + { + "name": "ArcSwiperSideSlip_title", + "value": "实现侧滑返回" + }, + { + "name": "ArcSwiperSideSlip_description", + "value": "ArcSwiper的滑动事件会与侧滑返回冲突,可以通过手势拦截去判断ArcSwiper是否滑动到开头去拦截ArcSwiper的滑动手势,实现再次左滑返回上一页的功能。" + }, + { + "name": "ArcSwiperStyles_title", + "value": "设置导航点样式" + }, + { + "name": "ArcSwiperStyles_titleDefault", + "value": "导航点使用默认样式" + }, + { + "name": "ArcSwiperStyles_titleCustomize", + "value": "自定义导航点样式" + }, + { + "name": "ArcSwiperStyles_description", + "value": "ArcSwiper提供了默认的弧形导航点样式,导航点默认显示在ArcSwiper下方居中位置,开发者也可以通过indicator属性自定义弧形导航点的样式。" + }, + { + "name": "ArcSwiperToggle_title", + "value": "控制页面切换方式" + }, + { + "name": "ArcSwiperToggle_description", + "value": "以下示例展示通过控制控制器和旋转表冠翻页的方法。" + }, + { + "name": "ArcListAcrScrollBar_title", + "value": "添加外置滚动条ArcScrollBar" + }, + { + "name": "ArcListAcrScrollBar_description", + "value": "弧形列表ArcList可与ArcScrollBar组件配合使用,为弧形列表添加外置滚动条。" + }, + { + "name": "ArcListArcIndexerBar_title", + "value": "与弧形索引条ArcAlphabetIndexer联动" + }, + { + "name": "ArcListArcIndexerBar_description", + "value": "许多应用需要监测列表的滚动位置变动并作出响应,或通过调整滚动位置实现列表的快速定位。为此,需使用弧形索引条组件ArcAlphabetIndexer。" + }, + { + "name": "arcListBuiltInScrollerBar_title", + "value": "添加内置滚动条" + }, + { + "name": "arcListBuiltInScrollerBar_description", + "value": "当列表项的高度超过屏幕高度时,弧形列表能够沿垂直方向滚动。" + }, + { + "name": "ArcListContents_title", + "value": "迭代弧形列表内容" + }, + { + "name": "ArcListContents_description", + "value": "通常,应用会通过数据集合动态创建列表。采用循环渲染的方式,可以从数据源中迭代获取数据,在每次迭代过程中创建相应的组件,从而降低代码的复杂度。" + }, + { + "name": "ArcListCrown_title", + "value": "响应旋转表冠" + }, + { + "name": "ArcListCrown_description", + "value": "手表设备上弧形列表在获焦的情况下可对旋转表冠做出响应,用户可通过旋转表冠的操作滑动列表,浏览列表项数据。" + }, + { + "name": "ArcListShow_title", + "value": "在弧形列表中显示数据" + }, + { + "name": "ArcListShow_description", + "value": "弧形列表视图垂直展示项目集合,当列表项超出屏幕范围时,提供滚动功能,这使得它非常适合展示大型数据集合。" + }, + { + "name": "ArcListSideSlip_title", + "value": "响应列表项侧滑" + }, + { + "name": "ArcListSideSlip_description", + "value": "ArcListItem的swipeAction属性可用于实现列表项的左右滑动功能。" + }, + { + "name": "ArcListStyles_head", + "value": "自定义弧形列表标题" + }, + { + "name": "ArcListStyles_title", + "value": "自定义弧形列表样式" + }, + { + "name": "ArcListStyles_titleSpacing", + "value": "自定义弧形列表项间距" + }, + { + "name": "ArcListStyles_titleScale", + "value": "列表项关闭自动缩放" + }, + { + "name": "ArcListStyles_description", + "value": "以下示例展示自定义弧形列表样式的方法。" + }, + { + "name": "LongList_title", + "value": "长列表的处理" + }, + { + "name": "LongList_description", + "value": "循环渲染适用于短列表,当构建具有大量列表项的长列表时,如果直接采用循环渲染方式,会一次性加载所有的列表元素,会导致页面启动时间过长,影响用户体验。因此,推荐使用数据懒加载(LazyForEach)方式实现按需迭代加载数据,从而提升列表性能。" + }, + { + "name": "CollapseAndExpand_title", + "value": "折叠与展开" + }, + { + "name": "CollapseAndExpand_description", + "value": "列表项的折叠与展开用途广泛,常用于信息清单的展示、填写等应用场景。" + }, + { + "name": "SwiperAndTabsLinkage_title", + "value": "Swiper与Tabs联动" + }, + { + "name": "SwiperAndTabsLinkage_description", + "value": "Swiper选中的元素改变时,会通过onSelected回调事件,将元素的索引值index返回。通过调用tabsController.changeIndex(index)方法来实现Tabs页签的切换。" + }, + { + "name": "SwiperIgnoreComponentSize_title", + "value": "设置圆点导航点间距和忽略导航点组件大小" + }, + { + "name": "SwiperIgnoreComponentSize_description", + "value": "针对圆点导航点,可以通过DotIndicator的space属性来设置圆点导航点的间距。当导航点的bottom设为0之后,导航点的底部与Swiper的底部还会有一定间距。如果希望消除该间距,可通过调用bottom(bottom, ignoreSize)属性来进行设置。" + }, + { + "name": "ArcLongList_title", + "value": "处理长列表" + }, + { + "name": "ArcLongList_description", + "value": "循环渲染适用于短列表,当构建具有大量列表项的长列表时,如果直接采用循环渲染方式,会一次性加载所有的列表元素,会导致页面启动时间过长,影响用户体验。因此,推荐使用数据懒加载(LazyForEach)方式实现按需迭代加载数据,从而提升列表性能。" + }, + { + "name": "ListChatRoom_title", + "value": "切换布局方向" + }, + { + "name": "ListChatRoom_description", + "value": "部分业务场景需要列表底部插入数据时,自动向上滚动,把新插入的节点展示出来。" + }, + { + "name": "LongGrid_title", + "value": "性能优化" + }, + { + "name": "LongGrid_description", + "value": "与长列表的处理类似,循环渲染适用于数据量较小的布局场景,当构建具有大量网格项的可滚动网格布局时,推荐使用数据懒加载方式实现按需迭代加载数据,从而提升列表性能。" + }, + { + "name": "ArcListCrown_set", + "value": "设置" + }, + { + "name": "ArcListStyles_waln", + "value": "WLAN" + }, + { + "name": "ArcListStyles_open", + "value": "已开启" + }, + { + "name": "ArcListStyles_blue", + "value": "蓝牙" + }, + { + "name": "ArcListStyles_net", + "value": "移动网络" + }, + { + "name": "ArcListStyles_connect", + "value": "更多连接" + }, + { + "name": "ArcListStyles_light", + "value": "显示和亮度" + } + ] +} \ No newline at end of file diff --git a/ArkUISample/ScrollableComponent/entry/src/main/resources/base/media/MaterialSymbolsDelete.svg b/ArkUISample/ScrollableComponent/entry/src/main/resources/base/media/MaterialSymbolsDelete.svg new file mode 100644 index 0000000000000000000000000000000000000000..8f8348613dafc3fb1a1adbaa0f978bd3e9398fd7 --- /dev/null +++ b/ArkUISample/ScrollableComponent/entry/src/main/resources/base/media/MaterialSymbolsDelete.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/ArkUISample/ScrollableComponent/entry/src/main/resources/base/media/background.png b/ArkUISample/ScrollableComponent/entry/src/main/resources/base/media/background.png new file mode 100644 index 0000000000000000000000000000000000000000..923f2b3f27e915d6871871deea0420eb45ce102f Binary files /dev/null and b/ArkUISample/ScrollableComponent/entry/src/main/resources/base/media/background.png differ diff --git a/ArkUISample/ScrollableComponent/entry/src/main/resources/base/media/blueTooth.svg b/ArkUISample/ScrollableComponent/entry/src/main/resources/base/media/blueTooth.svg new file mode 100644 index 0000000000000000000000000000000000000000..0fbcf2bd2720f8bc33ce34552ff07b0238523088 --- /dev/null +++ b/ArkUISample/ScrollableComponent/entry/src/main/resources/base/media/blueTooth.svg @@ -0,0 +1,16 @@ + + + 编组 + + + + + + + + + + + + + \ No newline at end of file diff --git a/ArkUISample/ScrollableComponent/entry/src/main/resources/base/media/delete.png b/ArkUISample/ScrollableComponent/entry/src/main/resources/base/media/delete.png new file mode 100644 index 0000000000000000000000000000000000000000..1714478bde5bd46fa9856e0ebc06be459c4664f2 Binary files /dev/null and b/ArkUISample/ScrollableComponent/entry/src/main/resources/base/media/delete.png differ diff --git a/ArkUISample/ScrollableComponent/entry/src/main/resources/base/media/displayAndBrightness.svg b/ArkUISample/ScrollableComponent/entry/src/main/resources/base/media/displayAndBrightness.svg new file mode 100644 index 0000000000000000000000000000000000000000..c19e018d71201ed17e239da5851bde5a9cfaf12a --- /dev/null +++ b/ArkUISample/ScrollableComponent/entry/src/main/resources/base/media/displayAndBrightness.svg @@ -0,0 +1,16 @@ + + + 编组 + + + + + + + + + + + + + \ No newline at end of file diff --git a/ArkUISample/ScrollableComponent/entry/src/main/resources/base/media/foreground.png b/ArkUISample/ScrollableComponent/entry/src/main/resources/base/media/foreground.png new file mode 100644 index 0000000000000000000000000000000000000000..97014d3e10e5ff511409c378cd4255713aecd85f Binary files /dev/null and b/ArkUISample/ScrollableComponent/entry/src/main/resources/base/media/foreground.png differ diff --git a/ArkUISample/ScrollableComponent/entry/src/main/resources/base/media/ic_contact.svg b/ArkUISample/ScrollableComponent/entry/src/main/resources/base/media/ic_contact.svg new file mode 100644 index 0000000000000000000000000000000000000000..45128f1a45c7f70b96217f8a840eb6ca922f5e56 --- /dev/null +++ b/ArkUISample/ScrollableComponent/entry/src/main/resources/base/media/ic_contact.svg @@ -0,0 +1,21 @@ + + + 默认头像icon + + + + + + + + + + \ No newline at end of file diff --git a/ArkUISample/ScrollableComponent/entry/src/main/resources/base/media/ic_settings_arrow.svg b/ArkUISample/ScrollableComponent/entry/src/main/resources/base/media/ic_settings_arrow.svg new file mode 100644 index 0000000000000000000000000000000000000000..ff6293ce432d79ed6c50d61d430ee79fe2e2dad2 --- /dev/null +++ b/ArkUISample/ScrollableComponent/entry/src/main/resources/base/media/ic_settings_arrow.svg @@ -0,0 +1,28 @@ + + + + + + + + + + + + + + + + + diff --git a/ArkUISample/ScrollableComponent/entry/src/main/resources/base/media/ic_settings_more_connections.svg b/ArkUISample/ScrollableComponent/entry/src/main/resources/base/media/ic_settings_more_connections.svg new file mode 100644 index 0000000000000000000000000000000000000000..7e654cf2401d3f4c5db1c971fcefb28af119ef2a --- /dev/null +++ b/ArkUISample/ScrollableComponent/entry/src/main/resources/base/media/ic_settings_more_connections.svg @@ -0,0 +1,21 @@ + + + 更多连接 + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/ArkUISample/ScrollableComponent/entry/src/main/resources/base/media/ic_settings_wifi.svg b/ArkUISample/ScrollableComponent/entry/src/main/resources/base/media/ic_settings_wifi.svg new file mode 100644 index 0000000000000000000000000000000000000000..53dadba1d2dac8ca8b98697705edb004874404c5 --- /dev/null +++ b/ArkUISample/ScrollableComponent/entry/src/main/resources/base/media/ic_settings_wifi.svg @@ -0,0 +1,11 @@ + + + Artboard + + + + + + + + \ No newline at end of file diff --git a/ArkUISample/ScrollableComponent/entry/src/main/resources/base/media/layered_image.json b/ArkUISample/ScrollableComponent/entry/src/main/resources/base/media/layered_image.json new file mode 100644 index 0000000000000000000000000000000000000000..fb49920440fb4d246c82f9ada275e26123a2136a --- /dev/null +++ b/ArkUISample/ScrollableComponent/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/ArkUISample/ScrollableComponent/entry/src/main/resources/base/media/mobileData.svg b/ArkUISample/ScrollableComponent/entry/src/main/resources/base/media/mobileData.svg new file mode 100644 index 0000000000000000000000000000000000000000..3af781748dbcef004e85fc31d92da3175b21c6c1 --- /dev/null +++ b/ArkUISample/ScrollableComponent/entry/src/main/resources/base/media/mobileData.svg @@ -0,0 +1,19 @@ + + + 编组 10 + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/ArkUISample/ScrollableComponent/entry/src/main/resources/base/media/startIcon.png b/ArkUISample/ScrollableComponent/entry/src/main/resources/base/media/startIcon.png new file mode 100644 index 0000000000000000000000000000000000000000..205ad8b5a8a42e8762fbe4899b8e5e31ce822b8b Binary files /dev/null and b/ArkUISample/ScrollableComponent/entry/src/main/resources/base/media/startIcon.png differ diff --git a/ArkUISample/ScrollableComponent/entry/src/main/resources/base/media/wlan.svg b/ArkUISample/ScrollableComponent/entry/src/main/resources/base/media/wlan.svg new file mode 100644 index 0000000000000000000000000000000000000000..be12071bad8d8780bf172fb777cc7bf5c76e5a57 --- /dev/null +++ b/ArkUISample/ScrollableComponent/entry/src/main/resources/base/media/wlan.svg @@ -0,0 +1,16 @@ + + + 编组 17 + + + + + + + + + + + + + \ No newline at end of file diff --git a/ArkUISample/ScrollableComponent/entry/src/main/resources/base/profile/backup_config.json b/ArkUISample/ScrollableComponent/entry/src/main/resources/base/profile/backup_config.json new file mode 100644 index 0000000000000000000000000000000000000000..78f40ae7c494d71e2482278f359ec790ca73471a --- /dev/null +++ b/ArkUISample/ScrollableComponent/entry/src/main/resources/base/profile/backup_config.json @@ -0,0 +1,3 @@ +{ + "allowToBackupRestore": true +} \ No newline at end of file diff --git a/ArkUISample/ScrollableComponent/entry/src/main/resources/base/profile/main_pages.json b/ArkUISample/ScrollableComponent/entry/src/main/resources/base/profile/main_pages.json new file mode 100644 index 0000000000000000000000000000000000000000..1898d94f58d6128ab712be2c68acc7c98e9ab9ce --- /dev/null +++ b/ArkUISample/ScrollableComponent/entry/src/main/resources/base/profile/main_pages.json @@ -0,0 +1,5 @@ +{ + "src": [ + "pages/Index" + ] +} diff --git a/ArkUISample/ScrollableComponent/entry/src/main/resources/dark/element/color.json b/ArkUISample/ScrollableComponent/entry/src/main/resources/dark/element/color.json new file mode 100644 index 0000000000000000000000000000000000000000..79b11c2747aec33e710fd3a7b2b3c94dd9965499 --- /dev/null +++ b/ArkUISample/ScrollableComponent/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/ArkUISample/ScrollableComponent/entry/src/mock/mock-config.json5 b/ArkUISample/ScrollableComponent/entry/src/mock/mock-config.json5 new file mode 100644 index 0000000000000000000000000000000000000000..b9a78e201535765168a92d3543c690273ecdc019 --- /dev/null +++ b/ArkUISample/ScrollableComponent/entry/src/mock/mock-config.json5 @@ -0,0 +1,17 @@ +/* + * Copyright (c) 2025 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +{ +} \ No newline at end of file diff --git a/ArkUISample/ScrollableComponent/entry/src/ohosTest/ets/test/Ability.test.ets b/ArkUISample/ScrollableComponent/entry/src/ohosTest/ets/test/Ability.test.ets new file mode 100644 index 0000000000000000000000000000000000000000..0f8ce9a2c012f8fe36114cef65216ef0b6254f41 --- /dev/null +++ b/ArkUISample/ScrollableComponent/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/ArkUISample/ScrollableComponent/entry/src/ohosTest/ets/test/List.test.ets b/ArkUISample/ScrollableComponent/entry/src/ohosTest/ets/test/List.test.ets new file mode 100644 index 0000000000000000000000000000000000000000..7c16bc08c6fb53175fcdc9d628a4d6a9b34bef4c --- /dev/null +++ b/ArkUISample/ScrollableComponent/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/ArkUISample/ScrollableComponent/entry/src/ohosTest/ets/test/index.test.ets b/ArkUISample/ScrollableComponent/entry/src/ohosTest/ets/test/index.test.ets new file mode 100644 index 0000000000000000000000000000000000000000..30b111830deafd1cbbb852db21fa483d02371daa --- /dev/null +++ b/ArkUISample/ScrollableComponent/entry/src/ohosTest/ets/test/index.test.ets @@ -0,0 +1,1324 @@ +/* + * Copyright (c) 2025 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { describe, it, expect, beforeAll } from '@ohos/hypium'; +// 导入测试依赖kit +import { abilityDelegatorRegistry, Driver, ON, MouseButton,MatchPattern, UiDirection } from '@kit.TestKit'; +import { UIAbility, Want } from '@kit.AbilityKit'; +import { Point } from '@ohos.UiTest'; + + +const delegator: abilityDelegatorRegistry.AbilityDelegator = abilityDelegatorRegistry.getAbilityDelegator(); +const bundleName = abilityDelegatorRegistry.getArguments().bundleName; +let abilityDelegator: abilityDelegatorRegistry.AbilityDelegator = abilityDelegatorRegistry.getAbilityDelegator(); +let want: Want; + +async function getResourceString(resource: Resource): Promise { + let manage = abilityDelegator.getAppContext().resourceManager; + let textString: string = await manage.getStringValue(resource); + return textString; +} + +export default function IndexTest() { + describe('IndexTest', () => { + beforeAll(async () => { + want = { + bundleName: bundleName, + abilityName: 'EntryAbility' + }; + await delegator.startAbility(want); + let driver = Driver.create(); + await driver.delayMs(1000); + const ability: UIAbility = await delegator.getCurrentTopAbility(); + console.info('get top ability'); + expect(ability.context.abilityInfo.name).assertEqual('EntryAbility'); + }) + + /** + * @tc.number UiTest_001 + * @tc.name testControlledScrollPositionList + * @tc.desc 测试控制滚动位置示例 + */ + it('testControlledScrollPositionList', 0, async (done: Function) => { + console.info('uitest: testControlledScrollPositionList begin'); + let driver = Driver.create(); + let componentButton = await driver.findComponent(ON.text('List', MatchPattern.CONTAINS)); + expect(componentButton === null).assertFalse(); + await componentButton.click(); + let str = await getResourceString($r('app.string.ControlledScrollPositionList_title')); + let sampleButton = await driver.findComponent(ON.text(str, MatchPattern.CONTAINS)); + expect(sampleButton === null).assertFalse(); + await sampleButton.click(); + + let stackList = await driver.findComponent(ON.type('Stack')); + expect(stackList === null).assertFalse(); + let button = await driver.findComponent(ON.type('Button')); + expect(button === null).assertFalse(); + await stackList.scrollToBottom(2400); + await button.click(); + await driver.pressBack(); + await driver.pressBack(); + console.info('uitest: testControlledScrollPositionList end'); + done(); + }) + + /** + * @tc.number UiTest_002 + * @tc.name testResponsiveScrollPositionList + * @tc.desc 测试响应滚动位置示例 + */ + it('testResponsiveScrollPositionList', 0, async (done: Function) => { + console.info('uitest: testResponsiveScrollPositionList begin'); + let driver = Driver.create(); + let componentButton = await driver.findComponent(ON.text('List', MatchPattern.CONTAINS)); + expect(componentButton === null).assertFalse(); + await componentButton.click(); + let str = await getResourceString($r('app.string.ResponsiveScrollPositionList_title')); + let sampleButton = await driver.findComponent(ON.text(str, MatchPattern.CONTAINS)); + expect(sampleButton === null).assertFalse(); + await sampleButton.click(); + + let stackList = await driver.findComponent(ON.type('Stack')); + expect(stackList === null).assertFalse(); + await stackList.scrollToBottom(2400); + await driver.pressBack(); + await driver.pressBack(); + console.info('uitest: testResponsiveScrollPositionList end'); + done(); + }) + + /** + * @tc.number UiTest_003 + * @tc.name testDataInList + * @tc.desc 测试列表显示数据示例 + */ + it('testDataInList', 0, async (done: Function) => { + console.info('uitest: testDataInList begin'); + let driver = Driver.create(); + let componentButton = await driver.findComponent(ON.text('List', MatchPattern.CONTAINS)); + expect(componentButton === null).assertFalse(); + await componentButton.click(); + let str = await getResourceString($r('app.string.DataInList_title')); + let sampleButton = await driver.findComponent(ON.text(str, MatchPattern.CONTAINS)); + expect(sampleButton === null).assertFalse(); + await sampleButton.click(); + + str = await getResourceString($r('app.string.peopleOne')); + let dataListText = await driver.findComponent(ON.text(str, MatchPattern.CONTAINS)); + expect(dataListText === null).assertFalse(); + await driver.pressBack(); + await driver.pressBack(); + console.info('uitest: testDataInList end'); + done(); + }) + + /** + * @tc.number UiTest_004 + * @tc.name testStickyHeaderList + * @tc.desc 测试添加粘性标题示例 + */ + it('testStickyHeaderList', 0, async (done: Function) => { + console.info('uitest: testStickyHeaderList begin'); + let driver = Driver.create(); + let componentButton = await driver.findComponent(ON.text('List', MatchPattern.CONTAINS)); + expect(componentButton === null).assertFalse(); + await componentButton.click(); + let str = await getResourceString($r('app.string.StickyHeaderList_title')); + let sampleButton = await driver.findComponent(ON.text(str, MatchPattern.CONTAINS)); + expect(sampleButton === null).assertFalse(); + await sampleButton.click(); + + let stickyList = await driver.findComponent(ON.type('List')); + expect(stickyList === null).assertFalse(); + await stickyList.scrollToBottom(); + await driver.pressBack(); + await driver.pressBack(); + console.info('uitest: testStickyHeaderList end'); + done(); + }) + + /** + * @tc.number UiTest_005 + * @tc.name testAddListItem + * @tc.desc 测试新增列表项示例 + */ + it('testAddListItem', 0, async (done: Function) => { + console.info('uitest: testAddListItem begin'); + let driver = Driver.create(); + let componentButton = await driver.findComponent(ON.text('List', MatchPattern.CONTAINS)); + expect(componentButton === null).assertFalse(); + await componentButton.click(); + let scrollPoint:Point = {x:400,y:400}; + await driver.mouseScroll(scrollPoint,true,17); + let str = await getResourceString($r('app.string.AddListItem_title')); + let sampleButton = await driver.findComponent(ON.text(str, MatchPattern.CONTAINS)); + expect(sampleButton === null).assertFalse(); + await sampleButton.click(); + + let addButton = await driver.findComponent(ON.text('+', MatchPattern.CONTAINS)); + expect(addButton === null).assertFalse(); + await addButton.click(); + await driver.mouseClick({x: 580, y: 770}, MouseButton.MOUSE_BUTTON_LEFT, 0, 0); + await driver.pressBack(); + await driver.pressBack(); + console.info('uitest: testAddListItem end'); + done(); + }) + + /** + * @tc.number UiTest_006 + * @tc.name testDeleteListItem + * @tc.desc 测试删除列表项示例 + */ + it('testDeleteListItem', 0, async (done: Function) => { + console.info('uitest: testDeleteListItem begin'); + let driver = Driver.create(); + let componentButton = await driver.findComponent(ON.text('List', MatchPattern.CONTAINS)); + expect(componentButton === null).assertFalse(); + await componentButton.click(); + let scrollPoint:Point = {x:400,y:400}; + await driver.mouseScroll(scrollPoint,true,17); + let str = await getResourceString($r('app.string.DeleteListItem_title')); + let sampleButton = await driver.findComponent(ON.text(str, MatchPattern.CONTAINS)); + expect(sampleButton === null).assertFalse(); + await sampleButton.click(); + + let addButton = await driver.findComponent(ON.text('+', MatchPattern.CONTAINS)); + expect(addButton === null).assertFalse(); + await addButton.click(); + await driver.mouseClick({x: 580, y: 770}, MouseButton.MOUSE_BUTTON_LEFT, 0, 0); + let listContent = await driver.findComponent(ON.text('Reading', MatchPattern.CONTAINS)); + expect(listContent === null).assertFalse(); + await listContent.longClick(); + let deleteButton = await driver.findComponent(ON.text('delete', MatchPattern.CONTAINS)); + expect(deleteButton === null).assertFalse(); + await deleteButton.click(); + await driver.pressBack(); + await driver.pressBack(); + console.info('uitest: testDeleteListItem end'); + done(); + }) + + /** + * @tc.number UiTest_007 + * @tc.name testListLayout + * @tc.desc 测试列表开发布局示例 + */ + it('testListLayout', 0, async (done: Function) => { + console.info('uitest: testListLayout begin'); + let driver = Driver.create(); + let componentButton = await driver.findComponent(ON.text('List', MatchPattern.CONTAINS)); + expect(componentButton === null).assertFalse(); + await componentButton.click(); + let str = await getResourceString($r('app.string.ListLayout_title')); + let sampleButton = await driver.findComponent(ON.text(str, MatchPattern.CONTAINS)); + expect(sampleButton === null).assertFalse(); + await sampleButton.click(); + + let dataListText = await driver.findComponent(ON.text('ListItem one', MatchPattern.CONTAINS)); + expect(dataListText === null).assertFalse(); + await driver.pressBack(); + await driver.pressBack(); + console.info('uitest: testListLayout end'); + done(); + }) + + /** + * @tc.number UiTest_008 + * @tc.name testGridScrollPosition + * @tc.desc 测试控制滚动位置的网格布局示例 + */ + it('testGridScrollPosition', 0, async (done: Function) => { + console.info('uitest: testGridScrollPosition begin'); + let driver = Driver.create(); + let componentButton = await driver.findComponent(ON.text('Grid', MatchPattern.CONTAINS)); + expect(componentButton === null).assertFalse(); + await componentButton.click(); + let str = await getResourceString($r('app.string.ScrollPosition_title')); + let sampleButton = await driver.findComponent(ON.text(str, MatchPattern.CONTAINS)); + expect(sampleButton === null).assertFalse(); + await sampleButton.click(); + + let buttonPrevious = await driver.findComponent(ON.text('Previous', MatchPattern.CONTAINS)); + let buttonNext = await driver.findComponent(ON.text('Next', MatchPattern.CONTAINS)); + expect(buttonPrevious === null).assertFalse(); + expect(buttonNext === null).assertFalse(); + await buttonNext.click(); + await buttonPrevious.click(); + await driver.pressBack(); + await driver.pressBack(); + console.info('uitest: testGridScrollPosition end'); + done(); + }) + + /** + * @tc.number UiTest_009 + * @tc.name testGridScrollableGrid + * @tc.desc 测试可滚动的网格布局示例 + */ + it('testGridScrollableGrid', 0, async (done: Function) => { + console.info('uitest: testGridScrollableGrid begin'); + let driver = Driver.create(); + let componentButton = await driver.findComponent(ON.text('Grid', MatchPattern.CONTAINS)); + expect(componentButton === null).assertFalse(); + await componentButton.click(); + let str = await getResourceString($r('app.string.ScrollableGrid_title')); + let sampleButton = await driver.findComponent(ON.text(str, MatchPattern.CONTAINS)); + expect(sampleButton === null).assertFalse(); + await sampleButton.click(); + + let scrollableGrid = await driver.findComponent(ON.type('Grid')); + expect(scrollableGrid === null).assertFalse(); + await scrollableGrid.scrollToBottom(); + await driver.pressBack(); + await driver.pressBack(); + console.info('uitest: testGridScrollableGrid end'); + done(); + }) + + /** + * @tc.number UiTest_010 + * @tc.name testSwiperAutoPlay + * @tc.desc 测试自动轮播示例 + */ + it('testSwiperAutoPlay', 0, async (done: Function) => { + console.info('uitest: testSwiperAutoPlay begin'); + let driver = Driver.create(); + let componentButton = await driver.findComponent(ON.text('Swiper', MatchPattern.CONTAINS)); + expect(componentButton === null).assertFalse(); + await componentButton.click(); + let str = await getResourceString($r('app.string.SwiperAutoPlay_title')); + let sampleButton = await driver.findComponent(ON.text(str, MatchPattern.CONTAINS)); + expect(sampleButton === null).assertFalse(); + await sampleButton.click(); + + let swiper = await driver.findComponent(ON.type('Swiper')); + expect(swiper === null).assertFalse(); + let scrollPoint:Point = {x:400,y:400}; + await driver.mouseScroll(scrollPoint,true,2); + await driver.pressBack(); + await driver.pressBack(); + console.info('uitest: testSwiperAutoPlay end'); + done(); + }) + + /** + * @tc.number UiTest_011 + * @tc.name testSwiperDirection + * @tc.desc 测试轮播方向示例 + */ + it('testSwiperDirection', 0, async (done: Function) => { + console.info('uitest: testSwiperCustomAnimation begin'); + let driver = Driver.create(); + let componentButton = await driver.findComponent(ON.text('Swiper', MatchPattern.CONTAINS)); + expect(componentButton === null).assertFalse(); + await componentButton.click(); + let str = await getResourceString($r('app.string.SwiperDirection_title')); + let sampleButton = await driver.findComponent(ON.text(str, MatchPattern.CONTAINS)); + expect(sampleButton === null).assertFalse(); + await sampleButton.click(); + + let swiper = await driver.findComponent(ON.type('Swiper')); + expect(swiper === null).assertFalse(); + let scrollPoint:Point = {x:400,y:400}; + let scrollPoint2:Point = {x:400,y:800}; + await driver.mouseScroll(scrollPoint,true,2); + await driver.mouseScroll(scrollPoint2,true,2); + await driver.pressBack(); + await driver.pressBack(); + console.info('uitest: testSwiperCustomAnimation end'); + done(); + }) + + /** + * @tc.number UiTest_012 + * @tc.name testSwiperMultiPage + * @tc.desc 测试每页显示多个子页面示例 + */ + it('testSwiperMultiPage', 0, async (done: Function) => { + console.info('uitest: testSwiperMultiPage begin'); + let driver = Driver.create(); + let componentButton = await driver.findComponent(ON.text('Swiper', MatchPattern.CONTAINS)); + expect(componentButton === null).assertFalse(); + await componentButton.click(); + let str = await getResourceString($r('app.string.SwiperMultiPage_title')); + let sampleButton = await driver.findComponent(ON.text(str, MatchPattern.CONTAINS)); + expect(sampleButton === null).assertFalse(); + await sampleButton.click(); + + let swiper = await driver.findComponent(ON.type('Swiper')); + expect(swiper === null).assertFalse(); + let scrollPoint:Point = {x:400,y:400}; + await driver.mouseScroll(scrollPoint,true,2); + await driver.pressBack(); + await driver.pressBack(); + console.info('uitest: testSwiperMultiPage end'); + done(); + }) + + /** + * @tc.number UiTest_013 + * @tc.name testSwiperCustomAnimation + * @tc.desc 测试自定义切换动画示例 + */ + it('testSwiperCustomAnimation', 0, async (done: Function) => { + console.info('uitest: testSwiperCustomAnimation begin'); + let driver = Driver.create(); + let componentButton = await driver.findComponent(ON.text('Swiper', MatchPattern.CONTAINS)); + expect(componentButton === null).assertFalse(); + await componentButton.click(); + let str = await getResourceString($r('app.string.SwiperCustomAnimation_title')); + let sampleButton = await driver.findComponent(ON.text(str, MatchPattern.CONTAINS)); + expect(sampleButton === null).assertFalse(); + await sampleButton.click(); + + let swiper = await driver.findComponent(ON.type('Swiper')); + expect(swiper === null).assertFalse(); + let scrollPoint:Point = {x:400,y:400}; + await driver.mouseScroll(scrollPoint,true,2); + await driver.pressBack(); + await driver.pressBack(); + console.info('uitest: testSwiperCustomAnimation end'); + done(); + }) + + /** + * @tc.number UiTest_014 + * @tc.name testSwiperPageSwitchMethod + * @tc.desc 测试页面切换方式示例 + */ + it('testSwiperPageSwitchMethod', 0, async (done: Function) => { + console.info('uitest: testSwiperPageSwitchMethod begin'); + let driver = Driver.create(); + let componentButton = await driver.findComponent(ON.text('Swiper', MatchPattern.CONTAINS)); + expect(componentButton === null).assertFalse(); + await componentButton.click(); + let str = await getResourceString($r('app.string.SwiperPageSwitchMethod_title')); + let sampleButton = await driver.findComponent(ON.text(str, MatchPattern.CONTAINS)); + expect(sampleButton === null).assertFalse(); + await sampleButton.click(); + + let buttonPrevious = await driver.findComponent(ON.text('showPrevious', MatchPattern.CONTAINS)); + let buttonNext = await driver.findComponent(ON.text('showNext', MatchPattern.CONTAINS)); + expect(buttonPrevious === null).assertFalse(); + expect(buttonNext === null).assertFalse(); + await buttonNext.click(); + await buttonPrevious.click(); + await driver.pressBack(); + await driver.pressBack(); + console.info('uitest: testSwiperPageSwitchMethod end'); + done(); + }) + + /** + * @tc.number UiTest_015 + * @tc.name testTabsLayout + * @tc.desc 测试基本布局示例 + */ + it('testTabsLayout', 0, async (done: Function) => { + console.info('uitest: testTabsLayout begin'); + let driver = Driver.create(); + let componentButton = await driver.findComponent(ON.text('Tabs', MatchPattern.CONTAINS)); + expect(componentButton === null).assertFalse(); + await componentButton.click(); + let str = await getResourceString($r('app.string.TabsLayout_title')); + let sampleButton = await driver.findComponent(ON.text(str, MatchPattern.CONTAINS)); + expect(sampleButton === null).assertFalse(); + await sampleButton.click(); + + let tabs = await driver.findComponent(ON.type('Tabs')); + expect(tabs === null).assertFalse(); + let scrollPoint:Point = {x:400,y:400}; + await driver.mouseScroll(scrollPoint,true,2); + await driver.pressBack(); + await driver.pressBack(); + console.info('uitest: testTabsLayout end'); + done(); + }) + + /** + * @tc.number UiTest_016 + * @tc.name testBottomTabBar + * @tc.desc 测试底部导航示例 + */ + it('testBottomTabBar', 0, async (done: Function) => { + console.info('uitest: testBottomTabBar begin'); + let driver = Driver.create(); + let componentButton = await driver.findComponent(ON.text('Tabs', MatchPattern.CONTAINS)); + expect(componentButton === null).assertFalse(); + await componentButton.click(); + let str = await getResourceString($r('app.string.BottomTabBar_title')); + let sampleButton = await driver.findComponent(ON.text(str, MatchPattern.CONTAINS)); + expect(sampleButton === null).assertFalse(); + await sampleButton.click(); + + let tabs = await driver.findComponent(ON.type('Tabs')); + expect(tabs === null).assertFalse(); + let scrollPoint:Point = {x:400,y:400}; + await driver.mouseScroll(scrollPoint,true,2); + await driver.pressBack(); + await driver.pressBack(); + console.info('uitest: testBottomTabBar end'); + done(); + }) + + /** + * @tc.number UiTest_017 + * @tc.name testTopTabBar + * @tc.desc 测试顶部导航示例 + */ + it('testTopTabBar', 0, async (done: Function) => { + console.info('uitest: testBottomTabBar begin'); + let driver = Driver.create(); + let componentButton = await driver.findComponent(ON.text('Tabs', MatchPattern.CONTAINS)); + expect(componentButton === null).assertFalse(); + await componentButton.click(); + let str = await getResourceString($r('app.string.TopTabBar_title')); + let sampleButton = await driver.findComponent(ON.text(str, MatchPattern.CONTAINS)); + expect(sampleButton === null).assertFalse(); + await sampleButton.click(); + + let tabs = await driver.findComponent(ON.type('Tabs')); + expect(tabs === null).assertFalse(); + let scrollPoint:Point = {x:400,y:400}; + await driver.mouseScroll(scrollPoint,true,2); + await driver.pressBack(); + await driver.pressBack(); + console.info('uitest: testBottomTabBar end'); + done(); + }) + + /** + * @tc.number UiTest_018 + * @tc.name testSideTabBar + * @tc.desc 测试侧边导航示例 + */ + it('testSideTabBar', 0, async (done: Function) => { + console.info('uitest: tesSideTabBar begin'); + let driver = Driver.create(); + let componentButton = await driver.findComponent(ON.text('Tabs', MatchPattern.CONTAINS)); + expect(componentButton === null).assertFalse(); + await componentButton.click(); + let str = await getResourceString($r('app.string.SideTabBar_title')); + let sampleButton = await driver.findComponent(ON.text(str, MatchPattern.CONTAINS)); + expect(sampleButton === null).assertFalse(); + await sampleButton.click(); + + let tabs = await driver.findComponent(ON.type('Tabs')); + expect(tabs === null).assertFalse(); + let scrollPoint:Point = {x:400,y:400}; + await driver.mouseScroll(scrollPoint,true,4); + await driver.pressBack(); + await driver.pressBack(); + console.info('uitest: tesSideTabBar end'); + done(); + }) + + /** + * @tc.number UiTest_019 + * @tc.name testSwipeLockedTabBar + * @tc.desc 测试限制导航栏的滑动切换示例 + */ + it('testSwipeLockedTabBar', 0, async (done: Function) => { + console.info('uitest: testSwipeLockedTabBar begin'); + let driver = Driver.create(); + let componentButton = await driver.findComponent(ON.text('Tabs', MatchPattern.CONTAINS)); + expect(componentButton === null).assertFalse(); + await componentButton.click(); + let str = await getResourceString($r('app.string.SwipeLockedTabBar_title')); + let sampleButton = await driver.findComponent(ON.text(str, MatchPattern.CONTAINS)); + expect(sampleButton === null).assertFalse(); + await sampleButton.click(); + + let tabs = await driver.findComponent(ON.type('Tabs')); + expect(tabs === null).assertFalse(); + let scrollPoint:Point = {x:400,y:400}; + await driver.mouseScroll(scrollPoint,true,4); + await driver.pressBack(); + await driver.pressBack(); + console.info('uitest: testSwipeLockedTabBar end'); + done(); + }) + + /** + * @tc.number UiTest_020 + * @tc.name testFixedTabBar + * @tc.desc 测试固定导航栏示例 + */ + it('testFixedTabBar', 0, async (done: Function) => { + console.info('uitest: testFixedTabBar begin'); + let driver = Driver.create(); + let componentButton = await driver.findComponent(ON.text('Tabs', MatchPattern.CONTAINS)); + expect(componentButton === null).assertFalse(); + await componentButton.click(); + let str = await getResourceString($r('app.string.FixedTabBar_title')); + let sampleButton = await driver.findComponent(ON.text(str, MatchPattern.CONTAINS)); + expect(sampleButton === null).assertFalse(); + await sampleButton.click(); + + let tabs = await driver.findComponent(ON.type('Tabs')); + expect(tabs === null).assertFalse(); + let scrollPoint:Point = {x:400,y:400}; + await driver.mouseScroll(scrollPoint,true,4); + await driver.pressBack(); + await driver.pressBack(); + console.info('uitest: testFixedTabBar end'); + done(); + }) + + /** + * @tc.number UiTest_021 + * @tc.name testScrollableTabBar + * @tc.desc 测试滚动导航栏示例 + */ + it('testScrollableTabBar', 0, async (done: Function) => { + console.info('uitest: testScrollableTabBar begin'); + let driver = Driver.create(); + let componentButton = await driver.findComponent(ON.text('Tabs', MatchPattern.CONTAINS)); + expect(componentButton === null).assertFalse(); + await componentButton.click(); + let str = await getResourceString($r('app.string.ScrollableTabBar_title')); + let sampleButton = await driver.findComponent(ON.text(str, MatchPattern.CONTAINS)); + expect(sampleButton === null).assertFalse(); + await sampleButton.click(); + + let tabs = await driver.findComponent(ON.type('Tabs')); + expect(tabs === null).assertFalse(); + let scrollPoint:Point = {x:400,y:400}; + await driver.mouseScroll(scrollPoint,true,12); + await driver.pressBack(); + await driver.pressBack(); + console.info('uitest: testScrollableTabBar end'); + done(); + }) + + /** + * @tc.number UiTest_022 + * @tc.name testCustomTabBar + * @tc.desc 测试自定义导航栏示例 + */ + it('testCustomTabBar', 0, async (done: Function) => { + console.info('uitest: testCustomTabBar begin'); + let driver = Driver.create(); + let componentButton = await driver.findComponent(ON.text('Tabs', MatchPattern.CONTAINS)); + expect(componentButton === null).assertFalse(); + await componentButton.click(); + let str = await getResourceString($r('app.string.CustomTabBar_title')); + let sampleButton = await driver.findComponent(ON.text(str, MatchPattern.CONTAINS)); + expect(sampleButton === null).assertFalse(); + await sampleButton.click(); + + let tabs = await driver.findComponent(ON.type('Tabs')); + expect(tabs === null).assertFalse(); + let scrollPoint:Point = {x:400,y:400}; + await driver.mouseScroll(scrollPoint,true,4); + await driver.pressBack(); + await driver.pressBack(); + console.info('uitest: testCustomTabBar end'); + done(); + }) + + /** + * @tc.number UiTest_023 + * @tc.name testArcSwiperAction + * @tc.desc 测试弧形轮播动画示例 + */ + it('ArcSwiperAction', 0, async (done: Function) => { + console.info('uitest: testSwiperCustomAnimation begin'); + let driver = Driver.create(); + let componentButton = await driver.findComponent(ON.text('ArcSwiper', MatchPattern.CONTAINS)); + expect(componentButton === null).assertFalse(); + await componentButton.click(); + let str = await getResourceString($r('app.string.ArcSwiperAction_title')); + let sampleButton = await driver.findComponent(ON.text(str, MatchPattern.CONTAINS)); + expect(sampleButton === null).assertFalse(); + await sampleButton.click(); + + let swiper = await driver.findComponent(ON.type('Swiper')); + expect(swiper === null).assertFalse(); + let scrollPoint:Point = {x:300,y:300}; + await driver.mouseScroll(scrollPoint,true,2); + await driver.pressBack(); + await driver.pressBack(); + console.info('uitest: testArcSwiperAction end'); + done(); + }) + + /** + * @tc.number UiTest_024 + * @tc.name testArcSwiperVertical + * @tc.desc 测试弧形轮播垂直方向示例 + */ + it('ArcSwiperVertical ', 0, async (done: Function) => { + console.info('uitest: testArcSwiperVertical begin'); + let driver = Driver.create(); + let componentButton = await driver.findComponent(ON.text('ArcSwiper', MatchPattern.CONTAINS)); + expect(componentButton === null).assertFalse(); + await componentButton.click(); + let str = await getResourceString($r('app.string.ArcSwiperVertical_title')); + let sampleButton = await driver.findComponent(ON.text(str, MatchPattern.CONTAINS)); + expect(sampleButton === null).assertFalse(); + await sampleButton.click(); + + let swiper = await driver.findComponent(ON.type('Swiper')); + expect(swiper === null).assertFalse(); + let scrollPoint:Point = {x:300,y:300}; + await driver.mouseScroll(scrollPoint,true,2); + await driver.pressBack(); + await driver.pressBack(); + console.info('uitest: testArcSwiperVertical end'); + done(); + }) + + /** + * @tc.number UiTest_025 + * @tc.name testArcSwiperHorizontal + * @tc.desc 测试弧形轮播水平方向示例 + */ + it('ArcSwiperHorizontal', 0, async (done: Function) => { + console.info('uitest: testArcSwiperHorizontal begin'); + let driver = Driver.create(); + let componentButton = await driver.findComponent(ON.text('ArcSwiper', MatchPattern.CONTAINS)); + expect(componentButton === null).assertFalse(); + await componentButton.click(); + let str = await getResourceString($r('app.string.ArcSwiperHorizontal_title')); + let sampleButton = await driver.findComponent(ON.text(str, MatchPattern.CONTAINS)); + expect(sampleButton === null).assertFalse(); + await sampleButton.click(); + + let swiper = await driver.findComponent(ON.type('Swiper')); + expect(swiper === null).assertFalse(); + let scrollPoint:Point = {x:300,y:300}; + await driver.mouseScroll(scrollPoint,true,2); + await driver.pressBack(); + await driver.pressBack(); + console.info('uitest: testArcSwiperHorizontal end'); + done(); + }) + + /** + * @tc.number UiTest_026 + * @tc.name testArcSwiperSideSlip + * @tc.desc 测试弧形轮播侧滑返回示例 + */ + it('ArcSwiperSideSlip', 0, async (done: Function) => { + console.info('uitest: testArcSwiperSideSlip begin'); + let driver = Driver.create(); + let componentButton = await driver.findComponent(ON.text('ArcSwiper', MatchPattern.CONTAINS)); + expect(componentButton === null).assertFalse(); + await componentButton.click(); + let str = await getResourceString($r('app.string.ArcSwiperSideSlip_title')); + let sampleButton = await driver.findComponent(ON.text(str, MatchPattern.CONTAINS)); + expect(sampleButton === null).assertFalse(); + await sampleButton.click(); + + let swiper = await driver.findComponent(ON.type('Swiper')); + expect(swiper === null).assertFalse(); + let scrollPoint:Point = {x:300,y:300}; + await driver.mouseScroll(scrollPoint,true,2); + await driver.mouseScroll(scrollPoint,false,2); + await driver.pressBack(); + await driver.pressBack(); + console.info('uitest: testArcSwiperSideSlip end'); + done(); + }) + + /** + * @tc.number UiTest_027 + * @tc.name testArcSwiperToggle + * @tc.desc 测试弧形轮播页面切换方式示例 + */ + it('ArcSwiperToggle', 0, async (done: Function) => { + console.info('uitest: testArcSwiperToggle begin'); + let driver = Driver.create(); + let componentButton = await driver.findComponent(ON.text('ArcSwiper', MatchPattern.CONTAINS)); + expect(componentButton === null).assertFalse(); + await componentButton.click(); + let str = await getResourceString($r('app.string.ArcSwiperToggle_title')); + let sampleButton = await driver.findComponent(ON.text(str, MatchPattern.CONTAINS)); + expect(sampleButton === null).assertFalse(); + await sampleButton.click(); + + let preArcButton = await driver.findComponent(ON.text('previous', MatchPattern.CONTAINS)); + let nextArcButton = await driver.findComponent(ON.text('next', MatchPattern.CONTAINS)); + expect(preArcButton === null).assertFalse(); + expect(nextArcButton === null).assertFalse(); + await nextArcButton.click(); + await preArcButton.click(); + await driver.pressBack(); + await driver.pressBack(); + console.info('uitest: testArcSwiperToggle end'); + done(); + }) + + /** + * @tc.number UiTest_028 + * @tc.name testArcSwiperStyles + * @tc.desc 测试弧形轮播设置导航点样式示例 + */ + it('ArcSwiperStyles', 0, async (done: Function) => { + console.info('uitest: testArcSwiperToggle begin'); + let driver = Driver.create(); + let componentButton = await driver.findComponent(ON.text('ArcSwiper', MatchPattern.CONTAINS)); + expect(componentButton === null).assertFalse(); + await componentButton.click(); + let str = await getResourceString($r('app.string.ArcSwiperStyles_title')); + let sampleButton = await driver.findComponent(ON.text(str, MatchPattern.CONTAINS)); + expect(sampleButton === null).assertFalse(); + await sampleButton.click(); + + let swiper = await driver.findComponent(ON.type('Swiper')); + expect(swiper === null).assertFalse(); + let scrollPoint:Point = {x:300,y:300}; + let scrollPoint2:Point = {x:300,y:600}; + await driver.mouseScroll(scrollPoint,true,2); + await driver.mouseScroll(scrollPoint2,true,2); + await driver.pressBack(); + await driver.pressBack(); + console.info('uitest: testArcSwiperStyles end'); + done(); + }) + + /** + * @tc.number UiTest_029 + * @tc.name testSwiperAndTabsLinkage + * @tc.desc 测试轮播与选项卡联动示例 + */ + it('SwiperAndTabsLinkage', 0, async (done: Function) => { + console.info('uitest: testSwiperAndTabsLinkage begin'); + let driver = Driver.create(); + let componentButton = await driver.findComponent(ON.text('Swiper', MatchPattern.CONTAINS)); + expect(componentButton === null).assertFalse(); + await componentButton.click(); + let str = await getResourceString($r('app.string.SwiperAndTabsLinkage_title')); + let sampleButton = await driver.findComponent(ON.text(str, MatchPattern.CONTAINS)); + expect(sampleButton === null).assertFalse(); + await sampleButton.click(); + + let swiper = await driver.findComponent(ON.type('Swiper')); + expect(swiper === null).assertFalse(); + let scrollPoint:Point = {x:400,y:500}; + await driver.mouseScroll(scrollPoint,true,2); + await driver.pressBack(); + await driver.pressBack(); + console.info('uitest: testSwiperAndTabsLinkage end'); + done(); + }) + + /** + * @tc.number UiTest_030 + * @tc.name testLongGrid + * @tc.desc 测试网格性能优化示例 + */ + it('LongGrid', 0, async (done: Function) => { + console.info('uitest: testLongGrid begin'); + let driver = Driver.create(); + let componentButton = await driver.findComponent(ON.text('Grid', MatchPattern.CONTAINS)); + expect(componentButton === null).assertFalse(); + await componentButton.click(); + let str = await getResourceString($r('app.string.LongGrid_title')); + let sampleButton = await driver.findComponent(ON.text(str, MatchPattern.CONTAINS)); + expect(sampleButton === null).assertFalse(); + await sampleButton.click(); + + let scrollableGrid = await driver.findComponent(ON.type('Grid')); + expect(scrollableGrid === null).assertFalse(); + await scrollableGrid.scrollToBottom(); + await driver.pressBack(); + await driver.pressBack(); + console.info('uitest: testLongGrid end'); + done(); + }) + + /** + * @tc.number UiTest_031 + * @tc.name testGridScrollbar + * @tc.desc 测试网格添加外置滚动条示例 + */ + it('GridScrollbar', 0, async (done: Function) => { + console.info('uitest: testGridScrollbar begin'); + let driver = Driver.create(); + let componentButton = await driver.findComponent(ON.text('Grid', MatchPattern.CONTAINS)); + expect(componentButton === null).assertFalse(); + await componentButton.click(); + let str = await getResourceString($r('app.string.GridScrollbar_title')); + let sampleButton = await driver.findComponent(ON.text(str, MatchPattern.CONTAINS)); + expect(sampleButton === null).assertFalse(); + await sampleButton.click(); + + let scrollableGrid = await driver.findComponent(ON.type('Grid')); + expect(scrollableGrid === null).assertFalse(); + await scrollableGrid.scrollToBottom(); + await driver.pressBack(); + await driver.pressBack(); + console.info('uitest: testGridScrollbar end'); + done(); + }) + + /** + * @tc.number UiTest_032 + * @tc.name testGridSideToSide + * @tc.desc 测试网格控制滚动位置示例 + */ + it('GridSideToSide', 0, async (done: Function) => { + console.info('uitest: testGridSideToSide begin'); + let driver = Driver.create(); + let componentButton = await driver.findComponent(ON.text('Grid', MatchPattern.CONTAINS)); + expect(componentButton === null).assertFalse(); + await componentButton.click(); + let str = await getResourceString($r('app.string.GridSideToSide_description')); + let sampleButton = await driver.findComponent(ON.text(str, MatchPattern.CONTAINS)); + expect(sampleButton === null).assertFalse(); + await sampleButton.click(); + + let preArcButton = await driver.findComponent(ON.text('上一页', MatchPattern.CONTAINS)); + let nextArcButton = await driver.findComponent(ON.text('下一页', MatchPattern.CONTAINS)); + expect(preArcButton === null).assertFalse(); + expect(nextArcButton === null).assertFalse(); + await nextArcButton.click(); + await preArcButton.click(); + await driver.pressBack(); + await driver.pressBack(); + console.info('uitest: testGridSideToSide end'); + done(); + }) + + /** + * @tc.number UiTest_033 + * @tc.name testLongList + * @tc.desc 测试长列表示例 + */ + it('LongList', 0, async (done: Function) => { + console.info('uitest: testLongList begin'); + let driver = Driver.create(); + let componentButton = await driver.findComponent(ON.text('List', MatchPattern.CONTAINS)); + expect(componentButton === null).assertFalse(); + await componentButton.click(); + let list = await driver.findComponent(ON.type('List')); + expect(list === null).assertFalse(); + await list.scrollToBottom(1000); + let str = await getResourceString($r('app.string.LongList_title')); + let sampleButton = await driver.findComponent(ON.text(str, MatchPattern.CONTAINS)); + expect(sampleButton === null).assertFalse(); + await sampleButton.click(); + + let scrollableList = await driver.findComponent(ON.type('List')); + expect(scrollableList === null).assertFalse(); + await scrollableList.scrollToBottom(); + await driver.pressBack(); + await driver.pressBack(); + console.info('uitest: testLongList end'); + done(); + }) + + /** + * @tc.number UiTest_033 + * @tc.name testCollapseAndExpand + * @tc.desc 测试列表折叠与展开示例 + */ + it('CollapseAndExpand', 0, async (done: Function) => { + console.info('uitest: testCollapseAndExpand begin'); + let driver = Driver.create(); + let componentButton = await driver.findComponent(ON.text('List', MatchPattern.CONTAINS)); + expect(componentButton === null).assertFalse(); + await componentButton.click(); + let list = await driver.findComponent(ON.type('List')); + expect(list === null).assertFalse(); + await list.scrollToBottom(1000); + let str = await getResourceString($r('app.string.CollapseAndExpand_title')); + let sampleButton = await driver.findComponent(ON.text(str, MatchPattern.CONTAINS)); + expect(sampleButton === null).assertFalse(); + await sampleButton.click(); + + let text = await driver.findComponent(ON.text('个人基本资料', MatchPattern.CONTAINS)); + expect(text === null).assertFalse(); + await text.click(); + let nameText = await driver.findComponent(ON.text('昵称', MatchPattern.CONTAINS)); + expect(nameText === null).assertFalse(); + await text.click(); + nameText = await driver.findComponent(ON.text('昵称', MatchPattern.CONTAINS)); + expect(nameText === null).assertTrue(); + await driver.pressBack(); + await driver.pressBack(); + console.info('uitest: testCollapseAndExpand end'); + done(); + }) + + /** + * @tc.number UiTest_035 + * @tc.name testArcLongList + * @tc.desc 测试弧形长列表示例 + */ + it('ArcLongList', 0, async (done: Function) => { + console.info('uitest: testArcLongList begin'); + let driver = Driver.create(); + let componentButton = await driver.findComponent(ON.text('ArcList', MatchPattern.CONTAINS)); + expect(componentButton === null).assertFalse(); + await componentButton.click(); + let str = await getResourceString($r('app.string.ArcLongList_title')); + let sampleButton = await driver.findComponent(ON.text(str, MatchPattern.CONTAINS)); + expect(sampleButton === null).assertFalse(); + await sampleButton.click(); + + let arclist = await driver.findComponent(ON.type('ArcList')); + expect(arclist === null).assertFalse(); + await arclist.scrollToBottom(15000); + await driver.pressBack(); + await driver.pressBack(); + console.info('uitest: testArcLongList end'); + done(); + }) + + /** + * @tc.number UiTest_036 + * @tc.name testArcListAcrScrollBar + * @tc.desc 测试弧形列表外置滚动条示例 + */ + it('ArcListAcrScrollBar', 0, async (done: Function) => { + console.info('uitest: testArcListAcrScrollBar begin'); + let driver = Driver.create(); + let componentButton = await driver.findComponent(ON.text('ArcList', MatchPattern.CONTAINS)); + expect(componentButton === null).assertFalse(); + await componentButton.click(); + let str = await getResourceString($r('app.string.ArcListAcrScrollBar_title')); + let sampleButton = await driver.findComponent(ON.text(str, MatchPattern.CONTAINS)); + expect(sampleButton === null).assertFalse(); + await sampleButton.click(); + + let arclist = await driver.findComponent(ON.type('ArcList')); + expect(arclist === null).assertFalse(); + await arclist.scrollToBottom(); + await driver.pressBack(); + await driver.pressBack(); + console.info('uitest: testArcListAcrScrollBar end'); + done(); + }) + + /** + * @tc.number UiTest_037 + * @tc.name testArcListBuiltInScrollerBar + * @tc.desc 测试弧形列表内置滚动条示例 + */ + it('arcListBuiltInScrollerBar', 0, async (done: Function) => { + console.info('uitest: testArcListBuiltInScrollerBar begin'); + let driver = Driver.create(); + let componentButton = await driver.findComponent(ON.text('ArcList', MatchPattern.CONTAINS)); + expect(componentButton === null).assertFalse(); + await componentButton.click(); + let str = await getResourceString($r('app.string.arcListBuiltInScrollerBar_title')); + let sampleButton = await driver.findComponent(ON.text(str, MatchPattern.CONTAINS)); + expect(sampleButton === null).assertFalse(); + await sampleButton.click(); + + let arclist = await driver.findComponent(ON.type('ArcList')); + expect(arclist === null).assertFalse(); + await arclist.scrollToBottom(); + await driver.pressBack(); + await driver.pressBack(); + console.info('uitest: testArcListBuiltInScrollerBar end'); + done(); + }) + + /** + * @tc.number UiTest_038 + * @tc.name testArcListContents + * @tc.desc 测试弧形列表内置滚动条示例 + */ + it('ArcListContents', 0, async (done: Function) => { + console.info('uitest: testArcListContents begin'); + let driver = Driver.create(); + let componentButton = await driver.findComponent(ON.text('ArcList', MatchPattern.CONTAINS)); + expect(componentButton === null).assertFalse(); + await componentButton.click(); + let str = await getResourceString($r('app.string.ArcListContents_title')); + let sampleButton = await driver.findComponent(ON.text(str, MatchPattern.CONTAINS)); + expect(sampleButton === null).assertFalse(); + await sampleButton.click(); + + let arclist = await driver.findComponent(ON.type('ArcList')); + expect(arclist === null).assertFalse(); + await arclist.scrollToBottom(); + await driver.pressBack(); + await driver.pressBack(); + console.info('uitest: testArcListContents end'); + done(); + }) + + /** + * @tc.number UiTest_039 + * @tc.name testArcListShow + * @tc.desc 测试弧形列表展示数据示例 + */ + it('ArcListShow', 0, async (done: Function) => { + console.info('uitest: testArcListShow begin'); + let driver = Driver.create(); + let componentButton = await driver.findComponent(ON.text('ArcList', MatchPattern.CONTAINS)); + expect(componentButton === null).assertFalse(); + await componentButton.click(); + let str = await getResourceString($r('app.string.ArcListShow_title')); + let sampleButton = await driver.findComponent(ON.text(str, MatchPattern.CONTAINS)); + expect(sampleButton === null).assertFalse(); + await sampleButton.click(); + + let arclist = await driver.findComponent(ON.type('ArcList')); + expect(arclist === null).assertFalse(); + await arclist.scrollToBottom(); + await driver.pressBack(); + await driver.pressBack(); + console.info('uitest: testArcListShow end'); + done(); + }) + + /** + * @tc.number UiTest_040 + * @tc.name testArcListStyles + * @tc.desc 测试弧形列表设置样式示例 + */ + it('ArcListStyles', 0, async (done: Function) => { + console.info('uitest: testArcListStyles begin'); + let driver = Driver.create(); + let componentButton = await driver.findComponent(ON.text('ArcList', MatchPattern.CONTAINS)); + expect(componentButton === null).assertFalse(); + await componentButton.click(); + let str = await getResourceString($r('app.string.ArcListStyles_title')); + let sampleButton = await driver.findComponent(ON.text(str, MatchPattern.CONTAINS)); + expect(sampleButton === null).assertFalse(); + await sampleButton.click(); + + let arclist = await driver.findComponent(ON.type('List')); + expect(arclist === null).assertFalse(); + await arclist.scrollToBottom(); + await driver.pressBack(); + await driver.pressBack(); + console.info('uitest: testArcListStyles end'); + done(); + }) + + /** + * @tc.number UiTest_041 + * @tc.name testArcListArcIndexerBar + * @tc.desc 测试弧形列表联动indexer示例 + */ + it('ArcListArcIndexerBar', 0, async (done: Function) => { + console.info('uitest: testArcListArcIndexerBar begin'); + let driver = Driver.create(); + let componentButton = await driver.findComponent(ON.text('ArcList', MatchPattern.CONTAINS)); + expect(componentButton === null).assertFalse(); + await componentButton.click(); + let str = await getResourceString($r('app.string.ArcListArcIndexerBar_title')); + let sampleButton = await driver.findComponent(ON.text(str, MatchPattern.CONTAINS)); + expect(sampleButton === null).assertFalse(); + await sampleButton.click(); + + let button = await driver.findComponent(ON.type('Button')); + expect(button === null).assertFalse(); + await button.click(); + let testText = await driver.findComponent(ON.text('F', MatchPattern.CONTAINS)); + expect(testText === null).assertFalse(); + let arclist = await driver.findComponent(ON.type('ArcList')); + expect(arclist === null).assertFalse(); + await arclist.scrollToBottom(5000); + await driver.pressBack(); + await driver.pressBack(); + console.info('uitest: testArcListArcIndexerBar end'); + done(); + }) + + /** + * @tc.number UiTest_042 + * @tc.name testArcListSideSlip + * @tc.desc 测试弧形列表侧滑示例 + */ + it('ArcListSideSlip', 0, async (done: Function) => { + console.info('uitest: testArcListSideSlip begin'); + let driver = Driver.create(); + let componentButton = await driver.findComponent(ON.text('ArcList', MatchPattern.CONTAINS)); + expect(componentButton === null).assertFalse(); + await componentButton.click(); + let str = await getResourceString($r('app.string.ArcListSideSlip_title')); + let sampleButton = await driver.findComponent(ON.text(str, MatchPattern.CONTAINS)); + expect(sampleButton === null).assertFalse(); + await sampleButton.click(); + + let arclist = await driver.findComponent(ON.type('ArcList')); + expect(arclist === null).assertFalse(); + let scrollPoint:Point = {x:200,y:500}; + let scrollPoint2:Point = {x:500,y:500}; + + await driver.fling(scrollPoint2,scrollPoint,1,600); + let button = await driver.findComponent(ON.type('Button')); + expect(button === null).assertFalse(); + await button.click(); + let testText = await driver.findComponent(ON.text('Alice', MatchPattern.CONTAINS)); + expect(testText === null).assertTrue(); + await arclist.scrollToBottom(5000); + await driver.pressBack(); + await driver.pressBack(); + console.info('uitest: testArcListSideSlip end'); + done(); + }) + + /** + * @tc.number UiTest_043 + * @tc.name testWaterFlowDynamicSwitchover + * @tc.desc 测试瀑布流动态切换列数示例 + */ + it('WaterFlowDynamicSwitchover', 0, async (done: Function) => { + console.info('uitest: testWaterFlowDynamicSwitchover begin'); + let driver = Driver.create(); + let componentButton = await driver.findComponent(ON.text('WaterFlow', MatchPattern.CONTAINS)); + expect(componentButton === null).assertFalse(); + await componentButton.click(); + let str = await getResourceString($r('app.string.WaterFlowDynamicSwitchover_title')); + let sampleButton = await driver.findComponent(ON.text(str, MatchPattern.CONTAINS)); + expect(sampleButton === null).assertFalse(); + await sampleButton.click(); + + let arclist = await driver.findComponent(ON.type('WaterFlow')); + expect(arclist === null).assertFalse(); + let flowItemText = await driver.findComponent(ON.text('FlowItem0', MatchPattern.CONTAINS)); + expect(flowItemText === null).assertFalse(); + let scrollPoint:Point = {x:350,y:1100}; + let scrollPoint2:Point = {x:350,y:550}; + await driver.fling(scrollPoint,scrollPoint2,1,1200); + let button = await driver.findComponent(ON.type('Button')); + expect(button === null).assertFalse(); + await button.click(); + let testText = await driver.findComponent(ON.text('N9', MatchPattern.CONTAINS)); + expect(testText === null).assertFalse(); + await driver.fling(scrollPoint,scrollPoint2,1,1200); + await driver.pressBack(); + await driver.pressBack(); + console.info('uitest: testWaterFlowDynamicSwitchover end'); + done(); + }) + + /** + * @tc.number UiTest_044 + * @tc.name testWaterFlowGroupingMixing + * @tc.desc 测试瀑布流混合布局示例 + */ + it('WaterFlowGroupingMixing', 0, async (done: Function) => { + console.info('uitest: testWaterFlowGroupingMixing begin'); + let driver = Driver.create(); + let componentButton = await driver.findComponent(ON.text('WaterFlow', MatchPattern.CONTAINS)); + expect(componentButton === null).assertFalse(); + await componentButton.click(); + let str = await getResourceString($r('app.string.WaterFlowGroupingMixing_title')); + let sampleButton = await driver.findComponent(ON.text(str, MatchPattern.CONTAINS)); + expect(sampleButton === null).assertFalse(); + await sampleButton.click(); + + let arclist = await driver.findComponent(ON.type('WaterFlow')); + expect(arclist === null).assertFalse(); + let scrollPoint:Point = {x:350,y:1100}; + let scrollPoint2:Point = {x:350,y:550}; + await driver.fling(scrollPoint,scrollPoint2,1,1200); + await driver.pressBack(); + await driver.pressBack(); + console.info('uitest: testWaterFlowGroupingMixing end'); + done(); + }) + + /** + * @tc.number UiTest_045 + * @tc.name testWaterFlowInfiniteScrolling + * @tc.desc 测试瀑布流无限滑动触底增加示例 + */ + it('WaterFlowInfiniteScrolling', 0, async (done: Function) => { + console.info('uitest: testWaterFlowInfiniteScrolling begin'); + let driver = Driver.create(); + let componentButton = await driver.findComponent(ON.text('WaterFlow', MatchPattern.CONTAINS)); + expect(componentButton === null).assertFalse(); + await componentButton.click(); + let str = await getResourceString($r('app.string.WaterFlowInfiniteScrolling_title')); + let sampleButton = await driver.findComponent(ON.text(str, MatchPattern.CONTAINS)); + expect(sampleButton === null).assertFalse(); + await sampleButton.click(); + + let arclist = await driver.findComponent(ON.type('WaterFlow')); + expect(arclist === null).assertFalse(); + let scrollPoint:Point = {x:350,y:1100}; + let scrollPoint2:Point = {x:350,y:550}; + await driver.fling(scrollPoint,scrollPoint2,1,1200); + await driver.pressBack(); + await driver.pressBack(); + console.info('uitest: testWaterFlowInfiniteScrolling end'); + done(); + }) + + /** + * @tc.number UiTest_046 + * @tc.name testWaterFlowInfiniteScrollingEarly + * @tc.desc 测试瀑布流无限滑动提前增加示例 + */ + it('WaterFlowInfiniteScrollingEarly', 0, async (done: Function) => { + console.info('uitest: testWaterFlowInfiniteScrollingEarly begin'); + let driver = Driver.create(); + let componentButton = await driver.findComponent(ON.text('WaterFlow', MatchPattern.CONTAINS)); + expect(componentButton === null).assertFalse(); + await componentButton.click(); + let str = await getResourceString($r('app.string.WaterFlowInfiniteScrollingEarly_title')); + let sampleButton = await driver.findComponent(ON.text(str, MatchPattern.CONTAINS)); + expect(sampleButton === null).assertFalse(); + await sampleButton.click(); + + let arclist = await driver.findComponent(ON.type('WaterFlow')); + expect(arclist === null).assertFalse(); + let scrollPoint:Point = {x:350,y:1100}; + let scrollPoint2:Point = {x:350,y:550}; + await driver.fling(scrollPoint,scrollPoint2,1,1200); + await driver.pressBack(); + await driver.pressBack(); + console.info('uitest: testWaterFlowInfiniteScrollingEarly end'); + done(); + }) + + /** + * @tc.number UiTest_034 + * @tc.name testListChatRoom + * @tc.desc 测试列表切换布局方向示例 + */ + it('ListChatRoom', 0, async (done: Function) => { + console.info('uitest: testListChatRoom begin'); + let driver = Driver.create(); + let componentButton = await driver.findComponent(ON.text('List', MatchPattern.CONTAINS)); + expect(componentButton === null).assertFalse(); + await componentButton.click(); + let list = await driver.findComponent(ON.type('List')); + expect(list === null).assertFalse(); + await list.scrollToBottom(1000); + let str = await getResourceString($r('app.string.ListChatRoom_title')); + let sampleButton = await driver.findComponent(ON.text(str, MatchPattern.CONTAINS)); + expect(sampleButton === null).assertFalse(); + await sampleButton.click(); + + let textInput = await driver.findComponent(ON.type('TextInput')); + expect(textInput === null).assertFalse(); + await textInput.inputText("message test") + let testButton = await driver.findComponent(ON.text('发送', MatchPattern.CONTAINS)); + expect(testButton === null).assertFalse(); + await testButton.click(); + await driver.mouseClick({x: 670, y: 700}, MouseButton.MOUSE_BUTTON_LEFT, 0, 0); + let nameText = await driver.findComponent(ON.text('message test', MatchPattern.CONTAINS)); + expect(nameText === null).assertFalse(); + await driver.pressBack(); + await driver.pressBack(); + console.info('uitest: testListChatRoom end'); + done(); + }) + + }) +} \ No newline at end of file diff --git a/ArkUISample/ScrollableComponent/entry/src/ohosTest/module.json5 b/ArkUISample/ScrollableComponent/entry/src/ohosTest/module.json5 new file mode 100644 index 0000000000000000000000000000000000000000..c3fd9dda3040d888d9d8b0b62bcb5d3b6fbeb614 --- /dev/null +++ b/ArkUISample/ScrollableComponent/entry/src/ohosTest/module.json5 @@ -0,0 +1,27 @@ +/* + * Copyright (c) 2025 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +{ + "module": { + "name": "entry_test", + "type": "feature", + "deviceTypes": [ + "default", + "tablet" + ], + "deliveryWithInstall": true, + "installationFree": false + } +} diff --git a/ArkUISample/ScrollableComponent/entry/src/test/List.test.ets b/ArkUISample/ScrollableComponent/entry/src/test/List.test.ets new file mode 100644 index 0000000000000000000000000000000000000000..f1186b1f53c3a70930921c5dbd1417332bec56c9 --- /dev/null +++ b/ArkUISample/ScrollableComponent/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/ArkUISample/ScrollableComponent/entry/src/test/LocalUnit.test.ets b/ArkUISample/ScrollableComponent/entry/src/test/LocalUnit.test.ets new file mode 100644 index 0000000000000000000000000000000000000000..7fc57c77dbf76d8df08a2b802a55b948e3fcf968 --- /dev/null +++ b/ArkUISample/ScrollableComponent/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/ArkUISample/ScrollableComponent/hvigor/hvigor-config.json5 b/ArkUISample/ScrollableComponent/hvigor/hvigor-config.json5 new file mode 100644 index 0000000000000000000000000000000000000000..d584c19c247db9a7caee4b606bb931aa9279c637 --- /dev/null +++ b/ArkUISample/ScrollableComponent/hvigor/hvigor-config.json5 @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2025 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +{ + "modelVersion": "5.0.1", + "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/ArkUISample/ScrollableComponent/hvigorfile.ts b/ArkUISample/ScrollableComponent/hvigorfile.ts new file mode 100644 index 0000000000000000000000000000000000000000..2a5e543f190732c159beb574dfc9fa37bc94e156 --- /dev/null +++ b/ArkUISample/ScrollableComponent/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. */ +} diff --git a/ArkUISample/ScrollableComponent/oh-package.json5 b/ArkUISample/ScrollableComponent/oh-package.json5 new file mode 100644 index 0000000000000000000000000000000000000000..e41bae026aab3b50d0abb42fece08ba43b4a772b --- /dev/null +++ b/ArkUISample/ScrollableComponent/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": "5.0.1", + "description": "Please describe the basic information.", + "dependencies": { + }, + "devDependencies": { + "@ohos/hypium": "1.0.19", + "@ohos/hamock": "1.0.0" + } +} diff --git a/ArkUISample/ScrollableComponent/screenshots/device/image1.png b/ArkUISample/ScrollableComponent/screenshots/device/image1.png new file mode 100644 index 0000000000000000000000000000000000000000..405d7c9a85730a32a35eb1e90e09dfed55114733 Binary files /dev/null and b/ArkUISample/ScrollableComponent/screenshots/device/image1.png differ diff --git a/ArkUISample/ScrollableComponent/screenshots/device/image2.png b/ArkUISample/ScrollableComponent/screenshots/device/image2.png new file mode 100644 index 0000000000000000000000000000000000000000..7bb783a24ecd950f7ba8e45d4b12d7905cff9e90 Binary files /dev/null and b/ArkUISample/ScrollableComponent/screenshots/device/image2.png differ diff --git a/ArkUISample/ScrollableComponent/screenshots/device/image3.png b/ArkUISample/ScrollableComponent/screenshots/device/image3.png new file mode 100644 index 0000000000000000000000000000000000000000..29676689f850c442159c7371319a739a126bb945 Binary files /dev/null and b/ArkUISample/ScrollableComponent/screenshots/device/image3.png differ diff --git a/ArkUISample/TextComponent/.gitignore b/ArkUISample/TextComponent/.gitignore new file mode 100644 index 0000000000000000000000000000000000000000..d2ff20141ceed86d87c0ea5d99481973005bab2b --- /dev/null +++ b/ArkUISample/TextComponent/.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/ArkUISample/TextComponent/AppScope/app.json5 b/ArkUISample/TextComponent/AppScope/app.json5 new file mode 100644 index 0000000000000000000000000000000000000000..af7bd41f017310b9498002b09145c9c5b6b75460 --- /dev/null +++ b/ArkUISample/TextComponent/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.textcomponent", + "vendor": "example", + "versionCode": 1000000, + "versionName": "1.0.0", + "icon": "$media:app_icon", + "label": "$string:app_name" + } +} diff --git a/ArkUISample/TextComponent/AppScope/resources/base/element/string.json b/ArkUISample/TextComponent/AppScope/resources/base/element/string.json new file mode 100644 index 0000000000000000000000000000000000000000..9752e547f0026820aeabe04df997f59e9335ac36 --- /dev/null +++ b/ArkUISample/TextComponent/AppScope/resources/base/element/string.json @@ -0,0 +1,8 @@ +{ + "string": [ + { + "name": "app_name", + "value": "TextComponent" + } + ] +} diff --git a/ArkUISample/TextComponent/AppScope/resources/base/media/app_icon.png b/ArkUISample/TextComponent/AppScope/resources/base/media/app_icon.png new file mode 100644 index 0000000000000000000000000000000000000000..a39445dc87828b76fed6d2ec470dd455c45319e3 Binary files /dev/null and b/ArkUISample/TextComponent/AppScope/resources/base/media/app_icon.png differ diff --git a/ArkUISample/TextComponent/README_zh.md b/ArkUISample/TextComponent/README_zh.md new file mode 100644 index 0000000000000000000000000000000000000000..49f2b8cdbfdbab1bbd9f233d24ed62f6af25e6ca --- /dev/null +++ b/ArkUISample/TextComponent/README_zh.md @@ -0,0 +1,125 @@ +# ArkUI使用文本控件指南文档示例 + +### 介绍 + +本示例通过使用[ArkUI指南文档](https://gitee.com/openharmony/docs/tree/master/zh-cn/application-dev/ui)中各场景的开发示例,展示在工程中,帮助开发者更好地理解ArkUI提供的组件及组件属性并合理使用。该工程中展示的代码详细描述可查如下链接: + +1. [文本显示 (Text/Span)](https://gitee.com/openharmony/docs/blob/master/zh-cn/application-dev/ui/arkts-common-components-text-display.md)。 +2. [文本输入 (TextInput/TextArea)](https://gitee.com/openharmony/docs/blob/master/zh-cn/application-dev/ui/arkts-common-components-text-input.md)。 +3. [富文本 (RichEditor)](https://gitee.com/openharmony/docs/blob/master/zh-cn/application-dev/ui/arkts-common-components-richeditor.md)。 +4. [图标小符号 (SymbolGlyph/SymbolSpan)](https://gitee.com/openharmony/docs/blob/master/zh-cn/application-dev/ui/arkts-common-components-symbol.md)。 +5. [属性字符串 (StyledString/MutableStyledString)](https://gitee.com/openharmony/docs/blob/master/zh-cn/application-dev/ui/arkts-styled-string.md)。 +6. [Text组件的文本绘制与显示](https://gitee.com/openharmony/docs/blob/master/zh-cn/application-dev/ui/ndk-styled-string.md)。 +7. [监听输入框事件](https://gitee.com/openharmony/docs/blob/master/zh-cn/application-dev/ui/ndk-textarea-event.md)。 + +### 效果预览 + +| 首页 | 文本显示组件目录 | 创建文本示例 | +|-------------------------------------| ----------------------------------- | ----------------------------------- | +| ![](screenshots/device/image1.jpeg) | ![](screenshots/device/image2.jpeg) | ![](screenshots/device/image3.jpeg) | + +### 使用说明 + +1. 在主界面,可以点击对应卡片,选择需要参考的组件示例。 + +2. 在组件目录选择详细的示例参考。 + +3. 进入示例界面,查看参考示例。 + +4. 通过自动测试框架可进行测试及维护。 + +### 工程目录 + +``` +entry/src/main/ets/ +|---entryability +|---pages +| |---ndk // ndk接口使用文本 +| | |---index.ets +| | |---TextDrawingDisplay.ets +| | |---ListenTextBoxEvents.ets +| |---propertyString // 属性字符串 +| | |---CreateApply.ets +| | |---index.ets +| | |---StyledStringGestureStyle.ets +| | |---StyledStringHtml.ets +| | |---StyledStringImageAttachment.ets +| | |---StyledStringParagraphStyle.ets +| | |---StyledStringSceneExample.ets +| | |---StyledStringStyle.ets +| |---richEditor // 富文本 +| | |---AddBuilderDecoratorContent.ets +| | |---AddEvent.ets +| | |---AddImageContent.ets +| | |---AddSymbolSpanContent.ets +| | |---AddTextContent.ets +| | |---BackplaneHighlighting.ets +| | |---CreateRichEditor.ets +| | |---GetGraphicInfoInComponent.ets +| | |---index.ets +| | |---SetAttributes.ets +| | |---SetUserPresetTextStyles.ets +| |---symbol // 图标小符号 +| | |---CreatSymbolGlyph.ets +| | |---index.ets +| | |---SymbolAddEvent.ets +| | |---SymbolAddToText.ets +| | |---SymbolCustomIconAnimation.ets +| | |---SymbolSceneExample.ets +| |---text // 文本显示 +| | |---AIMenu.ets +| | |---CreatText.ets +| | |---CustomTextStyle.ets +| | |---index.ets +| | |---SelectMenu.ets +| | |---TextAddEvent.ets +| | |---TextHotSearch.ets +| | |---TextSpan.ets +| |---testInput // 文本输入 +| | |---AutoFill.ets +| | |---CreatTextInput.ets +| | |---CursorAvoidance.ets +| | |---CustomTextInputStyle.ets +| | |---index.ets +| | |---KeyboardAvoidance.ets +| | |---LoginRegisterPage.ets +| | |---SelectMenu.ets +| | |---SetOmissionProperty.ets +| | |---SetTextInputType.ets +| | |---TextInputAddEvent.ets +|---pages +| |---Index.ets // 应用主页面 +entry/src/ohosTest/ +|---ets +| |---index.test.ets // 示例代码测试代码 +``` + +### 相关权限 + +不涉及。 + +### 依赖 + +不涉及。 + +### 约束与限制 + +1. 本示例仅支持标准系统上运行,支持设备:华为手机。 + +2. HarmonyOS系统:HarmonyOS 6.0.0及以上。 + +3. DevEco Studio版本:DevEco Studio 6.0.0及以上。 + +4. HarmonyOS SDK版本:HarmonyOS 6.0.0及以上。 + +### 下载 + +如需单独下载本工程,执行如下命令: + +```` +git init +git config core.sparsecheckout true +echo ArkUIDocSample/TextComponent > .git/info/sparse-checkout +git remote add origin https://gitee.com/harmonyos_samples/guide-snippets.git +git pull origin master +```` \ No newline at end of file diff --git a/ArkUISample/TextComponent/build-profile.json5 b/ArkUISample/TextComponent/build-profile.json5 new file mode 100644 index 0000000000000000000000000000000000000000..15bb241548284cd55b99f7bfdbc63130921e28f2 --- /dev/null +++ b/ArkUISample/TextComponent/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", + "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/ArkUISample/TextComponent/code-linter.json5 b/ArkUISample/TextComponent/code-linter.json5 new file mode 100644 index 0000000000000000000000000000000000000000..28586467ee7a761c737d8654a73aed6fddbc3c71 --- /dev/null +++ b/ArkUISample/TextComponent/code-linter.json5 @@ -0,0 +1,35 @@ +/* + * Copyright (c) 2025 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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": { + } +} \ No newline at end of file diff --git a/ArkUISample/TextComponent/entry/.gitignore b/ArkUISample/TextComponent/entry/.gitignore new file mode 100644 index 0000000000000000000000000000000000000000..e2713a2779c5a3e0eb879efe6115455592caeea5 --- /dev/null +++ b/ArkUISample/TextComponent/entry/.gitignore @@ -0,0 +1,6 @@ +/node_modules +/oh_modules +/.preview +/build +/.cxx +/.test \ No newline at end of file diff --git a/ArkUISample/TextComponent/entry/build-profile.json5 b/ArkUISample/TextComponent/entry/build-profile.json5 new file mode 100644 index 0000000000000000000000000000000000000000..48a79133bba1361549b5b101c1e7c184d136654d --- /dev/null +++ b/ArkUISample/TextComponent/entry/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. + */ + +{ + "apiType": "stageMode", + "buildOption": { + "externalNativeOptions": { + "path": "./src/main/cpp/CMakeLists.txt", + "arguments": "", + "cppFlags": "", + "abiFilters": [ + "x86_64", + "arm64-v8a" + ] + } + }, + "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/ArkUISample/TextComponent/entry/hvigorfile.ts b/ArkUISample/TextComponent/entry/hvigorfile.ts new file mode 100644 index 0000000000000000000000000000000000000000..e4f43d54667f8327c367c8096bd08bb8c75aff54 --- /dev/null +++ b/ArkUISample/TextComponent/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. */ +} diff --git a/ArkUISample/TextComponent/entry/obfuscation-rules.txt b/ArkUISample/TextComponent/entry/obfuscation-rules.txt new file mode 100644 index 0000000000000000000000000000000000000000..272efb6ca3f240859091bbbfc7c5802d52793b0b --- /dev/null +++ b/ArkUISample/TextComponent/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/ArkUISample/TextComponent/entry/oh-package.json5 b/ArkUISample/TextComponent/entry/oh-package.json5 new file mode 100644 index 0000000000000000000000000000000000000000..118bdd4fe7699368a010e04c24f5bfc887cf1298 --- /dev/null +++ b/ArkUISample/TextComponent/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/ArkUISample/TextComponent/entry/src/main/cpp/CMakeLists.txt b/ArkUISample/TextComponent/entry/src/main/cpp/CMakeLists.txt new file mode 100644 index 0000000000000000000000000000000000000000..b5320e1e1747df47b80c52ac3b1dbaa738cb5319 --- /dev/null +++ b/ArkUISample/TextComponent/entry/src/main/cpp/CMakeLists.txt @@ -0,0 +1,15 @@ +# the minimum version of CMake. +cmake_minimum_required(VERSION 3.5.0) +project(TextComponent) + +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) +target_link_libraries(entry PUBLIC libace_napi.z.so libnative_drawing.so libace_ndk.z.so) \ No newline at end of file diff --git a/ArkUISample/TextComponent/entry/src/main/cpp/napi_init.cpp b/ArkUISample/TextComponent/entry/src/main/cpp/napi_init.cpp new file mode 100644 index 0000000000000000000000000000000000000000..03b8bc38c7f21e29ac387679e6be3e894c5a8873 --- /dev/null +++ b/ArkUISample/TextComponent/entry/src/main/cpp/napi_init.cpp @@ -0,0 +1,194 @@ +/* + * Copyright (c) 2025 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#include "napi/native_api.h" +#include "arkui/styled_string.h" +#include "arkui/native_node.h" +#include +#include +#include +#include +#include +#include + +static napi_value CreateNativeNode(napi_env env, napi_callback_info info) +{ + const int fontSize = 28; + const int textSize = 400; + const int maxLines = 10; + size_t argc = 1; + napi_value args[1]; + napi_get_cb_info(env, info, &argc, args, nullptr, nullptr); + + ArkUI_NodeContentHandle rootSlot = nullptr; + OH_ArkUI_GetNodeContentFromNapiValue(env, args[0], &rootSlot); + + ArkUI_NativeNodeAPI_1 *nodeApi = reinterpret_cast( + OH_ArkUI_QueryModuleInterfaceByName(ARKUI_NATIVE_NODE, "ArkUI_NativeNodeAPI_1")); + if (nodeApi == nullptr) { + return nullptr; + } + // 创建一个Column容器组件 + ArkUI_NodeHandle column = nodeApi->createNode(ARKUI_NODE_COLUMN); + ArkUI_NumberValue colWidth[] = {{.f32 = 300}}; + ArkUI_AttributeItem widthItem = {.value = colWidth, .size = 1}; + nodeApi->setAttribute(column, NODE_WIDTH, &widthItem); + // 创建Text组件 + ArkUI_NodeHandle text = nodeApi->createNode(ARKUI_NODE_TEXT); + ArkUI_NumberValue textWidth[] = {{.f32 = 300}}; + ArkUI_AttributeItem textWidthItem = {.value = textWidth, .size = 1}; + nodeApi->setAttribute(text, NODE_WIDTH, &textWidthItem); + + ArkUI_NumberValue textHeight[] = {{.f32 = 100}}; + ArkUI_AttributeItem textHeightItem = {.value = textHeight, .size = 1}; + nodeApi->setAttribute(text, NODE_HEIGHT, &textHeightItem); + + ArkUI_NumberValue borderWidth[] = {{.f32 = 1}}; + ArkUI_AttributeItem borderWidthItem = {.value = borderWidth, .size = 1}; + nodeApi->setAttribute(text, NODE_BORDER_WIDTH, &borderWidthItem); + + // typographyStyle表示段落样式。 + OH_Drawing_TypographyStyle *typographyStyle = OH_Drawing_CreateTypographyStyle(); + // 文字居中显示 + OH_Drawing_SetTypographyTextAlign(typographyStyle, OH_Drawing_TextAlign::TEXT_ALIGN_CENTER); + OH_Drawing_SetTypographyTextMaxLines(typographyStyle, maxLines); + ArkUI_StyledString *styledString = OH_ArkUI_StyledString_Create(typographyStyle, OH_Drawing_CreateFontCollection()); + // 创建文本样式,设置字体和颜色。 + OH_Drawing_TextStyle *textStyle = OH_Drawing_CreateTextStyle(); + OH_Drawing_SetTextStyleFontSize(textStyle, fontSize); + OH_Drawing_SetTextStyleColor(textStyle, OH_Drawing_ColorSetArgb(0xFF, 0x70, 0x70, 0x70)); + // 文本样式的设置有顺序。 + OH_ArkUI_StyledString_PushTextStyle(styledString, textStyle); + OH_ArkUI_StyledString_AddText(styledString, "Hello"); + OH_ArkUI_StyledString_PopTextStyle(styledString); + // 在Hello和World中间插入100x100的占位。 + OH_Drawing_PlaceholderSpan placeHolder{ + .width = 100, + .height = 100, + }; + OH_ArkUI_StyledString_AddPlaceholder(styledString, &placeHolder); + OH_Drawing_TextStyle *worldTextStyle = OH_Drawing_CreateTextStyle(); + OH_Drawing_SetTextStyleFontSize(worldTextStyle, fontSize); + OH_Drawing_SetTextStyleColor(worldTextStyle, OH_Drawing_ColorSetArgb(0xFF, 0x27, 0x87, 0xD9)); + OH_ArkUI_StyledString_PushTextStyle(styledString, worldTextStyle); + OH_ArkUI_StyledString_AddText(styledString, "World!"); + OH_ArkUI_StyledString_PopTextStyle(styledString); + OH_Drawing_Typography *typography = OH_ArkUI_StyledString_CreateTypography(styledString); + OH_Drawing_TypographyLayout(typography, textSize); + ArkUI_AttributeItem styledStringItem = {.object = styledString}; + nodeApi->setAttribute(text, NODE_TEXT_CONTENT_WITH_STYLED_STRING, &styledStringItem); + + OH_ArkUI_StyledString_Destroy(styledString); + // Text作为Column子组件 + nodeApi->addChild(column, text); + OH_ArkUI_NodeContent_AddNode(rootSlot, column); + return nullptr; +} +static napi_value CreateTextAreaNode(napi_env env, napi_callback_info info) +{ + size_t argc = 1; + napi_value args[1]; + napi_get_cb_info(env, info, &argc, args, nullptr, nullptr); + + ArkUI_NodeContentHandle rootSlot = nullptr; + OH_ArkUI_GetNodeContentFromNapiValue(env, args[0], &rootSlot); + + ArkUI_NativeNodeAPI_1 *nodeApi = reinterpret_cast( + OH_ArkUI_QueryModuleInterfaceByName(ARKUI_NATIVE_NODE, "ArkUI_NativeNodeAPI_1")); + if (nodeApi == nullptr) { + return nullptr; + } + ArkUI_NodeHandle column = nodeApi->createNode(ARKUI_NODE_COLUMN); + ArkUI_NumberValue colWidth[] = {{.f32 = 300}}; + ArkUI_AttributeItem widthItem = {.value = colWidth, .size = 1}; + nodeApi->setAttribute(column, NODE_WIDTH, &widthItem); + + ArkUI_NodeHandle text = nodeApi->createNode(ARKUI_NODE_TEXT); + ArkUI_NumberValue textWidth[] = {{.f32 = 300}}; + ArkUI_AttributeItem textWidthItem = {.value = textWidth, .size = 1}; + nodeApi->setAttribute(text, NODE_WIDTH, &textWidthItem); + nodeApi->addChild(column, text); + + ArkUI_NodeHandle selectionText = nodeApi->createNode(ARKUI_NODE_TEXT); + ArkUI_NumberValue selectionTextWidth[] = {{.f32 = 300}}; + ArkUI_AttributeItem selectionTextWidthItem = {.value = selectionTextWidth, .size = 1}; + nodeApi->setAttribute(selectionText, NODE_WIDTH, &selectionTextWidthItem); + nodeApi->addChild(column, selectionText); + + ArkUI_NodeHandle textArea = nodeApi->createNode(ARKUI_NODE_TEXT_AREA); + ArkUI_NumberValue textAreaWidth[] = {{.f32 = 300}}; + ArkUI_AttributeItem textAreaWidthItem = {.value = textAreaWidth, .size = 1}; + nodeApi->setAttribute(textArea, NODE_WIDTH, &textAreaWidthItem); + + ArkUI_NumberValue borderWidth[] = {{.f32 = 1}}; + ArkUI_AttributeItem borderWidthItem = {.value = borderWidth, .size = 1}; + nodeApi->setAttribute(textArea, NODE_BORDER_WIDTH, &borderWidthItem); + + const ArkUI_AttributeItem *attributeItem = nodeApi->getAttribute(textArea, NODE_UNIQUE_ID); + auto id = attributeItem->value[0].i32; + nodeApi->registerNodeEvent(textArea, NODE_TEXT_AREA_ON_CHANGE, id, text); + nodeApi->registerNodeEvent(textArea, NODE_TEXT_AREA_ON_PASTE, id, text); + nodeApi->registerNodeEvent(textArea, NODE_TEXT_AREA_ON_TEXT_SELECTION_CHANGE, id, selectionText); + nodeApi->registerNodeEventReceiver([](ArkUI_NodeEvent *event) { + ArkUI_NodeEventType eventType = OH_ArkUI_NodeEvent_GetEventType(event); + ArkUI_AttributeItem content; + if (eventType == NODE_TEXT_AREA_ON_CHANGE || eventType == NODE_TEXT_AREA_ON_PASTE) { + ArkUI_StringAsyncEvent *stringEvent = OH_ArkUI_NodeEvent_GetStringAsyncEvent(event); + content = {.string = stringEvent->pStr }; + } else if (eventType == NODE_TEXT_AREA_ON_TEXT_SELECTION_CHANGE) { + ArkUI_NodeComponentEvent *componentEvent = OH_ArkUI_NodeEvent_GetNodeComponentEvent(event); + std::stringstream selectContent; + selectContent << "start: " << componentEvent->data[0].i32 << " , end: " << componentEvent->data[1].i32; + content = {.string = selectContent.str().c_str() }; + } else { + return; + } + ArkUI_NodeHandle textNode = reinterpret_cast(OH_ArkUI_NodeEvent_GetUserData(event)); + if (textNode) { + ArkUI_NativeNodeAPI_1 *nodeApi = reinterpret_cast( + OH_ArkUI_QueryModuleInterfaceByName(ARKUI_NATIVE_NODE, "ArkUI_NativeNodeAPI_1")); + nodeApi->setAttribute(textNode, NODE_TEXT_CONTENT, &content); + } + }); + nodeApi->addChild(column, textArea); + OH_ArkUI_NodeContent_AddNode(rootSlot, column); + return nullptr; +} + +EXTERN_C_START +static napi_value Init(napi_env env, napi_value exports) +{ + napi_property_descriptor desc[] = { + { "createNativeNode", nullptr, CreateNativeNode, nullptr, nullptr, nullptr, napi_default, nullptr }, + { "createTextAreaNode", nullptr, CreateTextAreaNode, 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); +} diff --git a/ArkUISample/TextComponent/entry/src/main/cpp/types/libentry/index.d.ts b/ArkUISample/TextComponent/entry/src/main/cpp/types/libentry/index.d.ts new file mode 100644 index 0000000000000000000000000000000000000000..d0214ce4ff991fa8b6662fab9ac34a8437956901 --- /dev/null +++ b/ArkUISample/TextComponent/entry/src/main/cpp/types/libentry/index.d.ts @@ -0,0 +1,17 @@ +/* + * Copyright (c) 2025 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +export const createNativeNode: (content: Object) => void; +export const createTextAreaNode: (content: Object) => void; \ No newline at end of file diff --git a/ArkUISample/TextComponent/entry/src/main/cpp/types/libentry/oh-package.json5 b/ArkUISample/TextComponent/entry/src/main/cpp/types/libentry/oh-package.json5 new file mode 100644 index 0000000000000000000000000000000000000000..2826cc7d6bd199c1008bb51d898dffa922201e6c --- /dev/null +++ b/ArkUISample/TextComponent/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/ArkUISample/TextComponent/entry/src/main/ets/common/Card.ets b/ArkUISample/TextComponent/entry/src/main/ets/common/Card.ets new file mode 100644 index 0000000000000000000000000000000000000000..8a5d71ab7914f99cbbfac51282bceff22857dad8 --- /dev/null +++ b/ArkUISample/TextComponent/entry/src/main/ets/common/Card.ets @@ -0,0 +1,137 @@ +/* + * Copyright (c) 2025 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +@Component +export struct CompletedRoutableCard { + @Prop + symbol: Resource = $r('sys.symbol.label'); + @Prop + @Require + title: string; + @Prop + @Require + description: ResourceStr; + + build() { + Card({ verticalAlign: VerticalAlign.Top }) { + Button({ type: ButtonType.Circle }) { + SymbolGlyph(this.symbol) + .fontColor(['#fff']) + .fontSize(16) + } + .borderRadius(14) + + Column({ space: 8 }) { + Text(this.title) + .fontColor($r('sys.color.font_primary')) + + Text(this.description) + .fontColor($r('sys.color.font_secondary')) + .fontSize($r('sys.float.Body_S')) + } + .alignItems(HorizontalAlign.Start) + .layoutWeight(1) + } + } +} + +@Component +export struct Card { + @Prop + verticalAlign: VerticalAlign = VerticalAlign.Center; + @BuilderParam + content: () => void; + + build() { + Row({ space: 12 }) { + this.content() + } + .alignItems(this.verticalAlign) + .backgroundColor('#fff') + .borderRadius(12) + .padding(12) + .width('100%') + } +} + +@Component +export struct RoutableCard { + @Prop + icon: Resource = $r('sys.symbol.label'); + @Prop + @Require + title: ResourceStr; + + build() { + Card() { + Button({ type: ButtonType.Circle }) { + SymbolGlyph(this.icon) + .fontColor(['#fff']) + .fontSize(16) + } + .borderRadius(14) + + Text(this.title) + .fontColor($r('sys.color.font_primary')) + .minFontSize(12) + .maxFontSize(16) + .maxLines(1) + .textOverflow({ overflow: TextOverflow.Ellipsis }) + + Blank() + + Button({ type: ButtonType.Normal, buttonStyle: ButtonStyleMode.TEXTUAL }) { + SymbolGlyph($r('sys.symbol.chevron_right')) + .fontSize(18) + .fontColor([$r('sys.color.font_secondary')]) + } + } + } +} + +@Component +export struct ComponentCard { + @Prop + title?: ResourceStr; + @BuilderParam content: () => void; + @Prop + description?: ResourceStr; + + build() { + Column({ space: 8 }) { + Text(this.title) + .fontSize(14) + .fontColor('#666') + Row({ space: 12 }) { + this.content(); + } + + if (this.description) { + Text(this.description) + .backgroundColor('#eee') + .borderRadius(4) + .padding(4) + .fontSize(12) + .fontColor('#999') + .width('100%') + } + } + .alignItems(HorizontalAlign.Start) + .backgroundColor('#fff') + .borderRadius(12) + .padding(12) + .width('100%') + } +} \ No newline at end of file diff --git a/ArkUISample/TextComponent/entry/src/main/ets/common/Route.ets b/ArkUISample/TextComponent/entry/src/main/ets/common/Route.ets new file mode 100644 index 0000000000000000000000000000000000000000..859fec8c9ebd491e575d5baf8d43bd0512add60c --- /dev/null +++ b/ArkUISample/TextComponent/entry/src/main/ets/common/Route.ets @@ -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. + */ + +export interface Route { + title: string; + name: string; + items?: Route[]; + description?: ResourceStr; +} \ No newline at end of file diff --git a/ArkUISample/TextComponent/entry/src/main/ets/common/resource.ets b/ArkUISample/TextComponent/entry/src/main/ets/common/resource.ets new file mode 100644 index 0000000000000000000000000000000000000000..e240a1079ad09a0f19080b49b57a6a0720416e6c --- /dev/null +++ b/ArkUISample/TextComponent/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 ResourceManager { + public resourceToString(resource: Resource): string { + return getContext(this).resourceManager.getStringSync(resource); + } +} + +// 默认导出let +let resourceToStringManager = new ResourceManager(); + +export default resourceToStringManager as ResourceManager; \ No newline at end of file diff --git a/ArkUISample/TextComponent/entry/src/main/ets/entryability/EntryAbility.ets b/ArkUISample/TextComponent/entry/src/main/ets/entryability/EntryAbility.ets new file mode 100644 index 0000000000000000000000000000000000000000..f85e945903c56eec3b80c0e60f8efd688b7555e2 --- /dev/null +++ b/ArkUISample/TextComponent/entry/src/main/ets/entryability/EntryAbility.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. + */ + +import { AbilityConstant, ConfigurationConstant, UIAbility, Want } from '@kit.AbilityKit'; +import { hilog } from '@kit.PerformanceAnalysisKit'; +import { window } from '@kit.ArkUI'; +import { KeyboardAvoidMode } from '@kit.ArkUI'; + +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(0x0000, 'testTag', '%{public}s', 'Ability onCreate'); + } + + onDestroy(): void { + hilog.info(0x0000, 'testTag', '%{public}s', 'Ability onDestroy'); + } + + onWindowStageCreate(windowStage: window.WindowStage): void { + // Main window is created, set main page for this ability + hilog.info(0x0000, 'testTag', '%{public}s', 'Ability onWindowStageCreate'); + + windowStage.loadContent('pages/Index', (err, data) => { + let keyboardAvoidMode = windowStage.getMainWindowSync().getUIContext().getKeyboardAvoidMode(); + windowStage.getMainWindowSync().getUIContext().setKeyboardAvoidMode(KeyboardAvoidMode.OFFSET_WITH_CARET); + if (err.code) { + hilog.error(0x0000, 'testTag', 'Failed to load the content. Cause: %{public}s', JSON.stringify(err) ?? ''); + return; + } + hilog.info(0x0000, 'testTag', 'Succeeded in loading the content. Data: %{public}s', JSON.stringify(data) ?? ''); + }); + } + + onWindowStageDestroy(): void { + // Main window is destroyed, release UI related resources + hilog.info(0x0000, 'testTag', '%{public}s', 'Ability onWindowStageDestroy'); + } + + onForeground(): void { + // Ability has brought to foreground + hilog.info(0x0000, 'testTag', '%{public}s', 'Ability onForeground'); + } + + onBackground(): void { + // Ability has back to background + hilog.info(0x0000, 'testTag', '%{public}s', 'Ability onBackground'); + } +} \ No newline at end of file diff --git a/ArkUISample/TextComponent/entry/src/main/ets/entrybackupability/EntryBackupAbility.ets b/ArkUISample/TextComponent/entry/src/main/ets/entrybackupability/EntryBackupAbility.ets new file mode 100644 index 0000000000000000000000000000000000000000..b1e212947256c5533c7b06285a597c94f840a6e3 --- /dev/null +++ b/ArkUISample/TextComponent/entry/src/main/ets/entrybackupability/EntryBackupAbility.ets @@ -0,0 +1,27 @@ +/* + * Copyright (c) 2025 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { hilog } from '@kit.PerformanceAnalysisKit'; +import { BackupExtensionAbility, BundleVersion } from '@kit.CoreFileKit'; + +export default class EntryBackupAbility extends BackupExtensionAbility { + async onBackup() { + hilog.info(0x0000, 'testTag', 'onBackup ok'); + } + + async onRestore(bundleVersion: BundleVersion) { + hilog.info(0x0000, 'testTag', 'onRestore ok %{public}s', JSON.stringify(bundleVersion)); + } +} \ No newline at end of file diff --git a/ArkUISample/TextComponent/entry/src/main/ets/pages/Index.ets b/ArkUISample/TextComponent/entry/src/main/ets/pages/Index.ets new file mode 100644 index 0000000000000000000000000000000000000000..0b620e6fb514d704192770e5dca477ddc72588e1 --- /dev/null +++ b/ArkUISample/TextComponent/entry/src/main/ets/pages/Index.ets @@ -0,0 +1,124 @@ +/* + * Copyright (c) 2025 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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'; +import { RoutableCard } from '../common/Card'; +import { Route } from '../common/Route'; +import { TextDestination, TEXT_ROUTE_PREFIX } from './text'; +import { TextInputDestination, INPUT_ROUTE_PREFIX } from './textInput'; +import { RichEditorDestination, RICH_EDITOR_ROUTE_PREFIX } from './richEditor'; +import { SymbolGlyphSpanDestination, SYMBOL_GLYPH_SPAN } from './symbol'; +import { PropertyStringDestination, PROPERTY_STRING_ROUTE_PREFIX } from './propertyString'; +import { NDKDestination, NDK_ROUTE_PREFIX } from './ndk'; +import resource from '../common/resource'; + +const routes: Route[] = [ + { + title: resource.resourceToString($r('app.string.pageIndex_Text')), + name: TEXT_ROUTE_PREFIX + }, + { + title: resource.resourceToString($r('app.string.pageIndex_TextInput')), + name: INPUT_ROUTE_PREFIX + }, + { + title: resource.resourceToString($r('app.string.pageIndex_RichEditor')), + name: RICH_EDITOR_ROUTE_PREFIX + }, + { + title: resource.resourceToString($r('app.string.pageIndex_symbolGlyphSpan')), + name: SYMBOL_GLYPH_SPAN + }, + { + title: resource.resourceToString($r('app.string.pageIndex_PropertyString')), + name: PROPERTY_STRING_ROUTE_PREFIX + }, + { + title: resource.resourceToString($r('app.string.pageIndex_TextNDKUI')), + name: NDK_ROUTE_PREFIX + } +]; + +@Builder +function Destination(name: string) { + if (name.startsWith(TEXT_ROUTE_PREFIX)) { + TextDestination(name); + } else if (name.startsWith(INPUT_ROUTE_PREFIX)) { + TextInputDestination(name); + } else if (name.startsWith(RICH_EDITOR_ROUTE_PREFIX)) { + RichEditorDestination(name); + } else if (name.startsWith(SYMBOL_GLYPH_SPAN)) { + SymbolGlyphSpanDestination(name); + } else if (name.startsWith(PROPERTY_STRING_ROUTE_PREFIX)) { + PropertyStringDestination(name); + }else if (name.startsWith(NDK_ROUTE_PREFIX)) { + NDKDestination(name); + } +} + +@Entry +@Component +struct Index { + @State condition: string = ''; + @Provide pathStack: NavPathStack = new NavPathStack(); + + getFilteredRoutes(): Route[] { + if (!this.condition) { + return routes; + } + return routes.filter((route: Route) => { + return route.title.includes(this.condition); + }) + } + + @LocalBuilder + Title() { + Column() { + Search({ value: this.condition }) + .onChange(value => { + this.condition = value; + }) + .margin({ start: LengthMetrics.vp(16), end: LengthMetrics.vp(16) }) + } + .justifyContent(FlexAlign.Center) + .height('100%') + } + + build() { + Navigation(this.pathStack) { + List({ space: 12 }) { + ForEach(this.getFilteredRoutes(), (route: Route) => { + ListItem() { + RoutableCard({ title: route.title }) + } + .width('100%') + .onClick(() => { + this.pathStack.pushPath({ name: route.name }); + }) + }) + } + .padding({ start: LengthMetrics.vp(16), end: LengthMetrics.vp(16) }) + .contentStartOffset(56) + .height('100%') + .width('100%') + } + .backgroundColor('#f1f3f5') + .title({ builder: this.Title, height: 56 }, { + backgroundBlurStyle: BlurStyle.COMPONENT_THICK, + barStyle: BarStyle.STACK + }) + .navDestination(Destination) + } +} \ No newline at end of file diff --git a/ArkUISample/TextComponent/entry/src/main/ets/pages/ndk/ListenTextBoxEvents.ets b/ArkUISample/TextComponent/entry/src/main/ets/pages/ndk/ListenTextBoxEvents.ets new file mode 100644 index 0000000000000000000000000000000000000000..ce81dd4ab61dc243e136f81cec83727d3d28cb5d --- /dev/null +++ b/ArkUISample/TextComponent/entry/src/main/ets/pages/ndk/ListenTextBoxEvents.ets @@ -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. + */ + +import nativeNode from 'libentry.so'; +import { NodeContent } from '@kit.ArkUI'; + +@Entry +@Component +export struct ListenTextBoxEvents { + // 初始化NodeContent对象。 + private rootSlot = new NodeContent(); + + aboutToAppear(): void { + // 通过C-API创建节点,并添加到管理器nodeContent上 + nativeNode.createTextAreaNode(this.rootSlot); + } + + build() { + NavDestination() { + Column() { + Row() { + // 将NodeContent和ContentSlot占位组件绑定。 + ContentSlot(this.rootSlot) + }.layoutWeight(1) + } + .width('100%') + .height('100%') + }.title($r('app.string.ListenTextBoxEvents_NDK_title')) + } +} \ No newline at end of file diff --git a/ArkUISample/TextComponent/entry/src/main/ets/pages/ndk/TextDrawingDisplay.ets b/ArkUISample/TextComponent/entry/src/main/ets/pages/ndk/TextDrawingDisplay.ets new file mode 100644 index 0000000000000000000000000000000000000000..93eeefd62d1893a836bfd3e3d88950d66ad78995 --- /dev/null +++ b/ArkUISample/TextComponent/entry/src/main/ets/pages/ndk/TextDrawingDisplay.ets @@ -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. + */ + +import nativeNode from 'libentry.so'; +import { NodeContent } from '@kit.ArkUI'; + +@Entry +@Component +export struct TextDrawingDisplay { + // 初始化NodeContent对象。 + private rootSlot = new NodeContent(); + + aboutToAppear(): void { + // 通过C-API创建节点,并添加到管理器nodeContent上 + nativeNode.createNativeNode(this.rootSlot); + } + + build() { + NavDestination() { + Column() { + Row() { + // 将NodeContent和ContentSlot占位组件绑定。 + ContentSlot(this.rootSlot) + }.layoutWeight(1) + } + .width('100%') + .height('100%') + }.title($r('app.string.TextDrawingDisplay_NDK_title')) + } +} \ No newline at end of file diff --git a/ArkUISample/TextComponent/entry/src/main/ets/pages/ndk/index.ets b/ArkUISample/TextComponent/entry/src/main/ets/pages/ndk/index.ets new file mode 100644 index 0000000000000000000000000000000000000000..d23cff77df6ffa3d4d156f6722cd9fa8dcdf794a --- /dev/null +++ b/ArkUISample/TextComponent/entry/src/main/ets/pages/ndk/index.ets @@ -0,0 +1,75 @@ +/* + * Copyright (c) 2025 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { CompletedRoutableCard } from '../../common/Card'; +import resource from '../../common/resource'; +import { Route } from '../../common/Route'; +import { ListenTextBoxEvents } from './ListenTextBoxEvents'; +import { TextDrawingDisplay } from './TextDrawingDisplay'; + +export const NDK_ROUTE_PREFIX: string = 'ndk'; + +const routes: Route[] = [ + { + name: `${NDK_ROUTE_PREFIX}/TextDrawingDisplay`, + title: resource.resourceToString($r('app.string.TextDrawingDisplay_NDK_title')), + description: $r('app.string.TextDrawingDisplay_NDK_desc') + }, + { + name: `${NDK_ROUTE_PREFIX}/ListenTextBoxEvents`, + title: resource.resourceToString($r('app.string.ListenTextBoxEvents_NDK_title')), + description: $r('app.string.ListenTextBoxEvents_NDK_desc') + } +]; + +@Builder +export function NDKDestination(name: string) { + if (name === NDK_ROUTE_PREFIX) { + NDKExample(); + } else if (name === routes[0].name) { + TextDrawingDisplay(); + } else if (name === routes[1].name) { + ListenTextBoxEvents(); + } +} + +@Entry +@Component +struct NDKExample { + @Consume pathStack: NavPathStack; + + build() { + NavDestination() { + List({ space: 12 }) { + ForEach(routes, (route: Route) => { + ListItem() { + CompletedRoutableCard({ title: route.title, description: route.description }) + } + .width('100%') + .onClick(() => { + this.pathStack.pushPath({ name: route.name }); + }) + }) + } + .contentStartOffset(56) + .padding({ left: 16, right: 16 }) + } + .backgroundColor('#f1f3f5') + .title($r('app.string.pageIndex_TextNDKUI'), { + backgroundBlurStyle: BlurStyle.COMPONENT_THICK, + barStyle: BarStyle.STACK + }) + } +} \ No newline at end of file diff --git a/ArkUISample/TextComponent/entry/src/main/ets/pages/propertyString/CreateApply.ets b/ArkUISample/TextComponent/entry/src/main/ets/pages/propertyString/CreateApply.ets new file mode 100644 index 0000000000000000000000000000000000000000..6edcb481112deadf731e283604dc80101aeaa9e6 --- /dev/null +++ b/ArkUISample/TextComponent/entry/src/main/ets/pages/propertyString/CreateApply.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. + */ + +import resource from '../../common/resource'; + +@Entry +@Component +struct styled_string_demo1 { + styledString1: StyledString = new StyledString(resource.resourceToString($r('app.string.CreateApply_Text_1'))); + mutableStyledString1: MutableStyledString = new MutableStyledString(resource.resourceToString($r('app.string.CreateApply_Text_2'))); + controller1: TextController = new TextController(); + controller2: TextController = new TextController(); + + async onPageShow() { + // 在生命周期onPageShow回调中绑定属性字符串 + this.controller1.setStyledString(this.styledString1); + } + + build() { + Column() { + // 显示属性字符串 + Text(undefined, { controller: this.controller1 }) + Text(undefined, { controller: this.controller2 }) + .onAppear(() => { + // 在组件onAppear回调中绑定属性字符串 + this.controller2.setStyledString(this.mutableStyledString1); + }) + } + .width('100%') + } +} \ No newline at end of file diff --git a/ArkUISample/TextComponent/entry/src/main/ets/pages/propertyString/StyledStringGestureStyle.ets b/ArkUISample/TextComponent/entry/src/main/ets/pages/propertyString/StyledStringGestureStyle.ets new file mode 100644 index 0000000000000000000000000000000000000000..5438ae04c7b9d5af479f8cf00526694c7e162400 --- /dev/null +++ b/ArkUISample/TextComponent/entry/src/main/ets/pages/propertyString/StyledStringGestureStyle.ets @@ -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. + */ + +import { ComponentCard } from '../../common/Card'; +import { drawing } from '@kit.ArkGraphics2D'; + +let gUIContext: UIContext; + +class MyCustomSpan extends CustomSpan { + constructor(word: string, width: number, height: number, fontSize: number) { + super(); + this.word = word; + this.width = width; + this.height = height; + this.fontSize = fontSize; + } + + onMeasure(measureInfo: CustomSpanMeasureInfo): CustomSpanMetrics { + return { width: this.width, height: this.height }; + } + + onDraw(context: DrawContext, options: CustomSpanDrawInfo) { + let canvas = context.canvas; + + const brush = new drawing.Brush(); + brush.setColor({ + alpha: 255, + red: 0, + green: 0, + blue: 0 + }); + const font = new drawing.Font(); + font.setSize(gUIContext.vp2px(this.fontSize)); + const textBlob = + drawing.TextBlob.makeFromString(this.word.substring(0, 5), font, drawing.TextEncoding.TEXT_ENCODING_UTF8); + canvas.attachBrush(brush); + + this.onDrawRectByRadius(context, options.x, options.x + gUIContext.vp2px(this.width), options.lineTop, + options.lineBottom, 20); + brush.setColor({ + alpha: 255, + red: 255, + green: 255, + blue: 255 + }); + canvas.attachBrush(brush); + canvas.drawTextBlob(textBlob, options.x, options.lineBottom - 30); + brush.setColor({ + alpha: 255, + red: 255, + green: 228, + blue: 196 + }); + canvas.attachBrush(brush); + const textBlob1 = + drawing.TextBlob.makeFromString(this.word.substring(5), font, drawing.TextEncoding.TEXT_ENCODING_UTF8); + canvas.drawTextBlob(textBlob1, options.x + gUIContext.vp2px(100), options.lineBottom - 30); + + canvas.detachBrush(); + } + + onDrawRectByRadius(context: DrawContext, left: number, right: number, top: number, bottom: number, radius: number) { + let canvas = context.canvas; + let path = new drawing.Path(); + + // 画带radius的rect + path.moveTo(left + radius, top); + path.lineTo(right - radius, top); + path.arcTo(right - 2 * radius, top, right, top + 2 * radius, 270, 90); + path.lineTo(right, bottom - radius); + path.arcTo(right - 2 * radius, bottom - 2 * radius, right, bottom, 0, 90); + + path.lineTo(left + 2 * radius, bottom); + path.arcTo(left, bottom - 2 * radius, left + 2 * radius, bottom, 90, 90); + path.lineTo(left, top + 2 * radius); + path.arcTo(left, top, left + 2 * radius, top + 2 * radius, 180, 90); + + canvas.drawPath(path); + } + + setWord(word: string) { + this.word = word; + } + + public width: number = 160; + public word: string = 'drawing'; + public height: number = 10; + public fontSize: number = 16; +} + +@Entry +@Component +export struct StyledStringGestureStyle { + customSpan3: MyCustomSpan = new MyCustomSpan('99VIP88%off', 200, 40, 30); + customSpanStyledString: MutableStyledString = new MutableStyledString(this.customSpan3); + textController: TextController = new TextController(); + isPageShow: boolean = true; + @State backgroundColor1: ResourceColor | undefined = undefined; + gestureStyleAttr: GestureStyle = new GestureStyle({ + onClick: () => { + this.backgroundColor1 = Color.Green; + }, + onLongPress: () => { + this.backgroundColor1 = Color.Grey; + } + }); + + aboutToAppear() { + gUIContext = this.getUIContext(); + } + + async onPageShow() { + if (!this.isPageShow) { + return; + } + this.isPageShow = false; + this.customSpanStyledString.setStyle({ + start: 0, + length: 1, + styledKey: StyledStringKey.GESTURE, + styledValue: this.gestureStyleAttr + }) + this.textController.setStyledString(this.customSpanStyledString); + } + + build() { + NavDestination() { + Column({ space: 12 }) { + ComponentCard({ title: $r('app.string.TStyledStringGestureStyle_title') }) { + // [Start styled_string_gesture_style] + Row() { + Column() { + Button($r('app.string.StyledStringGestureStyle_button_content')).backgroundColor(this.backgroundColor1).width('80%').margin(10) + Text(undefined, { controller: this.textController }) + .id('text1') + .copyOption(CopyOptions.InApp) + .fontSize(30) + } + .width('100%') + } + .height('100%') + // [End styled_string_gesture_style] + } + } + .width('100%') + .height('100%') + .padding({ left: 12, right: 12 }) + } + .backgroundColor('#f1f2f3') + .title($r('app.string.TStyledStringGestureStyle_title')) + } +} \ No newline at end of file diff --git a/ArkUISample/TextComponent/entry/src/main/ets/pages/propertyString/StyledStringHtml.ets b/ArkUISample/TextComponent/entry/src/main/ets/pages/propertyString/StyledStringHtml.ets new file mode 100644 index 0000000000000000000000000000000000000000..4d5eb81cf975b7867a933b584e01fc66ec7a0c8b --- /dev/null +++ b/ArkUISample/TextComponent/entry/src/main/ets/pages/propertyString/StyledStringHtml.ets @@ -0,0 +1,98 @@ +/* + * Copyright (c) 2025 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 { ComponentCard } from '../../common/Card'; +import { image } from '@kit.ImageKit'; +import { LengthMetrics } from '@kit.ArkUI'; +import resource from '../../common/resource'; + +@Entry +@Component +export struct StyledStringHtml { + imagePixelMap: image.PixelMap | undefined = undefined; + @State html: string | undefined = undefined; + @State styledString: StyledString | undefined = undefined; + controller1: TextController = new TextController; + controller2: TextController = new TextController; + private uiContext: UIContext = this.getUIContext(); + + async aboutToAppear() { + console.info('aboutToAppear initial imagePixelMap'); + this.imagePixelMap = await this.getPixmapFromMedia($r('app.media.startIcon')); + } + + private async getPixmapFromMedia(resource: Resource) { + let unit8Array = await this.uiContext.getHostContext()?.resourceManager?.getMediaContent({ + bundleName: resource.bundleName, + moduleName: resource.moduleName, + id: resource.id + }); + let imageSource = image.createImageSource(unit8Array?.buffer.slice(0, unit8Array.buffer.byteLength)); + let createPixelMap: image.PixelMap = await imageSource.createPixelMap({ + desiredPixelFormat: image.PixelMapFormat.RGBA_8888 + }); + await imageSource.release(); + return createPixelMap; + } + + build() { + NavDestination() { + Column({ space: 12 }) { + ComponentCard({ title: $r('app.string.StyledStringHtml_title') }) { + // [Start styled_string_html] + Column() { + Text(undefined, { controller: this.controller1 }).height(100).id('text1') + Row() { + Button($r('app.string.StyledStringHtml_Button_1')).onClick(() => { + let mutableStyledString1: MutableStyledString = + new MutableStyledString(resource.resourceToString($r('app.string.StyledStringHtml_Text_1')), [{ + start: 0, + length: 6, + styledKey: StyledStringKey.FONT, + styledValue: new TextStyle({ fontColor: Color.Green, fontSize: LengthMetrics.px(50) }) + }]); + if (this.imagePixelMap !== undefined) { + let mutableStyledString2 = new MutableStyledString(new ImageAttachment({ + value: this.imagePixelMap, + size: { width: 50, height: 50 }, + })); + mutableStyledString1.appendStyledString(mutableStyledString2); + } + this.styledString = mutableStyledString1; + this.controller1.setStyledString(mutableStyledString1); + }).margin(5) + Button($r('app.string.StyledStringHtml_Button_2')).onClick(() => { + this.html = StyledString.toHtml(this.styledString); + }).margin(5) + Button($r('app.string.StyledStringHtml_Button_3')).onClick(async () => { + let styledString = await StyledString.fromHtml(this.html); + this.controller2.setStyledString(styledString); + }).margin(5) + } + + Text(undefined, { controller: this.controller2 }).height(100).id('text2') + Text(this.html).id('text3') + }.width('100%') + // [End styled_string_html] + } + } + .width('100%') + .height('100%') + .padding({ left: 12, right: 12 }) + } + .backgroundColor('#f1f2f3') + .title($r('app.string.StyledStringHtml_title')) + } +} \ No newline at end of file diff --git a/ArkUISample/TextComponent/entry/src/main/ets/pages/propertyString/StyledStringImageAttachment.ets b/ArkUISample/TextComponent/entry/src/main/ets/pages/propertyString/StyledStringImageAttachment.ets new file mode 100644 index 0000000000000000000000000000000000000000..c07afa4b0ae9e4d53971d006446482415e079f51 --- /dev/null +++ b/ArkUISample/TextComponent/entry/src/main/ets/pages/propertyString/StyledStringImageAttachment.ets @@ -0,0 +1,184 @@ +/* + * Copyright (c) 2025 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 { ComponentCard } from '../../common/Card'; +import { image } from '@kit.ImageKit'; +import { LengthMetrics } from '@kit.ArkUI'; +import resource from '../../common/resource'; + +@Entry +@Component +export struct StyledStringImageAttachment { + @State abled: boolean = true; + @State message: string = 'Hello World'; + imagePixelMap: image.PixelMap | undefined = undefined; + @State imagePixelMap3: image.PixelMap | undefined = undefined; + mutableStr: MutableStyledString = new MutableStyledString('123'); + controller: TextController = new TextController(); + mutableStr2: MutableStyledString = new MutableStyledString('This is set decoration line style to the mutableStr2', [{ + start: 0, + length: 15, + styledKey: StyledStringKey.DECORATION, + styledValue: new DecorationStyle({ + type: TextDecorationType.Overline, + color: Color.Orange, + style: TextDecorationStyle.DOUBLE + }) + }]); + + async aboutToAppear() { + console.info('aboutToAppear initial imagePixelMap'); + this.imagePixelMap = await this.getPixmapFromMedia($r('app.media.startIcon')); + } + + private async getPixmapFromMedia(resource: Resource) { + let unit8Array = await this.getUIContext().getHostContext()?.resourceManager?.getMediaContent({ + bundleName: resource.bundleName, + moduleName: resource.moduleName, + id: resource.id + }); + let imageSource = image.createImageSource(unit8Array?.buffer?.slice(0, unit8Array?.buffer?.byteLength)); + let createPixelMap: image.PixelMap = await imageSource.createPixelMap({ + desiredPixelFormat: image.PixelMapFormat.RGBA_8888 + }); + await imageSource.release(); + return createPixelMap; + } + + leadingMarginValue: ParagraphStyle = new ParagraphStyle({ leadingMargin: LengthMetrics.vp(5)}); + //行高样式对象 + lineHeightStyle1: LineHeightStyle= new LineHeightStyle(new LengthMetrics(24)); + //Bold样式 + boldTextStyle: TextStyle = new TextStyle({ fontWeight: FontWeight.Bold }); + //创建含段落样式的对象paragraphStyledString1 + paragraphStyledString1: MutableStyledString = + new MutableStyledString(resource.resourceToString($r('app.string.StyledStringImageAttachment_Text_1')), [ + { + start: 0, + length: 28, + styledKey: StyledStringKey.PARAGRAPH_STYLE, + styledValue: this.leadingMarginValue + }, + { + start: 14, + length: 9, + styledKey: StyledStringKey.FONT, + styledValue: new TextStyle({ fontSize: LengthMetrics.vp(14), fontColor: '#B22222' }) + }, + { + start: 24, + length: 4, + styledKey: StyledStringKey.FONT, + styledValue: new TextStyle({ fontSize: LengthMetrics.vp(14), fontWeight: FontWeight.Lighter }) + }, + { + start: 11, + length: 4, + styledKey: StyledStringKey.LINE_HEIGHT, + styledValue: this.lineHeightStyle1 + } + ]); + paragraphStyledString2: MutableStyledString = + new MutableStyledString(resource.resourceToString($r('app.string.StyledStringImageAttachment_Text_2')), [ + { + start: 0, + length: 5, + styledKey: StyledStringKey.PARAGRAPH_STYLE, + styledValue: this.leadingMarginValue + }, + { + start: 0, + length: 4, + styledKey: StyledStringKey.LINE_HEIGHT, + styledValue: new LineHeightStyle(new LengthMetrics(60)) + }, + { + start: 0, + length: 7, + styledKey: StyledStringKey.FONT, + styledValue: this.boldTextStyle + }, + { + start: 1, + length: 1, + styledKey: StyledStringKey.FONT, + styledValue: new TextStyle({ fontSize: LengthMetrics.vp(18) }) + }, + { + start: 2, + length: 2, + styledKey: StyledStringKey.FONT, + styledValue: new TextStyle({ fontSize: LengthMetrics.vp(36) }) + }, + { + start: 4, + length: 3, + styledKey: StyledStringKey.FONT, + styledValue: new TextStyle({ fontSize: LengthMetrics.vp(20) }) + }, + { + start: 7, + length: 9, + styledKey: StyledStringKey.FONT, + styledValue: new TextStyle({ fontColor: Color.Grey, fontSize: LengthMetrics.vp(14)}) + } + ]); + + build() { + NavDestination() { + Column({ space: 12 }) { + ComponentCard({ title: $r('app.string.StyledStringImageAttachment_title') }) { + // [Start styled_string_image_attachment] + Row() { + Column({ space: 10 }) { + Text(undefined, { controller: this.controller }) + .id('text1') + .copyOption(CopyOptions.InApp) + .draggable(true) + .backgroundColor('#FFFFFF') + .borderRadius(5) + + Button($r('app.string.StyledStringImageAttachment_Button_1')) + .enabled(this.abled) + .onClick(() => { + if (this.imagePixelMap !== undefined) { + this.mutableStr = new MutableStyledString(new ImageAttachment({ + value: this.imagePixelMap, + size: { width: 180, height: 160 }, + verticalAlign: ImageSpanAlignment.BASELINE, + objectFit: ImageFit.Fill + })); + this.paragraphStyledString1.appendStyledString(this.paragraphStyledString2); + this.mutableStr.appendStyledString(this.paragraphStyledString1); + this.controller.setStyledString(this.mutableStr); + } + this.abled = false; + }) + } + .width('100%') + } + .height('100%') + .backgroundColor('#F8F8FF') + // [End styled_string_image_attachment] + } + } + .width('100%') + .height('100%') + .padding({ left: 12, right: 12 }) + } + .backgroundColor('#f1f2f3') + .title($r('app.string.StyledStringImageAttachment_title')) + } +} \ No newline at end of file diff --git a/ArkUISample/TextComponent/entry/src/main/ets/pages/propertyString/StyledStringParagraphStyle.ets b/ArkUISample/TextComponent/entry/src/main/ets/pages/propertyString/StyledStringParagraphStyle.ets new file mode 100644 index 0000000000000000000000000000000000000000..f4fd880165fd18ba4e55fd3819b8d0fe98948341 --- /dev/null +++ b/ArkUISample/TextComponent/entry/src/main/ets/pages/propertyString/StyledStringParagraphStyle.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 { ComponentCard } from '../../common/Card'; +import { LengthMetrics } from '@kit.ArkUI'; +import resource from '../../common/resource'; + +@Entry +@Component +export struct StyledStringParagraphStyle { + titleParagraphStyleAttr: ParagraphStyle = new ParagraphStyle({ textAlign: TextAlign.Center }); + //段落首行缩进15vp + paragraphStyleAttr1: ParagraphStyle = new ParagraphStyle({ textIndent: LengthMetrics.vp(15) }); + //行高样式对象 + lineHeightStyle1: LineHeightStyle= new LineHeightStyle(new LengthMetrics(24)); + //创建含段落样式的对象paragraphStyledString1 + paragraphStyledString1: MutableStyledString = + new MutableStyledString(resource.resourceToString($r('app.string.StyledStringParagraphStyle_Text_1')), [ + { + start: 0, + length: 4, + styledKey: StyledStringKey.PARAGRAPH_STYLE, + styledValue: this.titleParagraphStyleAttr + }, + { + start: 0, + length: 4, + styledKey: StyledStringKey.LINE_HEIGHT, + styledValue: new LineHeightStyle(new LengthMetrics(50)) + }, + { + start: 0, + length: 4, + styledKey: StyledStringKey.FONT, + styledValue: new TextStyle({ fontSize: LengthMetrics.vp(24), fontWeight: FontWeight.Bolder }) + }, + { + start: 5, + length: 3, + styledKey: StyledStringKey.PARAGRAPH_STYLE, + styledValue: this.paragraphStyleAttr1 + }, + { + start: 5, + length: 20, + styledKey: StyledStringKey.LINE_HEIGHT, + styledValue: this.lineHeightStyle1 + } + ]); + + //段落不设置缩进配置最大行数及超长显示方式 + paragraphStyleAttr3: ParagraphStyle = new ParagraphStyle({ + textAlign: TextAlign.End, + maxLines: 1, + wordBreak: WordBreak.BREAK_ALL, + overflow: TextOverflow.Ellipsis + }); + + controller: TextController = new TextController(); + + async onPageShow() { + this.controller.setStyledString(this.paragraphStyledString1); + } + + build() { + NavDestination() { + Column({ space: 12 }) { + ComponentCard({ title: $r('app.string.StyledStringParagraphStyle_title') }) { + // [Start styled_string_paragraph_style] + Column() { + Button($r('app.string.StyledStringParagraphStyle_Button_1')) + .onClick(() => { + this.paragraphStyledString1.replaceStyle({ + start: 5, + length: 3, + styledKey: StyledStringKey.PARAGRAPH_STYLE, + styledValue: this.paragraphStyleAttr3 + }); + this.controller.setStyledString(this.paragraphStyledString1); + }) + Text(undefined, { controller: this.controller }) + } + // [End styled_string_paragraph_style] + } + + } + .width('100%') + .height('100%') + .padding({ left: 12, right: 12 }) + } + .backgroundColor('#f1f2f3') + .title($r('app.string.StyledStringParagraphStyle_title')) + } +} \ No newline at end of file diff --git a/ArkUISample/TextComponent/entry/src/main/ets/pages/propertyString/StyledStringSceneExample.ets b/ArkUISample/TextComponent/entry/src/main/ets/pages/propertyString/StyledStringSceneExample.ets new file mode 100644 index 0000000000000000000000000000000000000000..60a3431b1bef0a10142e77e9cb291b7669ec8f20 --- /dev/null +++ b/ArkUISample/TextComponent/entry/src/main/ets/pages/propertyString/StyledStringSceneExample.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 { ComponentCard } from '../../common/Card'; +import { LengthMetrics } from '@kit.ArkUI'; +import resource from '../../common/resource'; + +@Entry +@Component +export struct StyledStringSceneExample { + alignCenterParagraphStyleAttr: ParagraphStyle = new ParagraphStyle({ textAlign: TextAlign.Center }); + //行高样式对象 + lineHeightStyle1: LineHeightStyle = new LineHeightStyle(LengthMetrics.vp(24)); + //Bold样式 + boldTextStyle: TextStyle = new TextStyle({ fontWeight: FontWeight.Bold }); + //创建含段落样式的对象paragraphStyledString1 + paragraphStyledString1: MutableStyledString = + new MutableStyledString(resource.resourceToString($r('app.string.StyledStringSceneExample_Text_1')), [ + { + start: 0, + length: 4, + styledKey: StyledStringKey.PARAGRAPH_STYLE, + styledValue: this.alignCenterParagraphStyleAttr + }, + { + start: 0, + length: 4, + styledKey: StyledStringKey.LINE_HEIGHT, + styledValue: new LineHeightStyle(LengthMetrics.vp(40)) + }, + { + start: 11, + length: 14, + styledKey: StyledStringKey.FONT, + styledValue: new TextStyle({ fontSize: LengthMetrics.vp(14), fontColor: Color.Grey }) + }, + { + start: 11, + length: 4, + styledKey: StyledStringKey.PARAGRAPH_STYLE, + styledValue: this.alignCenterParagraphStyleAttr + }, + { + start: 11, + length: 4, + styledKey: StyledStringKey.LINE_HEIGHT, + styledValue: this.lineHeightStyle1 + } + ]); + paragraphStyledString2: MutableStyledString = + new MutableStyledString(resource.resourceToString($r('app.string.StyledStringSceneExample_Text_2')), [ + { + start: 0, + length: 4, + styledKey: StyledStringKey.PARAGRAPH_STYLE, + styledValue: this.alignCenterParagraphStyleAttr + }, + { + start: 0, + length: 4, + styledKey: StyledStringKey.LINE_HEIGHT, + styledValue: new LineHeightStyle(LengthMetrics.vp(60)) + }, + { + start: 0, + length: 6, + styledKey: StyledStringKey.FONT, + styledValue: this.boldTextStyle + }, + { + start: 1, + length: 1, + styledKey: StyledStringKey.FONT, + styledValue: new TextStyle({ fontSize: LengthMetrics.vp(18) }) + }, + { + start: 2, + length: 4, + styledKey: StyledStringKey.FONT, + styledValue: new TextStyle({ fontSize: LengthMetrics.vp(40) }) + }, + { + start: 6, + length: 3, + styledKey: StyledStringKey.FONT, + styledValue: new TextStyle({ fontColor: Color.Grey, fontSize: LengthMetrics.vp(14) }) + }, + { + start: 6, + length: 3, + styledKey: StyledStringKey.DECORATION, + styledValue: new DecorationStyle({ type: TextDecorationType.LineThrough, color: Color.Grey }) + } + ]); + paragraphStyledString3: MutableStyledString = + new MutableStyledString(resource.resourceToString($r('app.string.StyledStringSceneExample_Text_3')), [ + { + start: 0, + length: 4, + styledKey: StyledStringKey.PARAGRAPH_STYLE, + styledValue: this.alignCenterParagraphStyleAttr + }, + { + start: 0, + length: 4, + styledKey: StyledStringKey.LINE_HEIGHT, + styledValue: new LineHeightStyle(LengthMetrics.vp(30)) + }, + { + start: 1, + length: 2, + styledKey: StyledStringKey.FONT, + styledValue: new TextStyle({ fontColor: '#FFD700', fontWeight: FontWeight.Bold }) + }, + { + start: 4, + length: 2, + styledKey: StyledStringKey.FONT, + styledValue: new TextStyle({ fontColor: '#FFD700', fontWeight: FontWeight.Bold }) + } + ]); + controller: TextController = new TextController(); + + build() { + NavDestination() { + Column({ space: 12 }) { + ComponentCard({ title: $r('app.string.StyledStringSceneExample_title') }) { + // [Start styled_string_scene_example] + Row() { + Column({ space: 5 }) { + Text(undefined, { controller: this.controller }) + .id('text1') + .width(240) + .copyOption(CopyOptions.InApp) + .draggable(true) + .onAppear(() => { + this.paragraphStyledString2.appendStyledString(this.paragraphStyledString3); + this.paragraphStyledString1.appendStyledString(this.paragraphStyledString2); + this.controller.setStyledString(this.paragraphStyledString1); + }) + + Button($r('app.string.StyledStringSceneExample_Button_1')) + .width(200) + .fontColor(Color.White) + .fontSize(18) + .backgroundColor('#3CB371') + .margin({ bottom: 10 }) + } + .borderWidth(1).borderColor('#FFDEAD') + .margin({ left: 10 }) + } + .height('60%') + // [End styled_string_scene_example] + } + } + .width('100%') + .height('100%') + .padding({ left: 12, right: 12 }) + } + .backgroundColor('#f1f2f3') + .title($r('app.string.StyledStringSceneExample_title')) + } +} \ No newline at end of file diff --git a/ArkUISample/TextComponent/entry/src/main/ets/pages/propertyString/StyledStringStyle.ets b/ArkUISample/TextComponent/entry/src/main/ets/pages/propertyString/StyledStringStyle.ets new file mode 100644 index 0000000000000000000000000000000000000000..683fbda11d832edaa62f9db8680052e37f252e8d --- /dev/null +++ b/ArkUISample/TextComponent/entry/src/main/ets/pages/propertyString/StyledStringStyle.ets @@ -0,0 +1,155 @@ +/* + * Copyright (c) 2025 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 { ComponentCard } from '../../common/Card'; +import { LengthMetrics, LengthUnit } from '@kit.ArkUI'; +import resource from '../../common/resource'; + +@Entry +@Component +export struct StyledStringStyle { + textStyleAttrs: TextStyle = new TextStyle({ + fontWeight: FontWeight.Bolder, + fontSize: LengthMetrics.vp(24), + fontStyle: FontStyle.Italic + }); + + mutableStyledString1: MutableStyledString = + new MutableStyledString(resource.resourceToString($r('app.string.StyledStringStyle_Text_1')), [ + { + start: 2, + length: 2, + styledKey: StyledStringKey.FONT, + styledValue: this.textStyleAttrs + }, + { + start: 7, + length: 4, + styledKey: StyledStringKey.FONT, + styledValue: new TextStyle({ fontColor: Color.Orange, fontSize: LengthMetrics.vp(12) }) + } + ]); + mutableStyledString2: MutableStyledString = + new MutableStyledString(resource.resourceToString($r('app.string.StyledStringStyle_Text_2')), [ + { + start: 0, + length: 3, + styledKey: StyledStringKey.TEXT_SHADOW, + styledValue: new TextShadowStyle({ + radius: 5, + type: ShadowType.COLOR, + color: Color.Red, + offsetX: 10, + offsetY: 10 + }) + } + ]); + mutableStyledString3: MutableStyledString = + new MutableStyledString(resource.resourceToString($r('app.string.StyledStringStyle_Text_3')), [ + { + start: 0, + length: 3, + styledKey: StyledStringKey.DECORATION, + styledValue: new DecorationStyle({ type: TextDecorationType.LineThrough, color: Color.Red }) + } + ]); + mutableStyledString4: MutableStyledString = + new MutableStyledString(resource.resourceToString($r('app.string.StyledStringStyle_Text_4')), [ + { + start: 0, + length: 3, + styledKey: StyledStringKey.BASELINE_OFFSET, + styledValue: new BaselineOffsetStyle(LengthMetrics.px(20)) + } + ]); + mutableStyledString5: MutableStyledString = + new MutableStyledString(resource.resourceToString($r('app.string.StyledStringStyle_Text_5')), [ + { + start: 8, + length: 3, + styledKey: StyledStringKey.LINE_HEIGHT, + styledValue: new LineHeightStyle(LengthMetrics.vp(50)) + } + ]); + mutableStyledString6: MutableStyledString = + new MutableStyledString(resource.resourceToString($r('app.string.StyledStringStyle_Text_6')), [ + { + start: 0, + length: 2, + styledKey: StyledStringKey.LETTER_SPACING, + styledValue: new LetterSpacingStyle(new LengthMetrics(20, LengthUnit.VP)) + } + ]); + + controller1: TextController = new TextController(); + controller2: TextController = new TextController(); + controller3: TextController = new TextController(); + controller4: TextController = new TextController(); + controller5: TextController = new TextController(); + controller6: TextController = new TextController(); + + async onPageShow() { + this.controller1.setStyledString(this.mutableStyledString1); + this.controller2.setStyledString(this.mutableStyledString2); + this.controller3.setStyledString(this.mutableStyledString3); + this.controller4.setStyledString(this.mutableStyledString4); + this.controller5.setStyledString(this.mutableStyledString5); + this.controller6.setStyledString(this.mutableStyledString6); + } + + build() { + NavDestination() { + Column({ space: 12 }) { + ComponentCard({ title: $r('app.string.StyledStringStyle_title_1') }) { + // [Start styled_string_text_style] + Text(undefined, { controller: this.controller1 }) + .id('1') + .margin({ top: 10 }) + // [End styled_string_text_style] + } + ComponentCard({ title: $r('app.string.StyledStringStyle_title_2') }) { + // [Start styled_string_text_shadow_style] + Text(undefined, { controller: this.controller2 }).id('2') + // [End styled_string_text_shadow_style] + } + ComponentCard({ title: $r('app.string.StyledStringStyle_title_3') }) { + // [Start styled_string_decoration_style] + Text(undefined, { controller: this.controller3 }).id('3') + // [End styled_string_decoration_style] + } + ComponentCard({ title: $r('app.string.StyledStringStyle_title_4') }) { + // [Start styled_string_baseline_offset_style] + Text(undefined, { controller: this.controller4 }).id('4') + // [End styled_string_baseline_offset_style] + } + ComponentCard({ title: $r('app.string.StyledStringStyle_title_5') }) { + // [Start styled_string_line_height_style] + Text(undefined, { controller: this.controller5 }).id('5') + // [End styled_string_line_height_style] + } + ComponentCard({ title: $r('app.string.StyledStringStyle_title_6') }) { + // [Start styled_string_letter_spacing_style] + Text(undefined, { controller: this.controller6 }).id('6') + // [End styled_string_letter_spacing_style] + } + } + .width('100%') + .height('100%') + .padding({ left: 12, right: 12 }) + } + .backgroundColor('#f1f2f3') + .title($r('app.string.StyledStringStyle_title')) + } +} \ No newline at end of file diff --git a/ArkUISample/TextComponent/entry/src/main/ets/pages/propertyString/index.ets b/ArkUISample/TextComponent/entry/src/main/ets/pages/propertyString/index.ets new file mode 100644 index 0000000000000000000000000000000000000000..69a07844fb1c415d572492ccc8bb77d82e6a6758 --- /dev/null +++ b/ArkUISample/TextComponent/entry/src/main/ets/pages/propertyString/index.ets @@ -0,0 +1,105 @@ +/* + * Copyright (c) 2025 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { CompletedRoutableCard } from '../../common/Card'; +import { Route } from '../../common/Route'; +import resource from '../../common/resource'; +import { router } from '@kit.ArkUI'; + +export const PROPERTY_STRING_ROUTE_PREFIX: string = 'propertyString'; + +const routes: Route[] = [ + { + name: `${PROPERTY_STRING_ROUTE_PREFIX}/CreateApply`, + title: resource.resourceToString($r('app.string.Create_Apply_StyledString_MutableStyledString_title')), + description: $r('app.string.Create_Apply_StyledString_MutableStyledString_desc') + }, + { + name: `${PROPERTY_STRING_ROUTE_PREFIX}/StyledStringStyle`, + title: resource.resourceToString($r('app.string.StyledStringStyle_title')), + description: $r('app.string.StyledStringStyle_description') + }, + { + name: `${PROPERTY_STRING_ROUTE_PREFIX}/StyledStringParagraphStyle`, + title: resource.resourceToString($r('app.string.StyledStringParagraphStyle_title')), + description: $r('app.string.StyledStringParagraphStyle_description') + }, + { + name: `${PROPERTY_STRING_ROUTE_PREFIX}/StyledStringImageAttachment`, + title: resource.resourceToString($r('app.string.StyledStringImageAttachment_title')), + description: $r('app.string.StyledStringImageAttachment_description') + }, + { + name: `${PROPERTY_STRING_ROUTE_PREFIX}/StyledStringGestureStyle`, + title: resource.resourceToString($r('app.string.TStyledStringGestureStyle_title')), + description: $r('app.string.StyledStringGestureStyle_description') + }, + { + name: `${PROPERTY_STRING_ROUTE_PREFIX}/StyledStringHtml`, + title: resource.resourceToString($r('app.string.StyledStringHtml_title')), + description: $r('app.string.StyledStringHtml_description') + }, + { + name: `${PROPERTY_STRING_ROUTE_PREFIX}/StyledStringSceneExample`, + title: resource.resourceToString($r('app.string.StyledStringSceneExample_title')), + description: $r('app.string.StyledStringSceneExample_description') + } +]; + +@Builder +export function PropertyStringDestination(name: string) { + if (name === PROPERTY_STRING_ROUTE_PREFIX) { + PropertyStringExample(); + } +} + +@Entry +@Component +struct PropertyStringExample { + goToSample(url: string): void { + router.pushUrl({ + url: url, + }, router.RouterMode.Single, (err) => { + if (err) { + console.error(`pushUrl failed, code is ${err.code}, message is ${err.message}`); + return; + } + console.info('pushUrl success'); + }) + } + + build() { + NavDestination() { + List({ space: 12 }) { + ForEach(routes, (route: Route) => { + ListItem() { + CompletedRoutableCard({ title: route.title, description: route.description }) + } + .width('100%') + .onClick(() => { + this.goToSample('pages/' + route.name); + }) + }) + } + .contentStartOffset(56) + .padding({ left: 16, right: 16 }) + } + .backgroundColor('#f1f3f5') + .title('propertyString', { + backgroundBlurStyle: BlurStyle.COMPONENT_THICK, + barStyle: BarStyle.STACK + }) + } +} \ No newline at end of file diff --git a/ArkUISample/TextComponent/entry/src/main/ets/pages/richEditor/AddBuilderDecoratorContent.ets b/ArkUISample/TextComponent/entry/src/main/ets/pages/richEditor/AddBuilderDecoratorContent.ets new file mode 100644 index 0000000000000000000000000000000000000000..c14e3958ff5c93fc6c6b0a00aa35bed85c134086 --- /dev/null +++ b/ArkUISample/TextComponent/entry/src/main/ets/pages/richEditor/AddBuilderDecoratorContent.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 { ComponentCard } from '../../common/Card'; +import resource from '../../common/resource'; + +@Entry +@Component +export struct AddBuilderDecoratorContent { + controller: RichEditorController = new RichEditorController(); + options: RichEditorOptions = { controller: this.controller }; + private myBuilder: CustomBuilder = undefined + + @Builder + TextBuilder() { + Row() { + Image($r('app.media.startIcon')).width(50).height(50).margin(16) + Column() { + Text($r('app.string.AddBuilderDecoratorContent_Text_1')).fontWeight(FontWeight.Bold).fontSize(16) + Text($r('app.string.AddBuilderDecoratorContent_Text_2')).fontColor('#8a8a8a').fontSize(12) + }.alignItems(HorizontalAlign.Start) + }.backgroundColor('#f4f4f4') + .borderRadius('20') + .width(220) + } + + build() { + NavDestination() { + Column({ space: 12 }) { + ComponentCard() { + Column({ space: 3 }) { + RichEditor(this.options) + .onReady(() => { + this.controller.addTextSpan( + resource.resourceToString($r('app.string.AddBuilderDecoratorContent_Text_3')), { + style: { + fontColor: Color.Black, + fontSize: 15 + } + }) + }) + Button($r('app.string.AddBuilderDecoratorContent_Button_1'), { + buttonStyle: ButtonStyleMode.NORMAL + }) + .height(30) + .fontSize(13) + .onClick(() => { + this.myBuilder = () => { + this.TextBuilder() + } + this.controller.addBuilderSpan(this.myBuilder) + }) + } + } + } + .width('100%') + .padding({ left: 12, right: 12 }) + } + .backgroundColor('#f1f2f3') + .title($r('app.string.Add_Builder_DecoratorContent_title')) + } +} \ No newline at end of file diff --git a/ArkUISample/TextComponent/entry/src/main/ets/pages/richEditor/AddEvent.ets b/ArkUISample/TextComponent/entry/src/main/ets/pages/richEditor/AddEvent.ets new file mode 100644 index 0000000000000000000000000000000000000000..78d87d697e47681cdfba5ac5e5efa89633d1ac7e --- /dev/null +++ b/ArkUISample/TextComponent/entry/src/main/ets/pages/richEditor/AddEvent.ets @@ -0,0 +1,385 @@ +/* + * Copyright (c) 2025 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 { ComponentCard } from '../../common/Card'; +import { pasteboard } from '@kit.BasicServicesKit'; +import resource from '../../common/resource'; + +@Component +struct event1 { + controller: RichEditorController = new RichEditorController(); + options: RichEditorOptions = { controller: this.controller }; + controller1: RichEditorController = new RichEditorController(); + options1: RichEditorOptions = { controller: this.controller1 }; + + build() { + Column() { + ComponentCard({ + title: $r('app.string.Add_Event_title_1'), + description: $r('app.string.Add_Event_title_1_desc') + }) { + RichEditor(this.options) + .onReady(() => { + this.controller.addTextSpan(resource.resourceToString($r('app.string.AddEvent_Text_1')), { + style: { + fontColor: Color.Black, + fontSize: 15 + } + }) + }) + } + } + } +} + +@Component +struct event2 { + controller: RichEditorController = new RichEditorController(); + options: RichEditorOptions = { controller: this.controller }; + controller1: RichEditorController = new RichEditorController(); + options1: RichEditorOptions = { controller: this.controller1 }; + + build() { + Column() { + ComponentCard({ + title: $r('app.string.Add_Event_title_2'), + description: $r('app.string.Add_Event_title_2_desc'), + }) { + Column({ space: 3 }) { + RichEditor(this.options) + .onReady(() => { + this.controller.addTextSpan(resource.resourceToString($r('app.string.AddEvent_Text_2')), { + style: { + fontColor: Color.Black, + fontSize: 15 + } + }) + }) + .onSelectionChange((value: RichEditorRange) => { + this.controller1.addTextSpan('\n' + resource.resourceToString($r('app.string.AddEvent_Text_3')) + + value.start + ',' + value.end + ')', { + style: { + fontColor: Color.Gray, + fontSize: 10 + } + }) + }) + .width(300) + .height(50) + Text(resource.resourceToString($r('app.string.AddEvent_Text_4'))).fontSize(10).fontColor(Color.Gray).width(300) + RichEditor(this.options1) + .width(300) + .height(70) + } + } + } + } +} + +@Component +struct event3 { + controller: RichEditorController = new RichEditorController(); + options: RichEditorOptions = { controller: this.controller }; + controller1: RichEditorController = new RichEditorController(); + options1: RichEditorOptions = { controller: this.controller1 }; + + build() { + Column() { + ComponentCard({ + title: $r('app.string.Add_Event_title_3'), + description: $r('app.string.Add_Event_title_3_desc') + }) { + Column({ space: 3 }) { + RichEditor(this.options) + .onReady(() => { + this.controller.addTextSpan(resource.resourceToString($r('app.string.AddEvent_Text_5')), { + style: { + fontColor: Color.Black, + fontSize: 15 + } + }) + }) + .onWillChange((value: RichEditorChangeValue) => { + this.controller1.addTextSpan(resource.resourceToString($r('app.string.AddEvent_Text_6')) + + JSON.stringify(value), { + style: { + fontColor: Color.Gray, + fontSize: 10 + } + }) + return true; + }) + .onDidChange((rangeBefore: TextRange, rangeAfter: TextRange) => { + this.controller1.addTextSpan(resource.resourceToString($r('app.string.AddEvent_Text_7')) + + JSON.stringify(rangeBefore) + '\nrangeAfter:' + JSON.stringify(rangeBefore), { + style: { + fontColor: Color.Gray, + fontSize: 10 + } + }) + }) + .width(300) + .height(50) + Text(resource.resourceToString($r('app.string.AddEvent_Text_4'))).fontSize(10).fontColor(Color.Gray).width(300) + RichEditor(this.options1) + .width(300) + .height(70) + } + } + } + } +} + +@Component +struct event4 { + controller: RichEditorController = new RichEditorController(); + options: RichEditorOptions = { controller: this.controller }; + controller1: RichEditorController = new RichEditorController(); + options1: RichEditorOptions = { controller: this.controller1 }; + + build() { + Column() { + ComponentCard({ + title: $r('app.string.Add_Event_title_4'), + description: $r('app.string.Add_Event_title_4_desc'), + }) { + Column({ space: 3 }) { + RichEditor(this.options) + .onReady(() => { + this.controller.addTextSpan(resource.resourceToString($r('app.string.AddEvent_Text_8')), { + style: { + fontColor: Color.Black, + fontSize: 15 + } + }) + }) + .aboutToIMEInput((value: RichEditorInsertValue) => { + this.controller1.addTextSpan(resource.resourceToString($r('app.string.AddEvent_Text_9')) + + JSON.stringify(value), { + style: { + fontColor: Color.Gray, + fontSize: 10 + } + }) + return true; + }) + .onDidIMEInput((value: TextRange) => { + this.controller1.addTextSpan(resource.resourceToString($r('app.string.AddEvent_Text_10')) + + JSON.stringify(value), { + style: { + fontColor: Color.Gray, + fontSize: 10 + } + }) + }) + .width(300) + .height(50) + Text(resource.resourceToString($r('app.string.AddEvent_Text_4'))).fontSize(10).fontColor(Color.Gray).width(300) + RichEditor(this.options1) + .width(300) + .height(70) + } + } + } + } +} + +@Component +struct event5 { + controller: RichEditorController = new RichEditorController(); + options: RichEditorOptions = { controller: this.controller }; + controller1: RichEditorController = new RichEditorController(); + options1: RichEditorOptions = { controller: this.controller1 }; + + PopDataFromPasteboard() { + let selection = this.controller.getSelection(); + let start = selection.selection[0]; + let end = selection.selection[1]; + if (start == end) { + start = this.controller.getCaretOffset(); + end = this.controller.getCaretOffset(); + } + let moveOffset = 0; + let sysBoard = pasteboard.getSystemPasteboard(); + sysBoard.getData((err, data) => { + if (err) { + return; + } + if (start != end) { + this.controller.deleteSpans({ start: start, end: end }) + } + let count = data.getRecordCount(); + for (let i = 0; i < count; i++) { + const element = data.getRecord(i); + if (element && element.plainText && element.mimeType === pasteboard.MIMETYPE_TEXT_PLAIN) { + this.controller.addTextSpan(element.plainText, + { + style: { fontSize: 26, fontColor: Color.Red }, + offset: start + moveOffset + } + ) + moveOffset += element.plainText.length; + } + } + this.controller.setCaretOffset(start + moveOffset) + }) + } + + build() { + Column() { + ComponentCard({ + title: $r('app.string.Add_Event_title_5'), + description: $r('app.string.Add_Event_title_5_desc') + }) { + Column({ space: 3 }) { + RichEditor(this.options) + .onReady(() => { + this.controller.addTextSpan(resource.resourceToString($r('app.string.AddEvent_Text_11')), + { style: { fontColor: Color.Black, fontSize: 15 } }) + }) + .onPaste((event) => { + this.controller1.addTextSpan(resource.resourceToString($r('app.string.AddEvent_Text_12')), + { style: { fontColor: Color.Gray, fontSize: 10 } }) + if (event != undefined && event.preventDefault) { + event.preventDefault(); + } + console.info('RichEditor onPaste') + this.PopDataFromPasteboard() + }) + .width(300) + .height(50) + Text(resource.resourceToString($r('app.string.AddEvent_Text_4'))).fontSize(10).fontColor(Color.Gray).width(300) + RichEditor(this.options1) + .width(300) + .height(70) + }.width('100%').alignItems(HorizontalAlign.Start) + } + } + } +} + +@Component +struct event6 { + controller: RichEditorController = new RichEditorController(); + options: RichEditorOptions = { controller: this.controller }; + controller1: RichEditorController = new RichEditorController(); + options1: RichEditorOptions = { controller: this.controller1 }; + + build() { + Column() { + ComponentCard({ + title: $r('app.string.Add_Event_title_6'), + description: $r('app.string.Add_Event_title_6_desc') + }) { + Column({ space: 3 }) { + RichEditor(this.options) + .onReady(() => { + this.controller.addTextSpan(resource.resourceToString($r('app.string.AddEvent_Text_13')), { + style: { + fontColor: Color.Black, + fontSize: 15 + } + }) + }) + .onCut(() => { + this.controller1.addTextSpan(resource.resourceToString($r('app.string.AddEvent_Text_14')), { + style: { + fontColor: Color.Gray, + fontSize: 10 + } + }) + }) + .width(300) + .height(50) + Text(resource.resourceToString($r('app.string.AddEvent_Text_4'))).fontSize(10).fontColor(Color.Gray).width(300) + RichEditor(this.options1) + .width(300) + .height(70) + } + } + } + } +} + +@Component +struct event7 { + controller: RichEditorController = new RichEditorController(); + options: RichEditorOptions = { controller: this.controller }; + controller1: RichEditorController = new RichEditorController(); + options1: RichEditorOptions = { controller: this.controller1 }; + + build() { + Column() { + ComponentCard({ + title: $r('app.string.Add_Event_title_7'), + description: $r('app.string.Add_Event_title_7') + }) { + Column({ space: 3 }) { + RichEditor(this.options) + .onReady(() => { + this.controller.addTextSpan(resource.resourceToString($r('app.string.AddEvent_Text_15')), { + style: { + fontColor: Color.Black, + fontSize: 15 + } + }) + }) + .onCopy(() => { + this.controller1.addTextSpan(resource.resourceToString($r('app.string.AddEvent_Text_16')), { + style: { + fontColor: Color.Gray, + fontSize: 10 + } + }) + }) + .width(300) + .height(50) + Text(resource.resourceToString($r('app.string.AddEvent_Text_4'))).fontSize(10).fontColor(Color.Gray).width(300) + RichEditor(this.options1) + .width(300) + .height(70) + } + } + } + } +} + +@Entry +@Component +export struct AddEvent { + scroller: Scroller = new Scroller(); + + build() { + NavDestination() { + Scroll(this.scroller) { + Column({ space: 12 }) { + event1(); + event2(); + event3(); + event4(); + event5(); + event6(); + event7(); + // tmp(); + + } + .width('100%') + .padding({ left: 12, right: 12 }) + }.id('scroll_') + } + .backgroundColor('#f1f2f3') + .title($r('app.string.Add_Event_title')) + } +} \ No newline at end of file diff --git a/ArkUISample/TextComponent/entry/src/main/ets/pages/richEditor/AddImageContent.ets b/ArkUISample/TextComponent/entry/src/main/ets/pages/richEditor/AddImageContent.ets new file mode 100644 index 0000000000000000000000000000000000000000..125a03d960a5787237d173100fdc02fda2fc1b8a --- /dev/null +++ b/ArkUISample/TextComponent/entry/src/main/ets/pages/richEditor/AddImageContent.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. + */ + +import { ComponentCard } from '../../common/Card'; +import resource from '../../common/resource'; + +@Entry +@Component +export struct AddImageContent { + controller: RichEditorController = new RichEditorController(); + options: RichEditorOptions = { controller: this.controller }; + + build() { + NavDestination() { + Column({ space: 12 }) { + ComponentCard() { + RichEditor(this.options) + .onReady(() => { + this.controller.addTextSpan(resource.resourceToString($r('app.string.AddImageContent_Text_1')), { + style: { + fontColor: Color.Black, + fontSize: 15 + } + }) + }) + .width(300) + .height(100) + Button($r('app.string.AddImageContent_Button_1'), { + buttonStyle: ButtonStyleMode.NORMAL + }) + .height(30) + .fontSize(13) + .onClick(() => { + this.controller.addImageSpan($r('app.media.startIcon'), { + imageStyle: { + size: ['57px', '57px'] + } + }) + }) + } + } + .width('100%') + .padding({ left: 12, right: 12 }) + } + .backgroundColor('#f1f2f3') + .title($r('app.string.Add_ImageContent_title')) + } +} \ No newline at end of file diff --git a/ArkUISample/TextComponent/entry/src/main/ets/pages/richEditor/AddSymbolSpanContent.ets b/ArkUISample/TextComponent/entry/src/main/ets/pages/richEditor/AddSymbolSpanContent.ets new file mode 100644 index 0000000000000000000000000000000000000000..e86404b6443b13e4bbbdf8010f336180cba8dd50 --- /dev/null +++ b/ArkUISample/TextComponent/entry/src/main/ets/pages/richEditor/AddSymbolSpanContent.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. + */ + +import { ComponentCard } from '../../common/Card'; +import resource from '../../common/resource'; + +@Entry +@Component +export struct AddSymbolSpanContent { + controller: RichEditorController = new RichEditorController(); + options: RichEditorOptions = { controller: this.controller }; + + build() { + NavDestination() { + Column({ space: 12 }) { + ComponentCard() { + RichEditor(this.options) + .onReady(() => { + this.controller.addTextSpan(resource.resourceToString($r('app.string.AddSymbolSpanContent_Text_1')), { + style: { + fontColor: Color.Black, + fontSize: 15 + } + }) + }) + .width(300) + .height(100) + Button($r('app.string.AddSymbolSpanContent_Button_1'), { + buttonStyle: ButtonStyleMode.NORMAL + }) + .height(30) + .fontSize(13) + .onClick(() => { + this.controller.addSymbolSpan($r('sys.symbol.basketball_fill'), { + style: { + fontSize: 30 + } + }) + }) + } + } + .width('100%') + .padding({ left: 12, right: 12 }) + } + .backgroundColor('#f1f2f3') + .title($r('app.string.Add_SymbolSpanContent_title')) + } +} \ No newline at end of file diff --git a/ArkUISample/TextComponent/entry/src/main/ets/pages/richEditor/AddTextContent.ets b/ArkUISample/TextComponent/entry/src/main/ets/pages/richEditor/AddTextContent.ets new file mode 100644 index 0000000000000000000000000000000000000000..9e8c0663c0c75b401a22f69f4323c81ca80f1105 --- /dev/null +++ b/ArkUISample/TextComponent/entry/src/main/ets/pages/richEditor/AddTextContent.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. + */ + +import { ComponentCard } from '../../common/Card'; +import resource from '../../common/resource'; + +@Entry +@Component +export struct AddTextContent { + controller: RichEditorController = new RichEditorController(); + options: RichEditorOptions = { controller: this.controller }; + + build() { + NavDestination() { + Column({ space: 12 }) { + ComponentCard() { + RichEditor(this.options) + .onReady(() => { + this.controller.addTextSpan(resource.resourceToString($r('app.string.AddTextContent_Text_1')), { + style: { + fontColor: Color.Black, + fontSize: 15 + } + }) + }) + .border({ width: 1, color: Color.Gray }) + .constraintSize({ + maxHeight: 100 + }) + .width(300) + .margin(10) + Button($r('app.string.AddTextContent_Button_1'), { + buttonStyle: ButtonStyleMode.NORMAL + }) + .height(30) + .fontSize(13) + .onClick(() => { + this.controller.addTextSpan(resource.resourceToString($r('app.string.AddTextContent_Text_2'))) + }) + } + } + .width('100%') + .padding({ left: 12, right: 12 }) + } + .backgroundColor('#f1f2f3') + .title($r('app.string.Add_TextContent_title')) + } +} \ No newline at end of file diff --git a/ArkUISample/TextComponent/entry/src/main/ets/pages/richEditor/BackplaneHighlighting.ets b/ArkUISample/TextComponent/entry/src/main/ets/pages/richEditor/BackplaneHighlighting.ets new file mode 100644 index 0000000000000000000000000000000000000000..56b4e3e79bc71b039d306210a04e35c4346435e3 --- /dev/null +++ b/ArkUISample/TextComponent/entry/src/main/ets/pages/richEditor/BackplaneHighlighting.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. + */ + +import { ComponentCard } from '../../common/Card'; +import resource from '../../common/resource'; + +@Entry +@Component +export struct BackplaneHighlighting { + controller: RichEditorController = new RichEditorController(); + options: RichEditorOptions = { controller: this.controller }; + + build() { + NavDestination() { + Column({ space: 12 }) { + ComponentCard() { + RichEditor(this.options) + .onReady(() => { + this.controller.addTextSpan(resource.resourceToString($r('app.string.BackplaneHighlighting_Text_1')), { + style: { + fontColor: Color.Black, + fontSize: 15 + } + }) + }) + .width(300) + .height(60) + Button($r('app.string.BackplaneHighlighting_Button_1'), { + buttonStyle: ButtonStyleMode.NORMAL + }) + .height(30) + .fontSize(13) + .onClick(() => { + this.controller.setSelection(0, 2) + }) + } + } + .width('100%') + .padding({ left: 12, right: 12 }) + } + .backgroundColor('#f1f2f3') + .title($r('app.string.Backplane_Highlighting_title')) + } +} \ No newline at end of file diff --git a/ArkUISample/TextComponent/entry/src/main/ets/pages/richEditor/CreateRichEditor.ets b/ArkUISample/TextComponent/entry/src/main/ets/pages/richEditor/CreateRichEditor.ets new file mode 100644 index 0000000000000000000000000000000000000000..ba5d5cace309235a83e8227a7b5c1ab77b80f1eb --- /dev/null +++ b/ArkUISample/TextComponent/entry/src/main/ets/pages/richEditor/CreateRichEditor.ets @@ -0,0 +1,76 @@ +/* + * Copyright (c) 2025 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { ComponentCard } from '../../common/Card'; +import resource from '../../common/resource'; + +@Entry +@Component +export struct CreateRichEditor { + controllerNoStyledString: RichEditorController = new RichEditorController(); + optionsNoStyledString: RichEditorOptions = { controller: this.controllerNoStyledString }; + fontStyle: TextStyle = new TextStyle({ + fontColor: Color.Pink + }); + // 定义字体样式对象 + + mutableStyledString: MutableStyledString = + new MutableStyledString(resource.resourceToString($r('app.string.CreateRichEditor_Text_1')), + [{ + start: 0, + length: 5, + styledKey: StyledStringKey.FONT, + styledValue: this.fontStyle + }]); + // 创建属性字符串 + + controller: RichEditorStyledStringController = new RichEditorStyledStringController(); + options: RichEditorStyledStringOptions = { controller: this.controller }; + + build() { + NavDestination() { + Column({ space: 12 }) { + ComponentCard({ + title: $r('app.string.Create_RichEditor_Component_title_1') + }) { + RichEditor(this.options) + .onReady(() => { + this.controller.setStyledString(this.mutableStyledString); + }) + } + + ComponentCard({ + title: $r('app.string.Create_RichEditor_Component_title_2'), + }) { + RichEditor(this.optionsNoStyledString) + .onReady(() => { + this.controllerNoStyledString.addTextSpan( + resource.resourceToString($r('app.string.CreateRichEditor_Text_2')), { + style: { + fontColor: Color.Black, + fontSize: 15 + } + }) + }) + } + } + .width('100%') + .height('100%') + .padding({ left: 12, right: 12 }) + } + .backgroundColor('#f1f2f3') + .title($r('app.string.Create_RichEditor_Component_title')) + } +} \ No newline at end of file diff --git a/ArkUISample/TextComponent/entry/src/main/ets/pages/richEditor/GetGraphicInfoInComponent.ets b/ArkUISample/TextComponent/entry/src/main/ets/pages/richEditor/GetGraphicInfoInComponent.ets new file mode 100644 index 0000000000000000000000000000000000000000..e7068bb172891b4e0b6e3fe168bafae978510cbf --- /dev/null +++ b/ArkUISample/TextComponent/entry/src/main/ets/pages/richEditor/GetGraphicInfoInComponent.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. + */ + +import { ComponentCard } from '../../common/Card'; +import resource from '../../common/resource'; + +@Entry +@Component +export struct GetGraphicInfoInComponent { + controller: RichEditorController = new RichEditorController(); + options: RichEditorOptions = { controller: this.controller }; + controller1: RichEditorController = new RichEditorController(); + options1: RichEditorOptions = { controller: this.controller1 } + + build() { + NavDestination() { + Column({ space: 12 }) { + ComponentCard() { + Column({ space: 3 }) { + // 创建两个富文本组件 + RichEditor(this.options) + .onReady(() => { + this.controller.addTextSpan( + resource.resourceToString($r('app.string.GetGraphicInfoInComponent_Text_1')), { + style: { + fontColor: Color.Black, + fontSize: 15 + } + }) + }) + .width(300) + .height(50) + Text($r('app.string.GetGraphicInfoInComponent_Text_1')).fontSize(10).fontColor(Color.Gray).width(300) + RichEditor(this.options1) + .width(300) + .height(50) + Button($r('app.string.GetGraphicInfoInComponent_Button_1'), { + buttonStyle: ButtonStyleMode.NORMAL + }) + .height(30) + .fontSize(13) + .onClick(() => { + this.controller1.addTextSpan(JSON.stringify(this.controller.getSpans()), { + style: { + fontColor: Color.Gray, + fontSize: 10 + } + }) + }) + } + } + } + .width('100%') + .padding({ left: 12, right: 12 }) + } + .backgroundColor('#f1f2f3') + .title($r('app.string.Get_GraphicInfo_In_Component_title')) + } +} \ No newline at end of file diff --git a/ArkUISample/TextComponent/entry/src/main/ets/pages/richEditor/SetAttributes.ets b/ArkUISample/TextComponent/entry/src/main/ets/pages/richEditor/SetAttributes.ets new file mode 100644 index 0000000000000000000000000000000000000000..0a6fd09c61692cca609d132ea8daafd02d7031d5 --- /dev/null +++ b/ArkUISample/TextComponent/entry/src/main/ets/pages/richEditor/SetAttributes.ets @@ -0,0 +1,288 @@ +/* + * Copyright (c) 2025 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 { ComponentCard } from '../../common/Card'; +import resource from '../../common/resource'; + +// 自定义SelectionMenuTheme接口 +export interface SelectionMenuTheme { + imageSize: number; + buttonSize: number; + menuSpacing: number; + editorOptionMargin: number; + expandedOptionPadding: number; + defaultMenuWidth: number; + imageFillColor: Resource; + backGroundColor: Resource; + iconBorderRadius: Resource; + containerBorderRadius: Resource; + cutIcon: Resource; + copyIcon: Resource; + pasteIcon: Resource; + selectAllIcon: Resource; + shareIcon: Resource; + translateIcon: Resource; + searchIcon: Resource; + arrowDownIcon: Resource; + iconPanelShadowStyle: ShadowStyle; + iconFocusBorderColor: Resource; +} + +// 定义defaultTheme变量 +export const defaultTheme: SelectionMenuTheme = { + imageSize: 24, + buttonSize: 48, + menuSpacing: 8, + editorOptionMargin: 1, + expandedOptionPadding: 3, + defaultMenuWidth: 256, + imageFillColor: $r('sys.color.ohos_id_color_primary'), + backGroundColor: $r('sys.color.ohos_id_color_dialog_bg'), + iconBorderRadius: $r('sys.float.ohos_id_corner_radius_default_m'), + containerBorderRadius: $r('sys.float.ohos_id_corner_radius_card'), + cutIcon: $r('sys.media.ohos_ic_public_cut'), + copyIcon: $r('sys.media.ohos_ic_public_copy'), + pasteIcon: $r('sys.media.ohos_ic_public_paste'), + selectAllIcon: $r('sys.media.ohos_ic_public_select_all'), + shareIcon: $r('sys.media.ohos_ic_public_share'), + translateIcon: $r('sys.media.ohos_ic_public_translate_c2e'), + searchIcon: $r('sys.media.ohos_ic_public_search_filled'), + arrowDownIcon: $r('sys.media.ohos_ic_public_arrow_down'), + iconPanelShadowStyle: ShadowStyle.OUTER_DEFAULT_MD, + iconFocusBorderColor: $r('sys.color.ohos_id_color_focused_outline'), +} + +@Component +struct attr1 { + controller: RichEditorController = new RichEditorController(); + options: RichEditorOptions = { controller: this.controller }; + sliderShow: boolean = false; + private theme: SelectionMenuTheme = defaultTheme; + + @Builder + SystemMenu() { + Column() { + Menu() { + if (this.controller) { + MenuItemGroup() { + MenuItem({ + startIcon: this.theme.cutIcon, + content: resource.resourceToString($r('app.string.SetAttributes_Text_1')), + labelInfo: 'Ctrl+X' + }) + MenuItem({ + startIcon: this.theme.copyIcon, + content: resource.resourceToString($r('app.string.SetAttributes_Text_2')), + labelInfo: 'Ctrl+C' + }) + MenuItem({ + startIcon: this.theme.pasteIcon, + content: resource.resourceToString($r('app.string.SetAttributes_Text_3')), + labelInfo: 'Ctrl+V' + }) + } + } + } + .radius(this.theme.containerBorderRadius) + .clip(true) + .backgroundColor(Color.White) + .width(this.theme.defaultMenuWidth) + } + .width(this.theme.defaultMenuWidth) + } + + build() { + Column() { + ComponentCard({ + title: $r('app.string.Set_Attributes_title_1'), + description: $r('app.string.Set_Attributes_title_1_desc'), + }) { + RichEditor(this.options) + .onReady(() => { + this.controller.addTextSpan(resource.resourceToString($r('app.string.SetAttributes_Text_4')), { + style: { + fontColor: Color.Black, + fontSize: 18 + } + }) + }) + .bindSelectionMenu(RichEditorSpanType.TEXT, this.SystemMenu, ResponseType.LongPress, { + onDisappear: () => { + this.sliderShow = false + } + }) + // 绑定自定义菜单 + .width(300) + .height(300) + } + } + } +} + +@Component +struct attr2 { + controller: RichEditorController = new RichEditorController(); + options: RichEditorOptions = { controller: this.controller }; + + build() { + Column() { + ComponentCard({ + title: $r('app.string.Set_Attributes_title_2'), + description: $r('app.string.Set_Attributes_title_2_desc') + }) { + RichEditor(this.options) + .onReady(() => { + this.controller.addTextSpan(resource.resourceToString($r('app.string.SetAttributes_Text_5')), { + style: { + fontColor: Color.Black, + fontSize: 15 + } + }) + }) + .caretColor(Color.Orange) + .width(300) + .height(300) + } + } + } +} + +@Component +struct attr3 { + controller: RichEditorController = new RichEditorController(); + options: RichEditorOptions = { controller: this.controller }; + + build() { + Column() { + ComponentCard({ + title: $r('app.string.Set_Attributes_title_3'), + description: $r('app.string.Set_Attributes_title_3_desc') + }) { + RichEditor(this.options) + .placeholder(resource.resourceToString($r('app.string.SetAttributes_Text_6')), { + fontColor: Color.Gray, + font: { + size: 15, + weight: FontWeight.Normal, + family: 'HarmonyOS Sans', + style: FontStyle.Normal + } + }) + .width(300) + .height(50) + } + } + } +} + +@Component +struct attr4 { + controller: RichEditorController = new RichEditorController(); + options: RichEditorOptions = { controller: this.controller }; + + build() { + Column() { + ComponentCard({ + title: $r('app.string.Set_Attributes_title_4'), + description: $r('app.string.Set_Attributes_title_4_desc') + }) { + RichEditor(this.options) + .onReady(() => { + this.controller.addTextSpan(resource.resourceToString($r('app.string.SetAttributes_Text_7')), + { + style: { + fontColor: Color.Black, + fontSize: 15 + } + }) + }) + .maxLines(2) + } + } + } +} + +@Component +struct attr5 { + controller: RichEditorController = new RichEditorController(); + options: RichEditorOptions = { controller: this.controller }; + + build() { + Column() { + ComponentCard({ + title: $r('app.string.Set_Attributes_title_5'), + description: $r('app.string.Set_Attributes_title_5_desc') + }) { + RichEditor(this.options) + .placeholder(resource.resourceToString($r('app.string.SetAttributes_Text_8'))) + .onReady(() => { + }) + .maxLength(7) + } + } + } +} + +@Component +struct attr6 { + controller: RichEditorController = new RichEditorController(); + options: RichEditorOptions = { controller: this.controller }; + + build() { + Column() { + ComponentCard({ + title: $r('app.string.Set_Attributes_title_6'), + description: $r('app.string.Set_Attributes_title_6_desc') + }) { + RichEditor(this.options) + .onReady(() => { + this.controller.addTextSpan(resource.resourceToString($r('app.string.SetAttributes_Text_9')), { + style: { + fontColor: Color.Black, + fontSize: 15 + } + }) + }) + } + } + } +} + +@Entry +@Component +export struct SetAttributes { + scroller: Scroller = new Scroller(); + controller: RichEditorController = new RichEditorController(); + options: RichEditorOptions = { controller: this.controller }; + + build() { + NavDestination() { + Scroll(this.scroller) { + Column({ space: 12 }) { + attr1(); + attr2(); + attr3(); + attr4(); + attr5(); + attr6(); + } + .width('100%') + .padding({ left: 12, right: 12 }) + }.id('scroll_') + } + .backgroundColor('#f1f2f3') + .title($r('app.string.Set_Attributes_title')) + } +} \ No newline at end of file diff --git a/ArkUISample/TextComponent/entry/src/main/ets/pages/richEditor/SetUserPresetTextStyles.ets b/ArkUISample/TextComponent/entry/src/main/ets/pages/richEditor/SetUserPresetTextStyles.ets new file mode 100644 index 0000000000000000000000000000000000000000..46fea9e75b6b6f47d09d579284eb647080ad1ad7 --- /dev/null +++ b/ArkUISample/TextComponent/entry/src/main/ets/pages/richEditor/SetUserPresetTextStyles.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. + */ + +import { ComponentCard } from '../../common/Card'; +import resource from '../../common/resource'; + +@Entry +@Component +export struct SetUserPresetTextStyles { + controller: RichEditorController = new RichEditorController(); + options: RichEditorOptions = { controller: this.controller }; + + build() { + NavDestination() { + Column({ space: 12 }) { + ComponentCard() { + RichEditor(this.options) + .onReady(() => { + this.controller.addTextSpan(resource.resourceToString($r('app.string.SetUserPresetTextStyles_Text_1')), { + style: { + fontColor: Color.Black, + fontSize: 15 + } + }) + }) + .width(300) + .height(60) + Button($r('app.string.SetUserPresetTextStyles_Button_1'), { + buttonStyle: ButtonStyleMode.NORMAL + }) + .height(30) + .fontSize(13) + .onClick(() => { + this.controller.setTypingStyle({ + fontWeight: 'medium', + fontColor: Color.Pink, + fontSize: 15, + fontStyle: FontStyle.Italic, + decoration: { + type: TextDecorationType.Underline, + color: Color.Gray + } + }) + }) + } + } + .width('100%') + .padding({ left: 12, right: 12 }) + } + .backgroundColor('#f1f2f3') + .title($r('app.string.Set_User_PresetText_Styles_title')) + } +} \ No newline at end of file diff --git a/ArkUISample/TextComponent/entry/src/main/ets/pages/richEditor/index.ets b/ArkUISample/TextComponent/entry/src/main/ets/pages/richEditor/index.ets new file mode 100644 index 0000000000000000000000000000000000000000..9ebb6185c758c145dcb3311b059f80d5661d77d9 --- /dev/null +++ b/ArkUISample/TextComponent/entry/src/main/ets/pages/richEditor/index.ets @@ -0,0 +1,139 @@ +/* + * Copyright (c) 2025 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { CompletedRoutableCard } from '../../common/Card'; +import { Route } from '../../common/Route'; +import resource from '../../common/resource'; +import { CreateRichEditor } from './CreateRichEditor'; +import { SetAttributes } from './SetAttributes'; +import { AddEvent } from './AddEvent'; +import { SetUserPresetTextStyles } from './SetUserPresetTextStyles'; +import { BackplaneHighlighting } from './BackplaneHighlighting'; +import { AddTextContent } from './AddTextContent'; +import { AddImageContent } from './AddImageContent'; +import { AddBuilderDecoratorContent } from './AddBuilderDecoratorContent'; +import { AddSymbolSpanContent } from './AddSymbolSpanContent'; +import { GetGraphicInfoInComponent } from './GetGraphicInfoInComponent'; + +export const RICH_EDITOR_ROUTE_PREFIX: string = 'RichEditor'; + +const routes: Route[] = [ + { + name: `${RICH_EDITOR_ROUTE_PREFIX}/CreateRichEditor`, + title: resource.resourceToString($r('app.string.Create_RichEditor_Component_title')), + description: $r('app.string.Create_RichEditor_Component_description') + }, + { + name: `${RICH_EDITOR_ROUTE_PREFIX}/SetAttributes`, + title: resource.resourceToString($r('app.string.Set_Attributes_title')), + }, + { + name: `${RICH_EDITOR_ROUTE_PREFIX}/AddEvent`, + title: resource.resourceToString($r('app.string.Add_Event_title')), + }, + { + name: `${RICH_EDITOR_ROUTE_PREFIX}/SetUserPresetTextStyles`, + title: resource.resourceToString($r('app.string.Set_User_PresetText_Styles_title')), + description: $r('app.string.Set_User_PresetText_Styles_desc') + }, + { + name: `${RICH_EDITOR_ROUTE_PREFIX}/BackplaneHighlighting`, + title: resource.resourceToString($r('app.string.Backplane_Highlighting_title')), + description: $r('app.string.Backplane_Highlighting_desc') + }, + { + name: `${RICH_EDITOR_ROUTE_PREFIX}/AddTextContent`, + title: resource.resourceToString($r('app.string.Add_TextContent_title')), + description: $r('app.string.Add_TextContent_desc') + }, + { + name: `${RICH_EDITOR_ROUTE_PREFIX}/AddImageContent`, + title: resource.resourceToString($r('app.string.Add_ImageContent_title')), + description: $r('app.string.Add_ImageContent_desc') + }, + { + name: `${RICH_EDITOR_ROUTE_PREFIX}/AddBuilderDecoratorContent`, + title: resource.resourceToString($r('app.string.Add_Builder_DecoratorContent_title')), + description: $r('app.string.Add_Builder_DecoratorContent_desc') + }, + { + name: `${RICH_EDITOR_ROUTE_PREFIX}/AddSymbolSpanContent`, + title: resource.resourceToString($r('app.string.Add_SymbolSpanContent_title')), + description: $r('app.string.Add_SymbolSpanContent_desc') + }, + { + name: `${RICH_EDITOR_ROUTE_PREFIX}/GetGraphicInfoInComponent`, + title: resource.resourceToString($r('app.string.Get_GraphicInfo_In_Component_title')), + description: $r('app.string.Get_GraphicInfo_In_Component_desc') + } +]; + +@Builder +export function RichEditorDestination(name: string) { + if (name === RICH_EDITOR_ROUTE_PREFIX) { + RichEditorExample(); + } else if (name === routes[0].name) { + CreateRichEditor(); + } else if (name === routes[1].name) { + SetAttributes(); + } else if (name === routes[2].name) { + AddEvent(); + } else if (name === routes[3].name) { + SetUserPresetTextStyles(); + } else if (name === routes[4].name) { + BackplaneHighlighting(); + } else if (name === routes[5].name) { + AddTextContent(); + } else if (name === routes[6].name) { + AddImageContent(); + } else if (name === routes[7].name) { + AddBuilderDecoratorContent(); + } else if (name === routes[8].name) { + AddSymbolSpanContent(); + } else if (name === routes[9].name) { + GetGraphicInfoInComponent(); + } +} + +@Entry +@Component +struct RichEditorExample { + @Consume pathStack: NavPathStack; + + build() { + NavDestination() { + Scroll() { + List({ space: 12 }) { + ForEach(routes, (route: Route) => { + ListItem() { + CompletedRoutableCard({ title: route.title, description: route.description }) + } + .width('100%') + .onClick(() => { + this.pathStack.pushPath({ name: route.name }); + }) + }) + } + .contentStartOffset(56) + .padding({ left: 16, right: 16 }) + }.id('scroll_') + } + .backgroundColor('#f1f3f5') + .title('RichEditor', { + backgroundBlurStyle: BlurStyle.COMPONENT_THICK, + barStyle: BarStyle.STACK + }) + } +} \ No newline at end of file diff --git a/ArkUISample/TextComponent/entry/src/main/ets/pages/symbol/CreatSymbolGlyph.ets b/ArkUISample/TextComponent/entry/src/main/ets/pages/symbol/CreatSymbolGlyph.ets new file mode 100644 index 0000000000000000000000000000000000000000..f8ebd2ab2859b865f036a8de8885d5e69d27c479 --- /dev/null +++ b/ArkUISample/TextComponent/entry/src/main/ets/pages/symbol/CreatSymbolGlyph.ets @@ -0,0 +1,40 @@ +/* + * Copyright (c) 2025 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { ComponentCard } from '../../common/Card'; + +@Entry +@Component +export struct CreatSymbolGlyph { + build() { + NavDestination() { + Column({ space: 12 }) { + ComponentCard({ title: $r('app.string.CreatSymbolGlyph_title') }) { + // [Start creat_symbol_glyph] + SymbolGlyph($r('sys.symbol.ohos_folder_badge_plus')) + .fontSize(96) + .renderingStrategy(SymbolRenderingStrategy.SINGLE) + .fontColor([Color.Black, Color.Green, Color.White]) + // [End creat_symbol_glyph] + } + } + .width('100%') + .height('100%') + .padding({ left: 12, right: 12 }) + } + .backgroundColor('#f1f2f3') + .title($r('app.string.CreatSymbolGlyph_title')) + } +} \ No newline at end of file diff --git a/ArkUISample/TextComponent/entry/src/main/ets/pages/symbol/SymbolAddEvent.ets b/ArkUISample/TextComponent/entry/src/main/ets/pages/symbol/SymbolAddEvent.ets new file mode 100644 index 0000000000000000000000000000000000000000..87d8cdc917e8a64c284962e1f1d00920b6309430 --- /dev/null +++ b/ArkUISample/TextComponent/entry/src/main/ets/pages/symbol/SymbolAddEvent.ets @@ -0,0 +1,45 @@ +/* + * Copyright (c) 2025 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 { ComponentCard } from '../../common/Card'; + +@Entry +@Component +export struct SymbolGlyphSpanAddEvent { + @State wifiColor: ResourceColor = Color.Black; + + build() { + NavDestination() { + Column({ space: 12 }) { + ComponentCard({ title: $r('app.string.SymbolGlyphSpanAddEvent_title') }) { + // [Start symbol_glyph_span_add_event] + SymbolGlyph($r('sys.symbol.ohos_wifi')) + .id('symbolGlyph1') + .fontSize(96) + .fontColor([this.wifiColor]) + .onClick(() => { + this.wifiColor = Color.Gray; + }) + // [End symbol_glyph_span_add_event] + } + } + .width('100%') + .height('100%') + .padding({ left: 12, right: 12 }) + } + .backgroundColor('#f1f2f3') + .title($r('app.string.SymbolGlyphSpanAddEvent_title')) + } +} \ No newline at end of file diff --git a/ArkUISample/TextComponent/entry/src/main/ets/pages/symbol/SymbolAddToText.ets b/ArkUISample/TextComponent/entry/src/main/ets/pages/symbol/SymbolAddToText.ets new file mode 100644 index 0000000000000000000000000000000000000000..8faacdae9e0a4d7863d6239fe7e3e8a3b6bab99d --- /dev/null +++ b/ArkUISample/TextComponent/entry/src/main/ets/pages/symbol/SymbolAddToText.ets @@ -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. + */ + +import { ComponentCard } from '../../common/Card'; + +@Entry +@Component +export struct SymbolGlyphSpanAddToText { + scroller: Scroller = new Scroller(); + + build() { + NavDestination() { + Scroll(this.scroller) { + Column({ space: 12 }) { + ComponentCard({ title: $r('app.string.SymbolGlyphSpanAddToText_title_1') }) { + // [Start creat_symbol_span] + Text() { + SymbolSpan($r('sys.symbol.ohos_trash')) + .fontWeight(FontWeight.Normal) + .fontSize(96) + }.id('1') + + // [End creat_symbol_span] + } + + ComponentCard({ title: $r('app.string.SymbolGlyphSpanAddToText_title_2') }) { + // [Start symbol_span_font_size] + Row() { + Column() { + Text('48') + Text() { + SymbolSpan($r('sys.symbol.ohos_folder_badge_plus')) + .fontSize(48) + .renderingStrategy(SymbolRenderingStrategy.SINGLE) + .fontColor([Color.Black, Color.Green, Color.White]) + }.id('2') + } + + Column() { + Text('72') + Text() { + SymbolSpan($r('sys.symbol.ohos_folder_badge_plus')) + .fontSize(72) + .renderingStrategy(SymbolRenderingStrategy.SINGLE) + .fontColor([Color.Black, Color.Green, Color.White]) + }.id('3') + } + + Column() { + Text('96') + Text() { + SymbolSpan($r('sys.symbol.ohos_folder_badge_plus')) + .fontSize(96) + .renderingStrategy(SymbolRenderingStrategy.SINGLE) + .fontColor([Color.Black, Color.Green, Color.White]) + }.id('4') + } + } + + // [End symbol_span_font_size] + } + + ComponentCard({ title: $r('app.string.SymbolGlyphSpanAddToText_title_3') }) { + // [Start symbol_span_font_weight] + Row() { + Column() { + Text('Light') + Text() { + SymbolSpan($r('sys.symbol.ohos_trash')) + .fontWeight(FontWeight.Lighter) + .fontSize(96) + }.id('5') + } + + Column() { + Text('Normal') + Text() { + SymbolSpan($r('sys.symbol.ohos_trash')) + .fontWeight(FontWeight.Normal) + .fontSize(96) + }.id('6') + } + + Column() { + Text('Bold') + Text() { + SymbolSpan($r('sys.symbol.ohos_trash')) + .fontWeight(FontWeight.Bold) + .fontSize(96) + }.id('7') + } + } + + // [End symbol_span_font_weight] + } + + ComponentCard({ title: $r('app.string.SymbolGlyphSpanAddToText_title_4') }) { + // [Start symbol_span_font_color] + Row() { + Column() { + Text('Black') + Text() { + SymbolSpan($r('sys.symbol.ohos_folder_badge_plus')) + .fontSize(96) + .fontColor([Color.Black]) + }.id('8') + } + + Column() { + Text('Green') + Text() { + SymbolSpan($r('sys.symbol.ohos_folder_badge_plus')) + .fontSize(96) + .fontColor([Color.Green]) + }.id('9') + } + + Column() { + Text('Pink') + Text() { + SymbolSpan($r('sys.symbol.ohos_folder_badge_plus')) + .fontSize(96) + .fontColor([Color.Pink]) + }.id('10') + } + } + + // [End symbol_span_font_color] + } + + ComponentCard({ title: $r('app.string.SymbolGlyphSpanAddToText_title_5') }) { + // [Start symbol_span_rendering_strategy] + Row() { + Column() { + Text($r('app.string.SymbolAddToText_Text_1')) + Text() { + SymbolSpan($r('sys.symbol.ohos_folder_badge_plus')) + .fontSize(96) + .renderingStrategy(SymbolRenderingStrategy.SINGLE) + .fontColor([Color.Black, Color.Green, Color.White]) + }.id('11') + } + + Column() { + Text($r('app.string.SymbolAddToText_Text_2')) + Text() { + SymbolSpan($r('sys.symbol.ohos_folder_badge_plus')) + .fontSize(96) + .renderingStrategy(SymbolRenderingStrategy.MULTIPLE_COLOR) + .fontColor([Color.Black, Color.Green, Color.White]) + }.id('12') + } + + Column() { + Text($r('app.string.SymbolAddToText_Text_3')) + Text() { + SymbolSpan($r('sys.symbol.ohos_folder_badge_plus')) + .fontSize(96) + .renderingStrategy(SymbolRenderingStrategy.MULTIPLE_OPACITY) + .fontColor([Color.Black, Color.Green, Color.White]) + }.id('13') + } + } + + // [End symbol_span_rendering_strategy] + } + + ComponentCard({ title: $r('app.string.SymbolGlyphSpanAddToText_title_6') }) { + // [Start symbol_span_effect_strategy] + Row() { + Column() { + Text($r('app.string.SymbolAddToText_Text_4')) + Text() { + SymbolSpan($r('sys.symbol.ohos_wifi')) + .fontSize(96) + .effectStrategy(SymbolEffectStrategy.NONE) + }.id('14') + } + + Column() { + Text($r('app.string.SymbolAddToText_Text_5')) + Text() { + SymbolSpan($r('sys.symbol.ohos_wifi')) + .fontSize(96) + .effectStrategy(SymbolEffectStrategy.SCALE) + }.id('15') + } + + Column() { + Text($r('app.string.SymbolAddToText_Text_6')) + Text() { + SymbolSpan($r('sys.symbol.ohos_wifi')) + .fontSize(96) + .effectStrategy(SymbolEffectStrategy.HIERARCHICAL) + }.id('16') + } + } + + // [End symbol_span_effect_strategy] + } + } + .width('100%') + .padding({ left: 12, right: 12 }) + }.id('scroll_') + } + .backgroundColor('#f1f2f3') + .title($r('app.string.SymbolGlyphSpanAddToText_title')) + } +} \ No newline at end of file diff --git a/ArkUISample/TextComponent/entry/src/main/ets/pages/symbol/SymbolCustomIconAnimation.ets b/ArkUISample/TextComponent/entry/src/main/ets/pages/symbol/SymbolCustomIconAnimation.ets new file mode 100644 index 0000000000000000000000000000000000000000..e74e5bda67a5a1290bf1d764c54be49e61f4d8f7 --- /dev/null +++ b/ArkUISample/TextComponent/entry/src/main/ets/pages/symbol/SymbolCustomIconAnimation.ets @@ -0,0 +1,64 @@ +/* + * Copyright (c) 2025 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { ComponentCard } from '../../common/Card'; + +@Entry +@Component +export struct SymbolGlyphSpanCustomIconAnimation { + @State isActive: boolean = true; + @State triggerValueReplace: number = 0; + + build() { + NavDestination() { + Column({ space: 12 }) { + ComponentCard({ title: $r('app.string.SymbolGlyphSpanCustomIconAnimation_title_1') }) { + // [Start symbol_effect_1] + Column() { + Text($r('app.string.SymbolCustomIconAnimation_Text_1')) + SymbolGlyph($r('sys.symbol.ohos_wifi')) + .id('1') + .fontSize(96) + .symbolEffect(new HierarchicalSymbolEffect(EffectFillStyle.ITERATIVE), this.isActive) + Button(this.isActive ? $r('app.string.SymbolGlyphSpanCustomIconAnimation_Button_1') : $r('app.string.SymbolGlyphSpanCustomIconAnimation_Button_2')).onClick(() => { + this.isActive = !this.isActive; + }) + } + // [End symbol_effect_1] + } + ComponentCard({ title: $r('app.string.SymbolGlyphSpanCustomIconAnimation_title_2') }) { + // [Start symbol_effect_2] + Column() { + Text($r('app.string.SymbolCustomIconAnimation_Text_2')) + SymbolGlyph($r('sys.symbol.ellipsis_message_1')) + .id('2') + .fontSize(96) + .fontColor([Color.Gray]) + .symbolEffect(new BounceSymbolEffect(EffectScope.WHOLE, EffectDirection.UP), this.triggerValueReplace) + Button($r('app.string.SymbolGlyphSpanCustomIconAnimation_Button_3')).onClick(() => { + this.triggerValueReplace = this.triggerValueReplace + 1; + }) + } + // [End symbol_effect_2] + } + } + .width('100%') + .height('100%') + .padding({ left: 12, right: 12 }) + } + .backgroundColor('#f1f2f3') + .title($r('app.string.SymbolGlyphSpanCustomIconAnimation_title')) + } +} \ No newline at end of file diff --git a/ArkUISample/TextComponent/entry/src/main/ets/pages/symbol/SymbolSceneExample.ets b/ArkUISample/TextComponent/entry/src/main/ets/pages/symbol/SymbolSceneExample.ets new file mode 100644 index 0000000000000000000000000000000000000000..618a85afc47e213f8711a3103db39181dc9b3b18 --- /dev/null +++ b/ArkUISample/TextComponent/entry/src/main/ets/pages/symbol/SymbolSceneExample.ets @@ -0,0 +1,244 @@ +/* + * Copyright (c) 2025 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 { ComponentCard } from '../../common/Card'; +import resource from '../../common/resource'; + +@Entry +@Component +export struct SymbolGlyphSpanSceneExample { + @State triggerValueReplace: number = 0; + @State symbolSources: Resource[] = + [$r('sys.symbol.repeat'), $r('sys.symbol.repeat_1'), $r('sys.symbol.arrow_left_arrow_right')]; + @State symbolSourcesIndex: number = 0; + @State symbolText: string[] = [resource.resourceToString($r('app.string.SymbolSceneExample_Text_1')), + resource.resourceToString($r('app.string.SymbolSceneExample_Text_2')), + resource.resourceToString($r('app.string.SymbolSceneExample_Text_3'))]; + @State symbolTextIndex: number = 0; + @State fontColorValue: ResourceColor = Color.Grey; + @State fontColorValue1: ResourceColor = '#E8E8E8'; + + build() { + NavDestination() { + Column({ space: 12 }) { + ComponentCard({ title: $r('app.string.SymbolGlyphSpanSceneExample_title') }) { + // [Start symbol_glyph_span_scene_example] + Column({ space: 10 }) { + Row() { + Text() { + Span(resource.resourceToString($r('app.string.SymbolSceneExample_Text_4'))) + .fontSize(20) + .fontWeight(FontWeight.Bolder) + Span('(101)') + }.id('text1') + } + + Row() { + Row({ space: 5 }) { + SymbolGlyph(this.symbolSources[this.symbolSourcesIndex]) + .id('symbolGlyph1') + .symbolEffect(new ReplaceSymbolEffect(EffectScope.WHOLE), this.triggerValueReplace) + .fontSize(20) + .fontColor([this.fontColorValue]) + Text(this.symbolText[this.symbolTextIndex]) + .fontColor(this.fontColorValue) + } + .onClick(() => { + this.symbolTextIndex++; + this.symbolSourcesIndex++; + this.triggerValueReplace++; + if (this.symbolSourcesIndex > (this.symbolSources.length - 1)) { + this.symbolSourcesIndex = 0; + this.triggerValueReplace = 0; + } + if (this.symbolTextIndex > (this.symbolText.length - 1)) { + this.symbolTextIndex = 0; + } + }) + .width('75%') + + Row({ space: 5 }) { + Text() { + SymbolSpan($r('sys.symbol.arrow_down_circle_badge_vip_circle_filled')) + .fontColor([this.fontColorValue]) + .fontSize(20) + }.id('text2') + + Text() { + SymbolSpan($r('sys.symbol.heart_badge_plus')) + .fontColor([this.fontColorValue]) + .fontSize(20) + }.id('text3') + + Text() { + SymbolSpan($r('sys.symbol.ohos_trash')) + .fontColor([this.fontColorValue]) + .fontSize(20) + }.id('text4') + } + .width('25%') + } + + Divider().width(5).color(this.fontColorValue1).width('98%') + Row() { + Row() { + Text($r('app.string.SymbolSceneExample_Text_5')) + }.width('82%') + + Row({ space: 5 }) { + SymbolGlyph($r('sys.symbol.play_arrow_triangle_2_circlepath')) + .id('symbolGlyph2') + .fontColor([this.fontColorValue]) + .fontSize(20) + SymbolGlyph($r('sys.symbol.trash')) + .id('symbolGlyph3') + .fontColor([this.fontColorValue]) + .fontSize(20) + } + } + + Divider().width(5).color(this.fontColorValue1).width('98%') + Row() { + Row() { + Text($r('app.string.SymbolSceneExample_Text_6')) + }.width('82%') + + Row({ space: 5 }) { + SymbolGlyph($r('sys.symbol.play_arrow_triangle_2_circlepath')) + .id('symbolGlyph4') + .fontColor([this.fontColorValue]) + .fontSize(20) + SymbolGlyph($r('sys.symbol.trash')) + .id('symbolGlyph5') + .fontColor([this.fontColorValue]) + .fontSize(20) + } + } + + Divider().width(5).color(this.fontColorValue1).width('98%') + Row() { + Row() { + Text($r('app.string.SymbolSceneExample_Text_7')) + }.width('82%') + + Row({ space: 5 }) { + SymbolGlyph($r('sys.symbol.play_arrow_triangle_2_circlepath')) + .id('symbolGlyph6') + .fontColor([this.fontColorValue]) + .fontSize(20) + SymbolGlyph($r('sys.symbol.trash')) + .id('symbolGlyph7') + .fontColor([this.fontColorValue]) + .fontSize(20) + } + } + + Divider().width(5).color(this.fontColorValue1).width('98%') + Row() { + Row() { + Text($r('app.string.SymbolSceneExample_Text_8')) + }.width('82%') + + Row({ space: 5 }) { + SymbolGlyph($r('sys.symbol.play_arrow_triangle_2_circlepath')) + .id('symbolGlyph8') + .fontColor([this.fontColorValue]) + .fontSize(20) + SymbolGlyph($r('sys.symbol.trash')) + .id('symbolGlyph9') + .fontColor([this.fontColorValue]) + .fontSize(20) + } + } + + Divider().width(5).color(this.fontColorValue1).width('98%') + Row() { + Row() { + Text($r('app.string.SymbolSceneExample_Text_9')) + }.width('82%') + + Row({ space: 5 }) { + SymbolGlyph($r('sys.symbol.play_arrow_triangle_2_circlepath')) + .id('symbolGlyph10') + .fontColor([this.fontColorValue]) + .fontSize(20) + SymbolGlyph($r('sys.symbol.trash')) + .id('symbolGlyph11') + .fontColor([this.fontColorValue]) + .fontSize(20) + } + } + + Divider().width(5).color(this.fontColorValue1).width('98%') + Row() { + Row() { + Text($r('app.string.SymbolSceneExample_Text_10')) + }.width('82%') + + Row({ space: 5 }) { + SymbolGlyph($r('sys.symbol.play_arrow_triangle_2_circlepath')) + .id('symbolGlyph12') + .fontColor([this.fontColorValue]) + .fontSize(20) + SymbolGlyph($r('sys.symbol.trash')) + .id('symbolGlyph13') + .fontColor([this.fontColorValue]) + .fontSize(20) + } + } + + Divider().width(5).color(this.fontColorValue1).width('98%') + Row() { + Row() { + Text($r('app.string.SymbolSceneExample_Text_11')) + }.width('82%') + + Row({ space: 5 }) { + SymbolGlyph($r('sys.symbol.play_arrow_triangle_2_circlepath')) + .id('symbolGlyph14') + .fontColor([this.fontColorValue]) + .fontSize(20) + SymbolGlyph($r('sys.symbol.trash')) + .id('symbolGlyph15') + .fontColor([this.fontColorValue]) + .fontSize(20) + } + } + + Divider().width(5).color(this.fontColorValue1).width('98%') + Column() { + Text($r('app.string.SymbolSceneExample_Text_12')) + } + .alignItems(HorizontalAlign.Center) + .width('98%') + } + .alignItems(HorizontalAlign.Start) + .width('100%') + .height(400) + .padding({ + left: 10, + top: 10 + }) + // [End symbol_glyph_span_scene_example] + } + } + .width('100%') + .height('100%') + .padding({ left: 12, right: 12 }) + } + .backgroundColor('#f1f2f3') + .title($r('app.string.SymbolGlyphSpanSceneExample_title')) + } +} \ No newline at end of file diff --git a/ArkUISample/TextComponent/entry/src/main/ets/pages/symbol/index.ets b/ArkUISample/TextComponent/entry/src/main/ets/pages/symbol/index.ets new file mode 100644 index 0000000000000000000000000000000000000000..245b218ccdb45068cd51411a692a92a119e3585f --- /dev/null +++ b/ArkUISample/TextComponent/entry/src/main/ets/pages/symbol/index.ets @@ -0,0 +1,100 @@ +/* + * Copyright (c) 2025 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { CompletedRoutableCard } from '../../common/Card'; +import { CreatSymbolGlyph } from './CreatSymbolGlyph'; +import { SymbolGlyphSpanAddToText } from './SymbolAddToText'; +import { SymbolGlyphSpanCustomIconAnimation } from './SymbolCustomIconAnimation'; +import { SymbolGlyphSpanAddEvent } from './SymbolAddEvent'; +import { SymbolGlyphSpanSceneExample } from './SymbolSceneExample'; + +import { Route } from '../../common/Route'; +import resource from '../../common/resource'; + +export const SYMBOL_GLYPH_SPAN: string = 'symbol'; + +const routes: Route[] = [ + { + name: `${SYMBOL_GLYPH_SPAN}/CreatSymbolGlyph`, + title: resource.resourceToString($r('app.string.CreatSymbolGlyph_title')), + description: $r('app.string.CreatSymbolGlyph_description') + }, + { + name: `${SYMBOL_GLYPH_SPAN}/SymbolGlyphSpanAddToText`, + title: resource.resourceToString($r('app.string.SymbolGlyphSpanAddToText_title')), + description: $r('app.string.SymbolGlyphSpanAddToText_description') + }, + { + name: `${SYMBOL_GLYPH_SPAN}/SymbolGlyphSpanCustomIconAnimation`, + title: resource.resourceToString($r('app.string.SymbolGlyphSpanCustomIconAnimation_title')), + description: $r('app.string.SymbolGlyphSpanCustomIconAnimation_description') + }, + { + name: `${SYMBOL_GLYPH_SPAN}/SymbolGlyphSpanAddEvent`, + title: resource.resourceToString($r('app.string.SymbolGlyphSpanAddEvent_title')), + description: $r('app.string.SymbolGlyphSpanAddEvent_description') + }, + { + name: `${SYMBOL_GLYPH_SPAN}/SymbolGlyphSpanSceneExample`, + title: resource.resourceToString($r('app.string.SymbolGlyphSpanSceneExample_title')), + description: $r('app.string.SymbolGlyphSpanSceneExample_description') + } +]; + +@Builder +export function SymbolGlyphSpanDestination(name: string) { + if (name === SYMBOL_GLYPH_SPAN) { + SymbolGlyphSpanExample(); + } else if (name === routes[0].name) { + CreatSymbolGlyph(); + } else if (name === routes[1].name) { + SymbolGlyphSpanAddToText(); + } else if (name === routes[2].name) { + SymbolGlyphSpanCustomIconAnimation(); + } else if (name === routes[3].name) { + SymbolGlyphSpanAddEvent(); + } else if (name === routes[4].name) { + SymbolGlyphSpanSceneExample(); + } +} + +@Entry +@Component +struct SymbolGlyphSpanExample { + @Consume pathStack: NavPathStack; + + build() { + NavDestination() { + List({ space: 12 }) { + ForEach(routes, (route: Route) => { + ListItem() { + CompletedRoutableCard({ title: route.title, description: route.description }) + } + .width('100%') + .onClick(() => { + this.pathStack.pushPath({ name: route.name }); + }) + }) + } + .contentStartOffset(56) + .padding({ left: 16, right: 16 }) + } + .backgroundColor('#f1f3f5') + .title('symbol', { + backgroundBlurStyle: BlurStyle.COMPONENT_THICK, + barStyle: BarStyle.STACK + }) + } +} \ No newline at end of file diff --git a/ArkUISample/TextComponent/entry/src/main/ets/pages/text/AIMenu.ets b/ArkUISample/TextComponent/entry/src/main/ets/pages/text/AIMenu.ets new file mode 100644 index 0000000000000000000000000000000000000000..23ea68380767ecb440240df190b4a86b553d72dc --- /dev/null +++ b/ArkUISample/TextComponent/entry/src/main/ets/pages/text/AIMenu.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 { ComponentCard } from '../../common/Card'; + +@Entry +@Component +export struct AIMenu { + build() { + NavDestination() { + Column({ space: 12 }) { + ComponentCard({ title: $r('app.string.SetUpAIMenu_title') }) { + // [Start set_ai_menu] + Text($r('app.string.AIMenu_Text_1')) + .fontSize(16) + .copyOption(CopyOptions.LocalDevice) + .enableDataDetector(true)// 使能实体识别 + .dataDetectorConfig({ + // 配置识别样式 + // types可支持PHONE_NUMBER电话号码、URL链接、EMAIL邮箱、ADDRESS地址、DATE_TIME时间 + // types设置为null或者[]时,识别所有类型的实体 + types: [], onDetectResultUpdate: (result: string) => { + } + }) + // [End set_ai_menu] + } + } + .width('100%') + .height('100%') + .padding({ left: 12, right: 12 }) + } + .backgroundColor('#f1f2f3') + .title($r('app.string.SetUpAIMenu_title')) + } +} \ No newline at end of file diff --git a/ArkUISample/TextComponent/entry/src/main/ets/pages/text/CreateText.ets b/ArkUISample/TextComponent/entry/src/main/ets/pages/text/CreateText.ets new file mode 100644 index 0000000000000000000000000000000000000000..db423574802acf63e39054a4d1849c478f9bcb6b --- /dev/null +++ b/ArkUISample/TextComponent/entry/src/main/ets/pages/text/CreateText.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. + */ + +import { ComponentCard } from '../../common/Card'; + +@Entry +@Component +export struct CreateText { + build() { + NavDestination() { + Column({ space: 12 }) { + ComponentCard({ title: $r('app.string.CreatText_title_1') }) { + // [Start create_a_text_in_one_way] + Text($r('app.string.CreateText_Text_1')) + // [End create_a_text_in_one_way] + } + + ComponentCard({ + title: $r('app.string.CreatText_title_2'), + description: $r('app.string.CreatText_description_1') + }) { + // [Start create_a_text_in_another_way] + Text($r('app.string.module_desc')) + .baselineOffset(0) + .fontSize(30) + .border({ width: 1 }) + .padding(10) + .width(300) + // [End create_a_text_in_another_way] + } + } + .width('100%') + .height('100%') + .padding({ left: 12, right: 12 }) + } + .backgroundColor('#f1f2f3') + .title($r('app.string.CreatText_title')) + } +} \ No newline at end of file diff --git a/ArkUISample/TextComponent/entry/src/main/ets/pages/text/CustomTextStyle.ets b/ArkUISample/TextComponent/entry/src/main/ets/pages/text/CustomTextStyle.ets new file mode 100644 index 0000000000000000000000000000000000000000..d451b7f6ed97a97e923b3994d777475194ce5f7d --- /dev/null +++ b/ArkUISample/TextComponent/entry/src/main/ets/pages/text/CustomTextStyle.ets @@ -0,0 +1,265 @@ +/* + * Copyright (c) 2025 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 { ComponentCard } from '../../common/Card'; + +@Entry +@Component +export struct CustomTextStyle { + scroller: Scroller = new Scroller(); + + build() { + NavDestination() { + Scroll(this.scroller) { + Column({ space: 12 }) { + ComponentCard({ title: $r('app.string.CustomTextStyle_title_1') }) { + Column() { + // [Start custom_text_align] + Text($r('app.string.TextAlign_Start')) + .width(300) + .textAlign(TextAlign.Start) + .border({ width: 1 }) + .padding(10) + Text($r('app.string.TextAlign_Center')) + .width(300) + .textAlign(TextAlign.Center) + .border({ width: 1 }) + .padding(10) + Text($r('app.string.TextAlign_End')) + .width(300) + .textAlign(TextAlign.End) + .border({ width: 1 }) + .padding(10) + // [End custom_text_align] + } + } + + ComponentCard({ + title: $r('app.string.CustomTextStyle_title_2'), + description: $r('app.string.CustomTextStyle_description_1') + }) { + Column({ space: 8 }) { + // [Start custom_text_overflow] + Text('This is the setting of textOverflow to Clip text content This is the setting of textOverflow ' + + 'to None text content. This is the setting of textOverflow to Clip text content This is the setting ' + + 'of textOverflow to None text content.') + .width(250) + .textOverflow({ overflow: TextOverflow.None }) + .maxLines(1) + .fontSize(12) + .border({ width: 1 }) + .padding(10) + Text($r('app.string.CustomTextStyle_textContent_1')) + .width(250) + .textOverflow({ overflow: TextOverflow.Ellipsis }) + .maxLines(1) + .fontSize(12) + .border({ width: 1 }) + .padding(10) + Text($r('app.string.CustomTextStyle_textContent_2')) + .width(250) + .textOverflow({ overflow: TextOverflow.MARQUEE }) + .maxLines(1) + .fontSize(12) + .border({ width: 1 }) + .padding(10) + Text($r('app.string.CustomTextStyle_textContent_8')) + .width(250) + .textOverflow({ overflow: TextOverflow.MARQUEE }) + .maxLines(1) + .fontSize(12) + .border({ width: 1 }) + .padding(10) + .marqueeOptions({ + start: true, + fromStart: true, + step: 6, + loop: -1, + delay: 0, + fadeout: false, + marqueeStartPolicy: MarqueeStartPolicy.DEFAULT + }) + // [End custom_text_overflow] + } + } + + ComponentCard({ title: $r('app.string.CustomTextStyle_title_3') }) { + Column({ space: 8 }) { + // [Start custom_line_height] + Text('This is the text with the line height set. This is the text with the line height set.') + .width(300).fontSize(12).border({ width: 1 }).padding(10) + Text('This is the text with the line height set. This is the text with the line height set.') + .width(300) + .fontSize(12) + .border({ width: 1 }) + .padding(10) + .lineHeight(20) + // [End custom_line_height] + } + } + + ComponentCard({ title: $r('app.string.CustomTextStyle_title_4') }) { + Column({ space: 8 }) { + // [Start custom_text_line_and_color] + Text('This is the text') + .decoration({ + type: TextDecorationType.LineThrough, + color: Color.Red + }) + .borderWidth(1) + .padding(10) + Text('This is the text') + .decoration({ + type: TextDecorationType.Overline, + color: Color.Red + }) + .borderWidth(1) + .padding(10) + Text('This is the text') + .decoration({ + type: TextDecorationType.Underline, + color: Color.Red + }) + .borderWidth(1) + .padding(10) + // [End custom_text_line_and_color] + } + } + + ComponentCard({ title: $r('app.string.CustomTextStyle_title_5') }) { + Column({ space: 8 }) { + // [Start custom_text_baseline_offset] + Text('This is the text content with baselineOffset 0.') + .baselineOffset(0) + .fontSize(12) + .border({ width: 1 }) + .padding(10) + .width('100%') + Text('This is the text content with baselineOffset 30.') + .baselineOffset(30) + .fontSize(12) + .border({ width: 1 }) + .padding(10) + .width('100%') + Text('This is the text content with baselineOffset -20.') + .baselineOffset(-20) + .fontSize(12) + .border({ width: 1 }) + .padding(10) + .width('100%') + // [End custom_text_baseline_offset] + } + } + + ComponentCard({ title: $r('app.string.CustomTextStyle_title_6') }) { + Column({ space: 8 }) { + // [Start custom_text_letter_space] + Text('This is the text content with letterSpacing 0.') + .letterSpacing(0) + .fontSize(12) + .border({ width: 1 }) + .padding(10) + .width('100%') + Text('This is the text content with letterSpacing 3.') + .letterSpacing(3) + .fontSize(12) + .border({ width: 1 }) + .padding(10) + .width('100%') + Text('This is the text content with letterSpacing -1.') + .letterSpacing(-1) + .fontSize(12) + .border({ width: 1 }) + .padding(10) + .width('100%') + // [End custom_text_letter_space] + } + } + + ComponentCard({ title: $r('app.string.CustomTextStyle_title_7') }) { + Column({ space: 8 }) { + // [Start custom_the_size_of_text] + Text($r('app.string.CustomTextStyle_textContent_3')) + .width(250) + .maxLines(1) + .maxFontSize(30) + .minFontSize(5) + .border({ width: 1 }) + .padding(10) + Text($r('app.string.CustomTextStyle_textContent_4')) + .width(250) + .maxLines(2) + .maxFontSize(30) + .minFontSize(5) + .border({ width: 1 }) + .padding(10) + Text($r('app.string.CustomTextStyle_textContent_5')) + .width(250) + .height(50) + .maxFontSize(30) + .minFontSize(15) + .border({ width: 1 }) + .padding(10) + Text($r('app.string.CustomTextStyle_textContent_6')) + .width(250) + .height(100) + .maxFontSize(30) + .minFontSize(15) + .border({ width: 1 }) + .padding(10) + // [End custom_the_size_of_text] + } + } + + ComponentCard({ title: $r('app.string.CustomTextStyle_title_8') }) { + Column({ space: 8 }) { + // [Start custom_the_text_by_text_case] + Text('This is the text content with textCase set to Normal.') + .textCase(TextCase.Normal) + .padding(10) + .border({ width: 1 }) + .padding(10) + + // 文本全小写展示 + Text('This is the text content with textCase set to LowerCase.') + .textCase(TextCase.LowerCase) + .border({ width: 1 }) + .padding(10) + + // 文本全大写展示 + Text('This is the text content with textCase set to UpperCase.') + .textCase(TextCase.UpperCase) + .border({ width: 1 }) + .padding(10) + // [End custom_the_text_by_text_case] + } + } + + ComponentCard({ title: $r('app.string.CustomTextStyle_title_9') }) { + // [Start custom_the_text_by_copy_option] + Text($r('app.string.CustomTextStyle_textContent_7')) + .fontSize(30) + .copyOption(CopyOptions.InApp) + // [End custom_the_text_by_copy_option] + } + } + .width('100%') + .padding({ left: 12, right: 12 }) + }.id('scroll_') + } + .backgroundColor('#f1f2f3') + .title($r('app.string.CustomTextStyle_title')) + } +} \ No newline at end of file diff --git a/ArkUISample/TextComponent/entry/src/main/ets/pages/text/SelectMenu.ets b/ArkUISample/TextComponent/entry/src/main/ets/pages/text/SelectMenu.ets new file mode 100644 index 0000000000000000000000000000000000000000..252cdf3e947a8c4ed0a54ae863ee21dab05e4f8c --- /dev/null +++ b/ArkUISample/TextComponent/entry/src/main/ets/pages/text/SelectMenu.ets @@ -0,0 +1,123 @@ +/* + * Copyright (c) 2025 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 { ComponentCard } from '../../common/Card'; +import resource from '../../common/resource'; + +@Entry +@Component +export struct SelectMenu { + controller: TextController = new TextController(); + options: TextOptions = { controller: this.controller }; + + // 定义菜单项 + @Builder + RightClickTextCustomMenu() { + Column() { + Menu() { + MenuItemGroup() { + MenuItem({ startIcon: $r('app.media.app_icon'), content: 'CustomMenu One', labelInfo: '' }) + .onClick(() => { + // 使用closeSelectionMenu接口关闭菜单 + this.controller.closeSelectionMenu(); + }) + MenuItem({ startIcon: $r('app.media.app_icon'), content: 'CustomMenu Two', labelInfo: '' }) + MenuItem({ startIcon: $r('app.media.app_icon'), content: 'CustomMenu Three', labelInfo: '' }) + } + }.backgroundColor('#F0F0F0') + } + } + + // 定义onCreateMenu,onMenuItemClick + onCreateMenu = (menuItems: Array) => { + let item1: TextMenuItem = { + content: 'customMenu1', + icon: $r('app.media.app_icon'), + id: TextMenuItemId.of('customMenu1'), + }; + let item2: TextMenuItem = { + content: 'customMenu2', + id: TextMenuItemId.of('customMenu2'), + icon: $r('app.media.app_icon'), + }; + menuItems.push(item1); + menuItems.unshift(item2); + return menuItems; + } + onMenuItemClick = (menuItem: TextMenuItem, textRange: TextRange) => { + if (menuItem.id.equals(TextMenuItemId.of('customMenu2'))) { + console.log(resource.resourceToString($r('app.string.SelectMenu_Text_1')) + + textRange.start + '; end:' + textRange.end); + return true; + } + if (menuItem.id.equals(TextMenuItemId.COPY)) { + console.log(resource.resourceToString($r('app.string.SelectMenu_Text_2')) + + textRange.start + '; end:' + textRange.end); + return true; + } + if (menuItem.id.equals(TextMenuItemId.SELECT_ALL)) { + console.log(resource.resourceToString($r('app.string.SelectMenu_Text_3')) + + textRange.start + '; end:' + textRange.end); + return false; + } + return false; + }; + + build() { + NavDestination() { + Column({ space: 12 }) { + ComponentCard({ title: $r('app.string.SetSelectionMenu_textContent_1') }) { + // [Start set_selection_menu_with_copyoption] + Text($r('app.string.SelectMenu_textContent_1')) + .fontSize(30) + .copyOption(CopyOptions.InApp) + // [End set_selection_menu_with_copyoption] + } + + ComponentCard({ title: $r('app.string.SetSelectionMenu_textContent_2') }) { + // [Start set_selection_menu_with_bindselectionmenu] + Text($r('app.string.SelectMenu_textContent_1'), this.options) + .fontSize(30) + .copyOption(CopyOptions.InApp) + .bindSelectionMenu(TextSpanType.TEXT, this.RightClickTextCustomMenu, TextResponseType.RIGHT_CLICK, { + onAppear: () => { + console.info(resource.resourceToString($r('app.string.SelectMenu_Text_4'))); + }, + onDisappear: () => { + console.info(resource.resourceToString($r('app.string.SelectMenu_Text_5'))); + } + }) + // [Start set_selection_menu_with_bindselectionmenu] + } + + ComponentCard({ title: $r('app.string.SetSelectionMenu_textContent_3') }) { + // [Start set_selection_menu_with_editmenuoptions] + Text($r('app.string.SelectMenu_textContent_1')) + .fontSize(20) + .copyOption(CopyOptions.LocalDevice) + .editMenuOptions({ + onCreateMenu: this.onCreateMenu, onMenuItemClick: this.onMenuItemClick + }) + // [End set_selection_menu_with_editmenuoptions] + } + } + .width('100%') + .height('100%') + .padding({ left: 12, right: 12 }) + } + .backgroundColor('#f1f2f3') + .title($r('app.string.SetSelectionMenu_title')) + } +} \ No newline at end of file diff --git a/ArkUISample/TextComponent/entry/src/main/ets/pages/text/TextAddEvent.ets b/ArkUISample/TextComponent/entry/src/main/ets/pages/text/TextAddEvent.ets new file mode 100644 index 0000000000000000000000000000000000000000..4675168db0e0026dcfded5f4884337ad4d80de84 --- /dev/null +++ b/ArkUISample/TextComponent/entry/src/main/ets/pages/text/TextAddEvent.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. + */ + +import { ComponentCard } from '../../common/Card'; + +@Entry +@Component +export struct TextAddEvent { + @State onClickText: ResourceStr = $r('app.string.TextAddEvent_textContent_1'); + + build() { + NavDestination() { + Column({ space: 12 }) { + ComponentCard({ title: $r('app.string.TextAddEvent_title') }) { + // [Start add_event_onclick] + Text(this.onClickText) + .id('Click') + .onClick(() => { + this.onClickText = $r('app.string.TextAddEvent_textContent_2'); + }) + // [End add_event_onclick] + } + } + .width('100%') + .height('100%') + .padding({ left: 12, right: 12 }) + } + .backgroundColor('#f1f2f3') + .title($r('app.string.TextAddEvent_title')) + } +} \ No newline at end of file diff --git a/ArkUISample/TextComponent/entry/src/main/ets/pages/text/TextHotSearch.ets b/ArkUISample/TextComponent/entry/src/main/ets/pages/text/TextHotSearch.ets new file mode 100644 index 0000000000000000000000000000000000000000..b3a3308e6e9b26cb8b031a83a458a0dd4c0377f6 --- /dev/null +++ b/ArkUISample/TextComponent/entry/src/main/ets/pages/text/TextHotSearch.ets @@ -0,0 +1,110 @@ +/* + * Copyright (c) 2025 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 the_text_fact_example] +import { ComponentCard } from '../../common/Card'; + +@Entry +@Component +export struct TextHotSearch { + build() { + NavDestination() { + Column({ space: 12 }) { + ComponentCard({ title: $r('app.string.TextHotSearch_title_1') }) { + Column() { + Row() { + Text('1').fontSize(14).fontColor(Color.Red).margin({ left: 10, right: 10 }) + Text($r('app.string.TextHotSearch_textContent_1')) + .fontSize(12) + .fontColor(Color.Blue) + .maxLines(1) + .textOverflow({ overflow: TextOverflow.Ellipsis }) + .fontWeight(300) + Text($r('app.string.TextHotSearch_textContent_2')) + .margin({ left: 6 }) + .textAlign(TextAlign.Center) + .fontSize(10) + .fontColor(Color.White) + .fontWeight(600) + .backgroundColor(0x770100) + .borderRadius(5) + .width(15) + .height(14) + }.width('100%').margin(5) + + Row() { + Text('2').fontSize(14).fontColor(Color.Red).margin({ left: 10, right: 10 }) + Text($r('app.string.TextHotSearch_textContent_3')) + .fontSize(12) + .fontColor(Color.Blue) + .fontWeight(300) + .constraintSize({ maxWidth: 200 }) + .maxLines(1) + .textOverflow({ overflow: TextOverflow.Ellipsis }) + Text($r('app.string.TextHotSearch_textContent_4')) + .margin({ left: 6 }) + .textAlign(TextAlign.Center) + .fontSize(10) + .fontColor(Color.White) + .fontWeight(600) + .backgroundColor(0xCC5500) + .borderRadius(5) + .width(15) + .height(14) + }.width('100%').margin(5) + + Row() { + Text('3').fontSize(14).fontColor(Color.Orange).margin({ left: 10, right: 10 }) + Text($r('app.string.TextHotSearch_textContent_5')) + .fontSize(12) + .fontColor(Color.Blue) + .fontWeight(300) + .maxLines(1) + .constraintSize({ maxWidth: 200 }) + .textOverflow({ overflow: TextOverflow.Ellipsis }) + Text($r('app.string.TextHotSearch_textContent_4')) + .margin({ left: 6 }) + .textAlign(TextAlign.Center) + .fontSize(10) + .fontColor(Color.White) + .fontWeight(600) + .backgroundColor(0xCC5500) + .borderRadius(5) + .width(15) + .height(14) + }.width('100%').margin(5) + + Row() { + Text('4').fontSize(14).fontColor(Color.Grey).margin({ left: 10, right: 10 }) + Text($r('app.string.TextHotSearch_textContent_6')) + .fontSize(12) + .fontColor(Color.Blue) + .fontWeight(300) + .constraintSize({ maxWidth: 200 }) + .maxLines(1) + .textOverflow({ overflow: TextOverflow.Ellipsis }) + }.width('100%').margin(5) + }.width('100%') + } + } + .width('100%') + .height('100%') + .padding({ left: 12, right: 12 }) + } + .backgroundColor('#f1f2f3') + .title($r('app.string.TextHotSearch_title')) + } +} +// [End the_text_fact_example] \ No newline at end of file diff --git a/ArkUISample/TextComponent/entry/src/main/ets/pages/text/TextSpan.ets b/ArkUISample/TextComponent/entry/src/main/ets/pages/text/TextSpan.ets new file mode 100644 index 0000000000000000000000000000000000000000..4d0abc81355a73605b4965f770e9387754481b52 --- /dev/null +++ b/ArkUISample/TextComponent/entry/src/main/ets/pages/text/TextSpan.ets @@ -0,0 +1,89 @@ +/* + * Copyright (c) 2025 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 { ComponentCard } from '../../common/Card'; + +@Entry +@Component +export struct TextSpan { + @State onClickText: ResourceStr = 'I am Upper-span2'; + + build() { + NavDestination() { + Column({ space: 12 }) { + ComponentCard({ title: $r('app.string.TextSpan_title_1') }) { + // [Start create_span] + Text($r('app.string.TextSpan_textContent_1')) { + Span($r('app.string.TextSpan_textContent_2')) + } + .padding(10) + .borderWidth(1) + // [End create_span] + } + + ComponentCard({ title: $r('app.string.TextSpan_title_2') }) { + // [Start create_span_with_lines] + Text() { + Span($r('app.string.TextSpan_textContent_3')) + .fontSize(16) + .fontColor(Color.Grey) + .decoration({ type: TextDecorationType.LineThrough, color: Color.Red }) + Span($r('app.string.TextSpan_textContent_4')) + .fontColor(Color.Blue) + .fontSize(16) + .fontStyle(FontStyle.Italic) + .decoration({ type: TextDecorationType.Underline, color: Color.Black }) + Span($r('app.string.TextSpan_textContent_5')) + .fontSize(16) + .fontColor(Color.Grey) + .decoration({ type: TextDecorationType.Overline, color: Color.Green }) + } + .borderWidth(1) + .padding(10) + // [End create_span_with_lines] + } + + ComponentCard({ title: $r('app.string.TextSpan_title_3') }) { + // [Start create_span_with_upper_case] + Text() { + Span('I am Upper-span').fontSize(12) + .textCase(TextCase.UpperCase) + } + .borderWidth(1) + .padding(10) + // [End create_span_with_upper_case] + } + + ComponentCard({ title: $r('app.string.TextSpan_title_4') }) { + // [Start create_span_with_onclick] + Text() { + Span(this.onClickText) + .fontSize(12) + .textCase(TextCase.UpperCase) + .onClick(() => { + this.onClickText = $r('app.string.TextSpan_textContent_6'); + }) + } + // [End create_span_with_onclick] + } + } + .width('100%') + .height('100%') + .padding({ left: 12, right: 12 }) + } + .backgroundColor('#f1f2f3') + .title($r('app.string.TextSpan_title')) + } +} \ No newline at end of file diff --git a/ArkUISample/TextComponent/entry/src/main/ets/pages/text/index.ets b/ArkUISample/TextComponent/entry/src/main/ets/pages/text/index.ets new file mode 100644 index 0000000000000000000000000000000000000000..266e20052a5fc87042689a5815bc8060727474fe --- /dev/null +++ b/ArkUISample/TextComponent/entry/src/main/ets/pages/text/index.ets @@ -0,0 +1,115 @@ +/* + * Copyright (c) 2025 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { CompletedRoutableCard } from '../../common/Card'; +import { CreateText } from './CreateText'; +import { CustomTextStyle } from './CustomTextStyle'; +import { Route } from '../../common/Route'; +import { TextAddEvent } from './TextAddEvent'; +import { TextHotSearch } from './TextHotSearch'; +import { TextSpan } from './TextSpan'; +import resource from '../../common/resource'; +import { SelectMenu } from './SelectMenu'; +import { AIMenu } from './AIMenu'; + +export const TEXT_ROUTE_PREFIX: string = 'text'; + +const routes: Route[] = [ + { + name: `${TEXT_ROUTE_PREFIX}/CreatText`, + title: resource.resourceToString($r('app.string.CreatText_title')), + description: $r('app.string.CreatText_description') + }, + { + name: `${TEXT_ROUTE_PREFIX}/TextSpan`, + title: resource.resourceToString($r('app.string.TextSpan_title')), + description: $r('app.string.TextSpan_description') + }, + { + name: `${TEXT_ROUTE_PREFIX}/CustomTextStyle`, + title: resource.resourceToString($r('app.string.CustomTextStyle_title')), + description: $r('app.string.CustomTextStyle_description') + }, + { + name: `${TEXT_ROUTE_PREFIX}/TextAddEvent`, + title: resource.resourceToString($r('app.string.TextAddEvent_title')), + description: $r('app.string.TextAddEvent_description') + }, + { + name: `${TEXT_ROUTE_PREFIX}/SelectMenu`, + title: resource.resourceToString($r('app.string.SetSelectionMenu_title')), + description: $r('app.string.SetSelectionMenu_description') + }, + { + name: `${TEXT_ROUTE_PREFIX}/AIMenu`, + title: resource.resourceToString($r('app.string.SetUpAIMenu_title')), + description: $r('app.string.SetUpAIMenu_description') + }, + { + name: `${TEXT_ROUTE_PREFIX}/TextHotSearch`, + title: resource.resourceToString($r('app.string.TextHotSearch_title')), + description: $r('app.string.TextHotSearch_description') + } +]; + +@Builder +export function TextDestination(name: string) { + if (name === TEXT_ROUTE_PREFIX) { + TextExample(); + } else if (name === routes[0].name) { + CreateText(); + } else if (name === routes[1].name) { + TextSpan(); + } else if (name === routes[2].name) { + CustomTextStyle(); + } else if (name === routes[3].name) { + TextAddEvent(); + } else if (name === routes[4].name) { + SelectMenu(); + } else if (name === routes[5].name) { + AIMenu(); + } else if (name === routes[6].name) { + TextHotSearch(); + } +} + +@Entry +@Component +struct TextExample { + @Consume pathStack: NavPathStack; + + build() { + NavDestination() { + List({ space: 12 }) { + ForEach(routes, (route: Route) => { + ListItem() { + CompletedRoutableCard({ title: route.title, description: route.description }) + } + .width('100%') + .onClick(() => { + this.pathStack.pushPath({ name: route.name }); + }) + }) + } + .contentStartOffset(56) + .padding({ left: 16, right: 16 }) + } + .backgroundColor('#f1f3f5') + .title('Text/Span', { + backgroundBlurStyle: BlurStyle.COMPONENT_THICK, + barStyle: BarStyle.STACK + }) + } +} \ No newline at end of file diff --git a/ArkUISample/TextComponent/entry/src/main/ets/pages/textInput/AutoFill.ets b/ArkUISample/TextComponent/entry/src/main/ets/pages/textInput/AutoFill.ets new file mode 100644 index 0000000000000000000000000000000000000000..5cdcceb7cdf74e2a0d92dc12d8a2bf3d92b4d5e7 --- /dev/null +++ b/ArkUISample/TextComponent/entry/src/main/ets/pages/textInput/AutoFill.ets @@ -0,0 +1,41 @@ +/* + * Copyright (c) 2025 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 { ComponentCard } from '../../common/Card'; + +@Entry +@Component +export struct AutoFill { + build() { + NavDestination() { + Column({ space: 12 }) { + ComponentCard({ description: $r('app.string.Auto_Fill_description') }) { + // [Start auto_fill] + TextInput({ placeholder: $r('app.string.Auto_Fill_PlaceHolder') }) + .width('95%') + .height(40) + .margin(20) + .contentType(ContentType.EMAIL_ADDRESS) + // [End auto_fill] + } + } + .width('100%') + .height('100%') + .padding({ left: 12, right: 12 }) + } + .backgroundColor('#f1f2f3') + .title($r('app.string.Auto_Fill')) + } +} \ No newline at end of file diff --git a/ArkUISample/TextComponent/entry/src/main/ets/pages/textInput/CreatTextInput.ets b/ArkUISample/TextComponent/entry/src/main/ets/pages/textInput/CreatTextInput.ets new file mode 100644 index 0000000000000000000000000000000000000000..6c8f1280d688fe1941892d529e7b214796919139 --- /dev/null +++ b/ArkUISample/TextComponent/entry/src/main/ets/pages/textInput/CreatTextInput.ets @@ -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. + */ + +import { ComponentCard } from '../../common/Card'; + +@Entry +@Component +export struct CreatTextInput { + build() { + NavDestination() { + Column({ space: 12 }) { + ComponentCard({ title: $r('app.string.CreatTextInput_title_1') }) { + // [Start create_text_input] + TextInput() + // [End create_text_input] + } + + ComponentCard({ + title: $r('app.string.CreatTextInput_title_2'), + description: $r('app.string.CreatTextInput_description_1') + }) { + Column({ space: 8 }) { + // [Start create_text_area] + TextArea() + // [End create_text_area] + // [Start create_text_area_example] + TextArea({ text: $r('app.string.CreatTextInput_textContent') }) + .width(300) + // [End create_text_area_example] + } + } + } + .width('100%') + .height('100%') + .padding({ left: 12, right: 12 }) + } + .backgroundColor('#f1f2f3') + .title($r('app.string.CreatTextInput_title')) + } +} \ No newline at end of file diff --git a/ArkUISample/TextComponent/entry/src/main/ets/pages/textInput/CursorAvoidance.ets b/ArkUISample/TextComponent/entry/src/main/ets/pages/textInput/CursorAvoidance.ets new file mode 100644 index 0000000000000000000000000000000000000000..57201b815e2837a4699f74711b9cc500c03b1d31 --- /dev/null +++ b/ArkUISample/TextComponent/entry/src/main/ets/pages/textInput/CursorAvoidance.ets @@ -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. + */ + +import { ComponentCard } from '../../common/Card'; + +// [Start cursor_avoid] +@Entry +@Component +export struct CursorAvoidance { + @State caretPosition: number = 600; + areaController: TextAreaController = new TextAreaController(); + text = 'Most of us compare ourselves with anyone we think is happier — a relative, someone we know a lot,' + + ' or someone we hardly know. As a result, what we do remember is anything that makes others happy, ' + + 'anything that makes ourselves unhappy,' + + ' totally forgetting that there is something happy in our own life.\ + So the best way to destroy happiness is to look at something and focus on even the smallest flaw. ' + + 'It is the smallest flaw that would make us complain. And it is the complaint that leads to us becoming unhappy.\ + If one chooses to be happy, he will be blessed; if he chooses to be unhappy, he will be cursed. ' + + 'Happiness is just what you think will make you happy.' + + 'Most of us compare ourselves with anyone we think is happier — a relative, someone we know a lot, ' + + 'or someone we hardly know. As a result, what we do remember is anything that makes others happy, ' + + 'anything that makes ourselves unhappy, totally forgetting that there is something happy in our own life.\ + '; + // : string = getResourceString($r('app.string.CursorAvoidance_Button_1')); + @State str1 : string = getContext(this).resourceManager.getStringSync($r('app.string.CursorAvoidance_Button_1')); + @State str2 : string = getContext(this).resourceManager.getStringSync($r('app.string.CursorAvoidance_Button_2')); + + build() { + NavDestination() { + ComponentCard({ title: $r('app.string.CursorAvoidance_title') }) { + Scroll() { + Column() { + Row() { + + Button(this.str1 + this.caretPosition).onClick(() => { + this.caretPosition += 1; + }).fontSize(10) + Button(this.str2 + this.caretPosition).onClick(() => { + this.caretPosition -= 1; + }).fontSize(10) + Button($r('app.string.CursorAvoidance_Button_3')).onClick(() => { + this.areaController.caretPosition(this.caretPosition); + }).fontSize(10) + } + + TextArea({ text: this.text, controller: this.areaController }) + .width('100%') + .fontSize('20fp') + } + }.width('100%').height('100%') + } + } + .backgroundColor('#f1f2f3') + .title($r('app.string.CursorAvoidance_title')) + } +} +// [End cursor_avoid] \ No newline at end of file diff --git a/ArkUISample/TextComponent/entry/src/main/ets/pages/textInput/CustomTextInputStyle.ets b/ArkUISample/TextComponent/entry/src/main/ets/pages/textInput/CustomTextInputStyle.ets new file mode 100644 index 0000000000000000000000000000000000000000..6bfeaf93dbdfce9a7117eee3a7687a369dd6ff63 --- /dev/null +++ b/ArkUISample/TextComponent/entry/src/main/ets/pages/textInput/CustomTextInputStyle.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. + */ + +import { ComponentCard } from '../../common/Card'; + +@Entry +@Component +export struct CustomTextInputStyle { + build() { + NavDestination() { + Column({ space: 12 }) { + ComponentCard({ title: $r('app.string.CustomTextInputStyle_title_1') }) { + // [Start custom_text_input_with_place_holder] + TextInput({ placeholder: $r('app.string.CustomTextInputStyle_textContent_1') }) + // [End custom_text_input_with_place_holder] + } + + ComponentCard({ title: $r('app.string.CustomTextInputStyle_title_2') }) { + // [Start custom_text_input_with_place_holder_and_text] + TextInput({ + placeholder: $r('app.string.CustomTextInputStyle_textContent_1'), + text: $r('app.string.CustomTextInputStyle_textContent_2') + }) + // [End custom_text_input_with_place_holder_and_text] + } + + ComponentCard({ title: $r('app.string.CustomTextInputStyle_title_3') }) { + // [Start custom_text_input_background_color] + TextInput({ + placeholder: $r('app.string.CustomTextInputStyle_textContent_1'), + text: $r('app.string.CustomTextInputStyle_textContent_2') + }) + .backgroundColor(Color.Pink) + // [End custom_text_input_background_color] + } + } + .width('100%') + .height('100%') + .padding({ left: 12, right: 12 }) + } + .backgroundColor('#f1f2f3') + .title($r('app.string.CustomTextInputStyle_title')) + } +} \ No newline at end of file diff --git a/ArkUISample/TextComponent/entry/src/main/ets/pages/textInput/KeyboardAvoidance.ets b/ArkUISample/TextComponent/entry/src/main/ets/pages/textInput/KeyboardAvoidance.ets new file mode 100644 index 0000000000000000000000000000000000000000..642e19c958f52a3cb993303b57c30c7cba2bc7be --- /dev/null +++ b/ArkUISample/TextComponent/entry/src/main/ets/pages/textInput/KeyboardAvoidance.ets @@ -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. + */ + +import { ComponentCard } from '../../common/Card'; + +// [Start keyboard_avoid] +@Entry +@Component +export struct KeyboardAvoidance { + placeHolderArr: string[] = ['1', '2', '3', '4', '5', '6', '7']; + + build() { + // [StartExclude keyboard_avoid] + NavDestination() { + Column({ space: 12 }) { + ComponentCard({ title: $r('app.string.KeyboardAvoidance_title') }) { + Column({ space: 12 }) { + // [EndExclude keyboard_avoid] + Scroll() { + Column() { + ForEach(this.placeHolderArr, (placeholder: string) => { + TextInput({ placeholder: 'TextInput ' + placeholder }) + .margin(30) + }) + } + } + .height('95%') + .width('100%') + } + } + // [End keyboard_avoid] + } + .width('100%') + .height('100%') + .padding({ left: 12, right: 12 }) + } + .backgroundColor('#f1f2f3') + .title($r('app.string.KeyboardAvoidance_title')) + } +} \ No newline at end of file diff --git a/ArkUISample/TextComponent/entry/src/main/ets/pages/textInput/LoginRegisterPage.ets b/ArkUISample/TextComponent/entry/src/main/ets/pages/textInput/LoginRegisterPage.ets new file mode 100644 index 0000000000000000000000000000000000000000..3998f3dcea363e128b1ac349478d1b75c0ce33df --- /dev/null +++ b/ArkUISample/TextComponent/entry/src/main/ets/pages/textInput/LoginRegisterPage.ets @@ -0,0 +1,54 @@ +/* + * Copyright (c) 2025 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 { ComponentCard } from '../../common/Card'; +import resource from '../../common/resource'; + +// [Start the_example_of_text_input] +@Entry +@Component +export struct LoginRegisterPage { + build() { + // [StartExclude the_example_of_text_input] + NavDestination() { + Column({ space: 12 }) { + ComponentCard({ title: $r('app.string.LoginRegisterPage_title') }) { + // [EndExclude the_example_of_text_input] + Column({ space: 12 }) { + TextInput({ placeholder: 'input your username' }) + .id('username') + .onSubmit((enterKeyType) => { + console.info(enterKeyType + resource.resourceToString($r('app.string.LoginRegisterPage_textContent'))); + }) + TextInput({ placeholder: 'input your password' }) + .id('password') + .type(InputType.Password) + .onSubmit((enterKeyType) => { + console.info(enterKeyType + resource.resourceToString($r('app.string.LoginRegisterPage_textContent'))); + }) + Button($r('app.string.LoginRegisterPage_Button_3')) + .width('100%') + } + } + } + .width('100%') + .height('100%') + .padding({ left: 12, right: 12 }) + } + // [End the_example_of_text_input] + .backgroundColor('#f1f2f3') + .title($r('app.string.LoginRegisterPage_title')) + } +} \ No newline at end of file diff --git a/ArkUISample/TextComponent/entry/src/main/ets/pages/textInput/SelectMenu.ets b/ArkUISample/TextComponent/entry/src/main/ets/pages/textInput/SelectMenu.ets new file mode 100644 index 0000000000000000000000000000000000000000..1f782392a69b9e376cf1bcef290059607ad3671d --- /dev/null +++ b/ArkUISample/TextComponent/entry/src/main/ets/pages/textInput/SelectMenu.ets @@ -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. + */ + +import { ComponentCard } from '../../common/Card'; + +@Entry +@Component +export struct SelectMenu { + build() { + NavDestination() { + Column({ space: 12 }) { + ComponentCard({ description: $r('app.string.SelectionMenu_description') }) { + Column({ space: 8 }) { + // [Start select_textinput] + TextInput({ text: $r('app.string.SelectMenu_textContent_1') }) + // [End select_textinput] + // [Start select_textarea] + TextArea({ text: $r('app.string.SelectMenu_textContent_1') }) + // [End select_textarea] + } + } + } + .width('100%') + .height('100%') + .padding({ left: 12, right: 12 }) + } + .backgroundColor('#f1f2f3') + .title($r('app.string.SelectionMenu_title')) + } +} \ No newline at end of file diff --git a/ArkUISample/TextComponent/entry/src/main/ets/pages/textInput/SetOmissionProperty.ets b/ArkUISample/TextComponent/entry/src/main/ets/pages/textInput/SetOmissionProperty.ets new file mode 100644 index 0000000000000000000000000000000000000000..cdf8397bfc230bee0cc98f07f7642aace1a87560 --- /dev/null +++ b/ArkUISample/TextComponent/entry/src/main/ets/pages/textInput/SetOmissionProperty.ets @@ -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. + */ + +import { ComponentCard } from '../../common/Card'; + +@Entry +@Component +export struct SetOmissionProperty { + build() { + NavDestination() { + Column({ space: 12 }) { + ComponentCard({ description: $r('app.string.Set_Omission_Property_description') }) { + // [Start set_omission_property] + TextInput({ text: $r('app.string.Set_Omission_Property_textContent') }) + .textOverflow(TextOverflow.Ellipsis) + .ellipsisMode(EllipsisMode.END) + .style(TextInputStyle.Inline) + .fontSize(30) + .margin(30) + // [End set_omission_property] + } + } + .width('100%') + .height('100%') + .padding({ left: 12, right: 12 }) + } + .backgroundColor('#f1f2f3') + .title($r('app.string.Set_Omission_Property')) + } +} \ No newline at end of file diff --git a/ArkUISample/TextComponent/entry/src/main/ets/pages/textInput/SetTextInputType.ets b/ArkUISample/TextComponent/entry/src/main/ets/pages/textInput/SetTextInputType.ets new file mode 100644 index 0000000000000000000000000000000000000000..566fd00c217e6c4afbe2ca08435d7fbd2b20a1ed --- /dev/null +++ b/ArkUISample/TextComponent/entry/src/main/ets/pages/textInput/SetTextInputType.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 { ComponentCard } from '../../common/Card'; + +@Entry +@Component +export struct SetTextInputType { + build() { + NavDestination() { + Scroll() { + Grid() { + GridItem() { + ComponentCard({ title: $r('app.string.SetTextInputType_title_1') }) { + TextInput() + .id('Normal') + .type(InputType.Normal) + } + }.width('33%') + GridItem() { + ComponentCard({ title: $r('app.string.SetTextInputType_title_2') }) { + // [Start set_password_input_type] + TextInput() + .id('Password') + .type(InputType.Password) + // [End set_password_input_type] + } + }.width('33%') + GridItem() { + ComponentCard({ title: $r('app.string.SetTextInputType_title_3') }) { + // [Start set_email_input_type] + TextInput() + .id('Email') + .type(InputType.Email) + // [End set_email_input_type] + } + }.width('33%') + GridItem() { + ComponentCard({ title: $r('app.string.SetTextInputType_title_4') }) { + // [Start set_number_input_type] + TextInput() + .id('Number') + .type(InputType.Number) + // [End set_number_input_type] + } + }.width('33%') + GridItem() { + ComponentCard({ title: $r('app.string.SetTextInputType_title_5') }) { + // [Start set_phonenumber_input_type] + TextInput() + .id('PhoneNumber') + .type(InputType.PhoneNumber) + // [End set_phonenumber_input_type] + } + }.width('33%') + GridItem() { + ComponentCard({ title: $r('app.string.SetTextInputType_title_6') }) { + // [Start set_number_decimal_input_type] + TextInput() + .id('NUMBER_DECIMAL') + .type(InputType.NUMBER_DECIMAL) + // [End set_number_decimal_input_type] + } + }.width('33%') + GridItem() { + ComponentCard({ title: $r('app.string.SetTextInputType_title_7') }) { + // [Start set_url_input_type] + TextInput() + .id('URL') + .type(InputType.URL) + // [End set_url_input_type] + } + }.width('33%') + } + .width('100%') + .height('100%') + .padding({ left: 12, right: 12 }) + }.id('scroll_') + } + .backgroundColor('#f1f2f3') + .title($r('app.string.SetTextInputType_title')) + } +} \ No newline at end of file diff --git a/ArkUISample/TextComponent/entry/src/main/ets/pages/textInput/TextInputAddEvent.ets b/ArkUISample/TextComponent/entry/src/main/ets/pages/textInput/TextInputAddEvent.ets new file mode 100644 index 0000000000000000000000000000000000000000..18a68f293890536c3465e288827b3be359014c71 --- /dev/null +++ b/ArkUISample/TextComponent/entry/src/main/ets/pages/textInput/TextInputAddEvent.ets @@ -0,0 +1,90 @@ +/* + * Copyright (c) 2025 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 { ComponentCard } from '../../common/Card'; + +@Entry +@Component +export struct TextInputAddEvent { + @State eventText: ResourceStr = $r('app.string.TextInputAddEvent_textContent_1'); + @State inputValue: ResourceStr = $r('app.string.TextInputAddEvent_textContent_2'); + controller: TextInputController = new TextInputController(); + passwordState: boolean = false; + + build() { + NavDestination() { + Column({ space: 12 }) { + ComponentCard({ title: $r('app.string.TextInputAddEvent_title_1') }) { + Column({ space: 8 }) { + Text(this.eventText) + Text(this.inputValue) + // [Start add_text_input_event] + TextInput({ + text: $r('app.string.TextInputAddEvent_textContent_2'), + placeholder: 'input your word...', + controller: this.controller + }) + .type(InputType.Password) + .showPassword(this.passwordState) + .onChange((value: string) => { + // 文本内容发生变化时触发该回调 + this.inputValue = 'onChange is triggering: ' + value; + }) + .onSubmit((enterKey: EnterKeyType, event: SubmitEvent) => { + // 按下输入法回车键时触发该回调 + this.eventText = 'onSubmit is triggering: ' + enterKey + ' ' + event.text; + }) + .onTextSelectionChange((selectionStart: number, selectionEnd: number) => { + // 文本选择的位置发生变化或编辑状态下光标位置发生变化时,触发该回调 + this.eventText = 'onTextSelectionChange is triggering: ' + selectionStart + ' ' + selectionEnd; + }) + .onSecurityStateChange((isShowPassword: boolean) => { + // 密码显隐状态切换时,触发该回调 + this.eventText = 'onSecurityStateChange is triggering: ' + isShowPassword + this.passwordState = isShowPassword; + }) + .onWillInsert((info: InsertValue) => { + // 在将要输入时,触发该回调 + this.eventText = 'onWillInsert is triggering: ' + info.insertValue + ' ' + info.insertOffset; + return true; + }) + .onDidInsert((info: InsertValue) => { + // 在输入完成时,触发该回调 + this.eventText = 'onDidInsert is triggering: ' + info.insertValue + ' ' + info.insertOffset + }) + .onWillDelete((info: DeleteValue) => { + // 在将要删除时,触发该回调 + this.eventText = 'onWillDelete is triggering: ' + info.deleteValue + ' ' + info.deleteOffset + return true; + }) + .onDidDelete((info: DeleteValue) => { + // 在删除完成时,触发该回调 + this.eventText = 'onDidDelete is triggering: ' + info.deleteValue + ' ' + info.deleteOffset + }) + .onFocus(() => { + this.eventText = $r('app.string.TextInputAddEvent_textContent_3'); + }) + // [End add_text_input_event] + } + } + } + .width('100%') + .height('100%') + .padding({ left: 12, right: 12 }) + } + .backgroundColor('#f1f2f3') + .title($r('app.string.TextInputAddEvent_title')) + } +} \ No newline at end of file diff --git a/ArkUISample/TextComponent/entry/src/main/ets/pages/textInput/index.ets b/ArkUISample/TextComponent/entry/src/main/ets/pages/textInput/index.ets new file mode 100644 index 0000000000000000000000000000000000000000..91475ab18832a47e42303551cacb889d9784a27c --- /dev/null +++ b/ArkUISample/TextComponent/entry/src/main/ets/pages/textInput/index.ets @@ -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. + */ + +import { CompletedRoutableCard } from '../../common/Card'; + +import { Route } from '../../common/Route'; +import { CreatTextInput } from './CreatTextInput'; +import { CustomTextInputStyle } from './CustomTextInputStyle'; +import { KeyboardAvoidance } from './KeyboardAvoidance'; +import { LoginRegisterPage } from './LoginRegisterPage'; +import { SetTextInputType } from './SetTextInputType'; +import { TextInputAddEvent } from './TextInputAddEvent'; +import resource from '../../common/resource'; +import { SelectMenu } from './SelectMenu'; +import { AutoFill } from './AutoFill'; +import { SetOmissionProperty } from './SetOmissionProperty'; +import { CursorAvoidance } from './CursorAvoidance'; + +export const INPUT_ROUTE_PREFIX: string = 'TextInput'; + +const routes: Route[] = [ + { + name: `${INPUT_ROUTE_PREFIX}/CreatTextInput`, + title: resource.resourceToString($r('app.string.CreatTextInput_title')), + description: $r('app.string.CreatTextInput_description') + }, + { + name: `${INPUT_ROUTE_PREFIX}/SetTextInputType`, + title: resource.resourceToString($r('app.string.SetTextInputType_title')), + description: $r('app.string.SetTextInputType_description') + }, + { + name: `${INPUT_ROUTE_PREFIX}/CustomTextInputStyle`, + title: resource.resourceToString($r('app.string.CustomTextInputStyle_title')), + description: $r('app.string.CustomTextInputStyle_description') + }, + { + name: `${INPUT_ROUTE_PREFIX}/TextInputAddEvent`, + title: resource.resourceToString($r('app.string.TextInputAddEvent_title')), + description: $r('app.string.TextInputAddEvent_description') + }, + { + name: `${INPUT_ROUTE_PREFIX}/SelectMenu`, + title: resource.resourceToString($r('app.string.SelectionMenu_title')), + description: $r('app.string.SelectionMenu_description') + }, + { + name: `${INPUT_ROUTE_PREFIX}/AutoFill`, + title: resource.resourceToString($r('app.string.Auto_Fill')), + description: $r('app.string.Auto_Fill_description') + }, + { + name: `${INPUT_ROUTE_PREFIX}/SetOmissionProperty`, + title: resource.resourceToString($r('app.string.Set_Omission_Property')), + description: $r('app.string.Set_Omission_Property_description') + }, + { + name: `${INPUT_ROUTE_PREFIX}/KeyboardAvoidance`, + title: resource.resourceToString($r('app.string.KeyboardAvoidance_title')), + description: $r('app.string.KeyboardAvoidance_description') + }, + { + name: `${INPUT_ROUTE_PREFIX}/CursorAvoidance`, + title: resource.resourceToString($r('app.string.CursorAvoidance_title')), + description: $r('app.string.CursorAvoidance_description') + }, + { + name: `${INPUT_ROUTE_PREFIX}/LoginRegisterPage`, + title: resource.resourceToString($r('app.string.LoginRegisterPage_title')), + description: $r('app.string.LoginRegisterPage_description') + } +]; + +@Builder +export function TextInputDestination(name: string) { + if (name === INPUT_ROUTE_PREFIX) { + TextInputExample(); + } else if (name === routes[0].name) { + CreatTextInput(); + } else if (name === routes[1].name) { + SetTextInputType(); + } else if (name === routes[2].name) { + CustomTextInputStyle(); + } else if (name === routes[3].name) { + TextInputAddEvent(); + } else if (name === routes[4].name) { + SelectMenu(); + } else if (name === routes[5].name) { + AutoFill(); + } else if (name === routes[6].name) { + SetOmissionProperty(); + } else if (name === routes[7].name) { + KeyboardAvoidance(); + } else if (name === routes[8].name) { + CursorAvoidance(); + } else if (name === routes[9].name) { + LoginRegisterPage(); + } +} + +@Entry +@Component +struct TextInputExample { + @Consume pathStack: NavPathStack; + + build() { + NavDestination() { + Scroll() { + List({ space: 12 }) { + ForEach(routes, (route: Route) => { + ListItem() { + CompletedRoutableCard({ title: route.title, description: route.description }) + } + .width('100%') + .onClick(() => { + this.pathStack.pushPath({ name: route.name }); + }) + }) + } + .contentStartOffset(56) + .padding({ left: 16, right: 16 }) + }.id('scroll_') + } + .backgroundColor('#f1f3f5') + .title('TextInput/TextArea', { + backgroundBlurStyle: BlurStyle.COMPONENT_THICK, + barStyle: BarStyle.STACK + }) + } +} \ No newline at end of file diff --git a/ArkUISample/TextComponent/entry/src/main/module.json5 b/ArkUISample/TextComponent/entry/src/main/module.json5 new file mode 100644 index 0000000000000000000000000000000000000000..4144486d1af4c03b0d767cce1cda86fc0d697f91 --- /dev/null +++ b/ArkUISample/TextComponent/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": [ + "action.system.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/ArkUISample/TextComponent/entry/src/main/resources/base/element/color.json b/ArkUISample/TextComponent/entry/src/main/resources/base/element/color.json new file mode 100644 index 0000000000000000000000000000000000000000..3c712962da3c2751c2b9ddb53559afcbd2b54a02 --- /dev/null +++ b/ArkUISample/TextComponent/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/ArkUISample/TextComponent/entry/src/main/resources/base/element/float.json b/ArkUISample/TextComponent/entry/src/main/resources/base/element/float.json new file mode 100644 index 0000000000000000000000000000000000000000..a0a93dd91fd48f08f3a9532c76e9b26e68d4c034 --- /dev/null +++ b/ArkUISample/TextComponent/entry/src/main/resources/base/element/float.json @@ -0,0 +1,8 @@ +{ + "float": [ + { + "name": "page_text_font_size", + "value": "50fp" + } + ] +} \ No newline at end of file diff --git a/ArkUISample/TextComponent/entry/src/main/resources/base/element/string.json b/ArkUISample/TextComponent/entry/src/main/resources/base/element/string.json new file mode 100644 index 0000000000000000000000000000000000000000..73b3acaef15802ff2f03a357a5ed977d861bd736 --- /dev/null +++ b/ArkUISample/TextComponent/entry/src/main/resources/base/element/string.json @@ -0,0 +1,1232 @@ +{ + "string": [ + { + "name": "module_desc", + "value": "模块描述" + }, + { + "name": "EntryAbility_desc", + "value": "description" + }, + { + "name": "EntryAbility_label", + "value": "TextComponent" + }, + { + "name": "pageIndex_Text", + "value": "文本显示(Text/Span)" + }, + { + "name": "pageIndex_TextInput", + "value": "文本输入(TextInput/TextArea)" + }, + { + "name": "pageIndex_RichEditor", + "value": "富文本(RichEditor)" + }, + { + "name": "pageIndex_PropertyString", + "value": "属性字符串(StyledString/MutableStyledString)" + }, + { + "name": "pageIndex_TextNDKUI", + "value": "使用文本(NDK)" + }, + { + "name": "CreatText_title", + "value": "创建文本" + }, + { + "name": "CreatText_title_1", + "value": "string字符串" + }, + { + "name": "CreatText_title_2", + "value": "引用Resource资源" + }, + { + "name": "TextSpan_title", + "value": "添加子组件" + }, + { + "name": "TextSpan_title_1", + "value": "创建Span" + }, + { + "name": "TextSpan_title_2", + "value": "设置文本装饰线及颜色" + }, + { + "name": "TextSpan_title_3", + "value": "通过textCase设置文字一直保持大写或者小写状态" + }, + { + "name": "TextSpan_title_4", + "value": "添加事件" + }, + { + "name": "TextSpan_description", + "value": "Span只能作为Text和RichEditor组件的子组件显示文本内容,可以在一个Text内添加多个Span来显示一段信息" + }, + { + "name": "TextSpan_textContent_1", + "value": "我是Text" + }, + { + "name": "TextSpan_textContent_2", + "value": "我是Span" + }, + { + "name": "TextSpan_textContent_3", + "value": "我是Span1," + }, + { + "name": "TextSpan_textContent_4", + "value": "我是Span2" + }, + { + "name": "TextSpan_textContent_5", + "value": ",我是Span3" + }, + { + "name": "TextSpan_textContent_6", + "value": "我是Span——onClick" + }, + { + "name": "CreatText_description", + "value": "示例使用string字符串和引用Resource资源两种方式来创建文本" + }, + { + "name": "CreatText_description_1", + "value": "资源引用类型可以通过$r创建Resource类型对象,文件位置为/resources/base/element/string.json" + }, + { + "name": "CustomTextStyle_title", + "value": "自定义文本样式" + }, + { + "name": "CustomTextStyle_title_1", + "value": "通过textAlign属性设置文本对齐样式" + }, + { + "name": "CustomTextStyle_title_2", + "value": "通过textOverflow属性控制文本超长处理" + }, + { + "name": "CustomTextStyle_title_3", + "value": "通过lineHeight属性设置文本行高" + }, + { + "name": "CustomTextStyle_title_4", + "value": "通过decoration属性设置文本装饰线样式及其颜色" + }, + { + "name": "CustomTextStyle_title_5", + "value": "通过baselineOffset属性设置文本基线的偏移量" + }, + { + "name": "CustomTextStyle_title_6", + "value": "通过letterSpacing属性设置文本字符间距" + }, + { + "name": "CustomTextStyle_title_7", + "value": "通过minFontSize与maxFontSize自适应字体大小" + }, + { + "name": "CustomTextStyle_title_8", + "value": "通过textCase属性设置文本大小写" + }, + { + "name": "CustomTextStyle_title_9", + "value": "通过copyOption属性设置文本是否可复制粘贴" + }, + { + "name": "CustomTextStyle_description", + "value": "示例中展示对文本的对齐、文本超长处理、文本行高、装饰线等属性进行设置的自定义文本样式" + }, + { + "name": "CustomTextStyle_description_1", + "value": "textOverflow需配合maxLines一起使用(默认情况下文本自动折行)。从API version 18开始,文本超长时设置跑马灯的方式展示时,支持设置跑马灯的配置项,比如开关、步长、循环次数、方向等" + }, + { + "name": "CustomTextStyle_textContent_1", + "value": "我是超长文本,超出的部分显示省略号 I am an extra long text, with ellipses displayed for any excess。" + }, + { + "name": "CustomTextStyle_textContent_2", + "value": "当文本溢出其尺寸时,文本将滚动显示 When the text overflows its dimensions,the text will scroll for displaying." + }, + { + "name": "CustomTextStyle_textContent_3", + "value": "我的最大字号为30,最小字号为5,宽度为250,maxLines为1" + }, + { + "name": "CustomTextStyle_textContent_4", + "value": "我的最大字号为30,最小字号为5,宽度为250,maxLines为2" + }, + { + "name": "CustomTextStyle_textContent_5", + "value": "我的最大字号为30,最小字号为15,宽度为250,高度为50" + }, + { + "name": "CustomTextStyle_textContent_6", + "value": "我的最大字号为30,最小字号为15,宽度为250,高度为100" + }, + { + "name": "CustomTextStyle_textContent_7", + "value": "这是一段可复制文本。" + }, + { + "name": "CustomTextStyle_textContent_8", + "value": "当文本溢出其尺寸时,文本将滚动显示,支持设置跑马灯配置项 When the text overflows its dimensions, the text will scroll for displaying." + }, + { + "name": "TextAlign_Start", + "value": "左对齐" + }, + { + "name": "TextAlign_Center", + "value": "中间对齐" + }, + { + "name": "TextAlign_End", + "value": "右对齐" + }, + { + "name": "TextAddEvent_title", + "value": "添加事件" + }, + { + "name": "SetSelectionMenu_title", + "value": "设置选中菜单" + }, + { + "name": "SelectionMenu_title", + "value": "选中菜单" + }, + { + "name": "SelectionMenu_description", + "value": "输入框中的文字被选中时会弹出包含剪切、复制、翻译、搜索的菜单" + }, + { + "name": "SetSelectionMenu_description", + "value": "设置Text被选中时,会弹出包含复制、翻译、搜索以及自定义的菜单" + }, + { + "name": "SetSelectionMenu_textContent_1", + "value": "Text组件需要设置copyOption属性才可以被选中" + }, + { + "name": "SetSelectionMenu_textContent_2", + "value": "Text组件通过设置bindSelectionMenu属性绑定自定义选择菜单" + }, + { + "name": "SetSelectionMenu_textContent_3", + "value": "Text组件通过设置editMenuOptions属性扩展自定义选择菜单,可以设置扩展项的文本内容、图标以及回调方法" + }, + { + "name": "TextAddEvent_description", + "value": "Text组件可以添加通用事件,可以绑定onClick、onTouch等事件来响应操作" + }, + { + "name": "TextAddEvent_textContent_1", + "value": "点我" + }, + { + "name": "TextAddEvent_textContent_2", + "value": "我是Text的点击响应事件" + }, + { + "name": "TextHotSearch_title", + "value": "场景示例" + }, + { + "name": "TextHotSearch_title_1", + "value": "热搜榜示例" + }, + { + "name": "TextHotSearch_description", + "value": "示例通过maxLines、textOverflow、textAlign、constraintSize属性展示了热搜榜的效果" + }, + { + "name": "TextHotSearch_textContent_1", + "value": "我是热搜词条1" + }, + { + "name": "TextHotSearch_textContent_2", + "value": "爆" + }, + { + "name": "TextHotSearch_textContent_3", + "value": "我是热搜词条2 我是热搜词条2 我是热搜词条2 我是热搜词条2 我是热搜词条2" + }, + { + "name": "TextHotSearch_textContent_4", + "value": "热" + }, + { + "name": "TextHotSearch_textContent_5", + "value": "我是热搜词条3" + }, + { + "name": "TextHotSearch_textContent_6", + "value": "我是热搜词条4 我是热搜词条4 我是热搜词条4 我是热搜词条4 我是热搜词条4" + }, + { + "name": "CreatTextInput_title", + "value": "创建输入框" + }, + { + "name": "CreatTextInput_title_1", + "value": "单行输入框" + }, + { + "name": "CreatTextInput_title_2", + "value": "多行输入框" + }, + { + "name": "CreatTextInput_description", + "value": "示例通过接口创建文本输入框,其中TextInput为单行输入框、TextArea为多行输入框" + }, + { + "name": "CreatTextInput_description_1", + "value": "多行输入框文字超出一行时会自动折行" + }, + { + "name": "CreatTextInput_textContent", + "value": "我是TextArea我是TextArea我是TextArea我是TextArea" + }, + { + "name": "SetTextInputType_title", + "value": "设置输入框类型" + }, + { + "name": "SetTextInputType_title_1", + "value": "基本输入模式(默认类型)" + }, + { + "name": "SetTextInputType_title_2", + "value": "密码输入模式" + }, + { + "name": "SetTextInputType_title_3", + "value": "邮箱地址输入模式" + }, + { + "name": "SetTextInputType_title_4", + "value": "纯数字输入模式" + }, + { + "name": "SetTextInputType_title_5", + "value": "电话号码输入模式" + }, + { + "name": "SetTextInputType_title_6", + "value": "带小数点的数字输入模式" + }, + { + "name": "SetTextInputType_title_7", + "value": "带URL的输入模式" + }, + { + "name": "SetTextInputType_description", + "value": "TextInput有9种可选类型,示例中展示Normal基本输入模式和Password密码输入模式两种类型" + }, + { + "name": "CustomTextInputStyle_title", + "value": "自定义样式" + }, + { + "name": "CustomTextInputStyle_title_1", + "value": "设置无输入时的提示文本" + }, + { + "name": "CustomTextInputStyle_title_2", + "value": "设置输入框当前的文本内容" + }, + { + "name": "CustomTextInputStyle_title_3", + "value": "添加backgroundColor改变输入框的背景颜色" + }, + { + "name": "CustomTextInputStyle_description", + "value": "示例对输入框的提示文本、文本内容和背景颜色进行展示,更丰富的样式可以结合通用属性实现" + }, + { + "name": "CustomTextInputStyle_textContent_1", + "value": "我是提示文本" + }, + { + "name": "CustomTextInputStyle_textContent_2", + "value": "我是当前文本内容" + }, + { + "name": "TextInputAddEvent_title", + "value": "添加事件" + }, + { + "name": "TextInputAddEvent_title_1", + "value": "设置无输入时的提示文本" + }, + { + "name": "TextInputAddEvent_description", + "value": "文本框主要用于获取用户输入的信息,把信息处理成数据进行上传,绑定onChange事件可以获取输入框内改变的内容。用户也可以使用通用事件来进行相应的交互操作" + }, + { + "name": "TextInputAddEvent_textContent_1", + "value": "焦点事件" + }, + { + "name": "TextInputAddEvent_textContent_2", + "value": "输入值" + }, + { + "name": "TextInputAddEvent_textContent_3", + "value": "获取焦点" + }, + { + "name": "LoginRegisterPage_title", + "value": "登录/注册示例" + }, + { + "name": "LoginRegisterPage_description", + "value": "示例模仿用户在登录/注册页面,进行登录或注册" + }, + { + "name": "LoginRegisterPage_textContent", + "value": "输入法回车键的类型值" + }, + { + "name": "KeyboardAvoidance_title", + "value": "键盘避让" + }, + { + "name": "CursorAvoidance_title", + "value": "光标避让" + }, + { + "name": "CursorAvoidance_description", + "value": "keyBoardAvoidMode枚举中的OFFSET和RESIZE在键盘抬起后,不支持二次避让。如果想要支持光标位置在点击或者通过接口设置变化后发生二次避让,可以考虑使用OFFSET_WITH_CARET和RESIZE_CARET替换原有的OFFSET和RESIZE模式。\n对于滚动容器更推荐使用RESIZE_WITH_CARET,非滚动容器应该使用OFFSET_WITH_CARET。" + }, + { + "name": "KeyboardAvoidance_description", + "value": "示例中键盘抬起后,具有滚动能力的容器组件在横竖屏切换时,才会生效键盘避让" + }, + { + "name": "SelectMenu_textContent_1", + "value": "这是一段文本,用来展示选中菜单" + }, + { + "name": "SelectMenu_textContent_2", + "value": "自定义选择菜单弹出时触发该回调" + }, + { + "name": "SelectMenu_textContent_3", + "value": "自定义选择菜单关闭时触发该回调" + }, + { + "name": "SetUpAIMenu_title", + "value": "设置AI菜单" + }, + { + "name": "SetUpAIMenu_description", + "value": "Text组件通过enableDataDetector和dataDetectorConfig属性实现AI菜单的显示" + }, + { + "name": "Auto_Fill", + "value": "自动填充" + }, + { + "name": "Auto_Fill_description", + "value": "输入框可以通过contentType属性设置自动填充类型" + }, + { + "name": "Auto_Fill_PlaceHolder", + "value": "输入你的邮箱..." + }, + { + "name": "Set_Omission_Property", + "value": "设置省略属性" + }, + { + "name": "Set_Omission_Property_description", + "value": "输入框可以通过ellipsisMode属性设置省略位置" + }, + { + "name": "Set_Omission_Property_textContent", + "value": "这是一段文本,用来展示省略模式" + }, + { + "name": "Create_RichEditor_Component_title", + "value": "创建RichEditor组件" + }, + { + "name": "Create_RichEditor_Component_title_1", + "value": "创建使用属性字符串构建的RichEditor组件" + }, + { + "name": "Create_RichEditor_Component_title_2", + "value": "创建不使用属性字符串构建的RichEditor组件" + }, + { + "name": "Create_RichEditor_Component_description", + "value": "开发者可以创建使用属性字符串和不使用属性字符串构建的RichEditor组件" + }, + { + "name": "Set_Attributes_title", + "value": "设置属性" + }, + { + "name": "Set_Attributes_title_1", + "value": "设置自定义选择菜单" + }, + { + "name": "Set_Attributes_title_1_desc", + "value": "通过bindSelectionMenu设置自定义选择菜单" + }, + { + "name": "Set_Attributes_title_2", + "value": "设置输入框光标、手柄颜色" + }, + { + "name": "Set_Attributes_title_2_desc", + "value": "通过caretColor设置输入框光标、手柄颜色" + }, + { + "name": "Set_Attributes_title_3", + "value": "设置无输入时的提示文本" + }, + { + "name": "Set_Attributes_title_3_desc", + "value": "通过placeholder设置无输入时的提示文本" + }, + { + "name": "Set_Attributes_title_4", + "value": "设置最大行数" + }, + { + "name": "Set_Attributes_title_4_desc", + "value": "通过maxLines设置富文本可显示的最大行数" + }, + { + "name": "Set_Attributes_title_5", + "value": "设置最大长度" + }, + { + "name": "Set_Attributes_title_5_desc", + "value": "通过maxLength设置富文本的最大输入字符数" + }, + { + "name": "Set_Attributes_title_6", + "value": "默认选中菜单" + }, + { + "name": "Set_Attributes_title_6_desc", + "value": "富文本中的文字被选中时会弹出包含剪切、复制、翻译、分享的菜单" + }, + { + "name": "Add_Event_title", + "value": "添加事件" + }, + { + "name": "Add_Event_title_1", + "value": "添加组件初始化完成后可触发的回调" + }, + { + "name": "Add_Event_title_1_desc", + "value": "通过onReady来添加组件初始化完成后可触发的回调" + }, + { + "name": "Add_Event_title_2", + "value": "添加组件内容选择区域或编辑状态下光标位置改变时可触发的回调" + }, + { + "name": "Add_Event_title_2_desc", + "value": "通过onSelectionChange来添加组件内容选择区域或编辑状态下光标位置改变时可触发的回调" + }, + { + "name": "Add_Event_title_3", + "value": "添加组件内容选择区域或编辑状态下光标位置改变时可触发的回调" + }, + { + "name": "Add_Event_title_3_desc", + "value": "通过onWillChange添加图文变化前可触发的回调,通过onDidChange添加图文变化后可触发的回调" + }, + { + "name": "Add_Event_title_4", + "value": "添加输入法输入内容前和完成输入后可触发的回调" + }, + { + "name": "Add_Event_title_4_desc", + "value": "在添加输入法输入内容前,可以通过aboutToIMEInput触发回调。在输入法完成输入后,可以通过onDidIMEInput触发回调" + }, + { + "name": "Add_Event_title_5", + "value": "添加完成粘贴前可触发的回调" + }, + { + "name": "Add_Event_title_5_desc", + "value": "通过onPaste回调,来添加粘贴前要处理的流程" + }, + { + "name": "Add_Event_title_6", + "value": "添加完成剪切前可触发的回调" + }, + { + "name": "Add_Event_title_6_desc", + "value": "通过onCut回调,来添加剪切前要处理的流程" + }, + { + "name": "Add_Event_title_7", + "value": "添加完成复制前可触发的回调" + }, + { + "name": "Add_Event_title_7_desc", + "value": "通过onCopy回调,来添加复制前要处理的流程" + }, + { + "name": "Set_User_PresetText_Styles_title", + "value": "设置用户预设的文本样式" + }, + { + "name": "Set_User_PresetText_Styles_desc", + "value": "通过setTypingStyle设置用户预设的文本样式" + }, + { + "name": "Backplane_Highlighting_title", + "value": "设置组件内的内容选中时部分背板高亮" + }, + { + "name": "Backplane_Highlighting_desc", + "value": "通过setSelection设置组件内的内容选中时部分背板高亮" + }, + { + "name": "Add_TextContent_title", + "value": "添加文本内容" + }, + { + "name": "Add_TextContent_desc", + "value": "除了直接在组件内输入内容,也可以通过addTextSpan添加文本内容" + }, + { + "name": "Add_ImageContent_title", + "value": "添加图片内容" + }, + { + "name": "Add_ImageContent_desc", + "value": "通过addImageSpan添加图片内容" + }, + { + "name": "Add_Builder_DecoratorContent_title", + "value": "添加@Builder装饰器修饰的内容" + }, + { + "name": "Add_Builder_DecoratorContent_desc", + "value": "通过addBuilderSpan添加@Builder装饰器修饰的内容" + }, + { + "name": "Add_SymbolSpanContent_title", + "value": "添加SymbolSpan内容" + }, + { + "name": "Add_SymbolSpanContent_desc", + "value": "可通过addSymbolSpan添加Symbol内容。此接口可用于特殊符号添加与展示,例如在编辑学术论文时,此接口可用于添加各种数学符号" + }, + { + "name": "Get_GraphicInfo_In_Component_title", + "value": "获取组件内图文信息" + }, + { + "name": "Get_GraphicInfo_In_Component_desc", + "value": "可通过getSpans获取组件内所有图文内容的信息,包括图文的内容、id、样式、位置等信息。获取内容位置信息后,可对指定范围内容进行样式的更新" + }, + { + "name": "Create_Apply_StyledString_MutableStyledString_title", + "value": "创建并应用StyledString和MutableStyledString" + }, + { + "name": "Create_Apply_StyledString_MutableStyledString_desc", + "value": "可以通过TextController提供的setStyledString方法,将属性字符串附加到文本组件,并推荐在onPageShow或者文本组件的onAppear回调中触发绑定" + }, + { + "name": "pageIndex_StyledString", + "value": "属性字符串 StyledString/MutableStyledString" + }, + { + "name": "CreatStyledString_title", + "value": "创建并应用StyledString和MutableStyledString" + }, + { + "name": "CreatStyledString_description", + "value": "可以通过TextController提供的setStyledString方法,将属性字符串附加到文本组件,并推荐在onPageShow或者文本组件的onAppear回调中触发绑定。" + }, + { + "name": "StyledStringStyle_title", + "value": "设置文本样式" + }, + { + "name": "StyledStringStyle_description", + "value": "属性字符串目前提供了多种Style对象,包括TextStyle、TextShadowStyle、DecorationStyle、BaselineOffsetStyle、LineHeightStyle、LetterSpacingStyle,用于设置文本的各类样式。" + }, + { + "name": "StyledStringStyle_title_1", + "value": "创建及应用文本字体样式对象(TextStyle)" + }, + { + "name": "StyledStringStyle_title_2", + "value": "创建及应用文本阴影对象(TextShadowStyle)" + }, + { + "name": "StyledStringStyle_title_3", + "value": "创建及应用文本装饰线对象(DecorationStyle)" + }, + { + "name": "StyledStringStyle_title_4", + "value": "创建及应用文本基线偏移量对象(BaselineOffsetStyle)" + }, + { + "name": "StyledStringStyle_title_5", + "value": "创建及应用文本行高对象(LineHeightStyle)" + }, + { + "name": "StyledStringStyle_title_6", + "value": "创建及应用文本字符间距对象(LetterSpacingStyle)" + }, + { + "name": "StyledStringParagraphStyle_title", + "value": "设置段落样式" + }, + { + "name": "StyledStringParagraphStyle_description", + "value": "可通过ParagraphStyle设置段落样式布局。" + }, + { + "name": "StyledStringImageAttachment_title", + "value": "通过ImageAttachment来添加图片" + }, + { + "name": "StyledStringImageAttachment_description", + "value": "将图片和文本附加到同一个MutableStyledString对象上,并实现图文混排。" + }, + { + "name": "TStyledStringGestureStyle_title", + "value": "设置事件" + }, + { + "name": "StyledStringGestureStyle_description", + "value": "除了初始化属性字符串对象即初始样式对象,亦可通过setStyle接口再叠加新样式或更新已有样式,同时需要在附加的文本组件controller上主动触发更新绑定的属性字符串。" + }, + { + "name": "StyledStringGestureStyle_button_content", + "value": "响应属性字符串事件改变背景色" + }, + { + "name": "StyledStringHtml_title", + "value": "格式转换" + }, + { + "name": "StyledStringHtml_description", + "value": "可以通过toHtml、fromHtml接口实现属性字符串与HTML格式字符串的相关转换,当前支持转换的HTML标签范围:

。" + }, + { + "name": "StyledStringSceneExample_title", + "value": "场景示例" + }, + { + "name": "StyledStringSceneExample_description", + "value": "通过ParagraphStyle、LineHeightStyle、TextStyle对象展示了会员过期提示的效果。" + }, + { + "name": "pageIndex_symbolGlyphSpan", + "value": "图标小符号(SymbolGlyph/SymbolSpan)" + }, + { + "name": "CreatSymbolGlyph_title", + "value": "创建图标" + }, + { + "name": "CreatSymbolGlyph_description", + "value": "SymbolGlyph通过$r引用Resource资源来创建,目前仅支持系统预置的Symbol资源名。" + }, + { + "name": "SymbolGlyphSpanAddToText_title", + "value": "添加到文本中" + }, + { + "name": "SymbolGlyphSpanAddToText_description", + "value": "SymbolSpan可作为Text的子组件用于显示图标小符号。可以在一个Text组件内添加多个SymbolSpan,从而展示一串连续的图标。" + }, + { + "name": "SymbolGlyphSpanCustomIconAnimation_title", + "value": "自定义图标动效" + }, + { + "name": "SymbolGlyphSpanCustomIconAnimation_description", + "value": "相较于effectStrategy属性在启动时即触发动效,可以通过以下两种方式来控制动效的播放状态,以及选择更多样化的动效策略。" + }, + { + "name": "SymbolGlyphSpanAddEvent_title", + "value": "添加事件" + }, + { + "name": "SymbolGlyphSpanAddEvent_description", + "value": "SymbolGlyph组件可以添加通用事件,例如绑定onClick、onTouch等事件来响应操作。" + }, + { + "name": "SymbolGlyphSpanSceneExample_title", + "value": "场景示例" + }, + { + "name": "SymbolGlyphSpanSceneExample_description", + "value": "该示例通过symbolEffect、fontSize、fontColor属性展示了播放列表的效果。" + }, + { + "name": "SymbolGlyphSpanAddToText_title_1", + "value": "创建SymbolSpan" + }, + { + "name": "SymbolGlyphSpanAddToText_title_2", + "value": "通过fontSize属性设置SymbolSpan的大小" + }, + { + "name": "SymbolGlyphSpanAddToText_title_3", + "value": "通过fontWeight属性设置SymbolSpan组件的粗细" + }, + { + "name": "SymbolGlyphSpanAddToText_title_4", + "value": "通过fontColor属性设置SymbolSpan的颜色" + }, + { + "name": "SymbolGlyphSpanAddToText_title_5", + "value": "通过renderingStrategy属性设置SymbolSpan的渲染策略" + }, + { + "name": "SymbolGlyphSpanAddToText_title_6", + "value": "通过effectStrategy属性设置SymbolSpan的动效策略" + }, + { + "name": "SymbolGlyphSpanCustomIconAnimation_title_1", + "value": "通过设置SymbolEffect属性,可以同时配置SymbolGlyph的动效策略和播放状态" + }, + { + "name": "SymbolGlyphSpanCustomIconAnimation_title_2", + "value": "通过设置SymbolEffect属性,可以同时指定SymbolGlyph的动画效果策略及其播放触发条件" + }, + { + "name": "ListenTextBoxEvents_NDK_title", + "value": "输入框文本事件监听" + }, + { + "name": "ListenTextBoxEvents_NDK_desc", + "value": "输入框包含多种交互行为,开发者可注册事件监听并获取状态" + }, + { + "name": "TextDrawingDisplay_NDK_title", + "value": "Text组件的文本绘制与显示" + }, + { + "name": "TextDrawingDisplay_NDK_desc", + "value": "Text组件提供了接口NODE_TEXT_CONTENT_WITH_STYLED_STRING,可以直接渲染方舟文本引擎生成的文本" + }, + { + "name": "StyledStringHtml_Button_1", + "value": "添加属性字符串" + }, + { + "name": "StyledStringHtml_Button_2", + "value": "toHtml" + }, + { + "name": "StyledStringHtml_Button_3", + "value": "fromHtml" + }, + { + "name": "StyledStringImageAttachment_Button_1", + "value": "点击查看商品卡片" + }, + { + "name": "StyledStringParagraphStyle_Button_1", + "value": "change" + }, + { + "name": "StyledStringSceneExample_Button_1", + "value": "限时4.88元 立即续费" + }, + { + "name": "AddBuilderDecoratorContent_Button_1", + "value": "addBuilderSpan" + }, + { + "name": "AddImageContent_Button_1", + "value": "addImageSpan" + }, + { + "name": "AddSymbolSpanContent_Button_1", + "value": "addSymbolSpan" + }, + { + "name": "AddTextContent_Button_1", + "value": "addTextSpan" + }, + { + "name": "BackplaneHighlighting_Button_1", + "value": "setSelection(0,2)" + }, + { + "name": "GetGraphicInfoInComponent_Button_1", + "value": "getSpans" + }, + { + "name": "SetUserPresetTextStyles_Button_1", + "value": "setTypingStyle" + }, + { + "name": "SymbolGlyphSpanCustomIconAnimation_Button_1", + "value": "关闭" + }, + { + "name": "SymbolGlyphSpanCustomIconAnimation_Button_2", + "value": "播放" + }, + { + "name": "SymbolGlyphSpanCustomIconAnimation_Button_3", + "value": "trigger" + }, + { + "name": "CursorAvoidance_Button_1", + "value": "CaretPosition++: " + }, + { + "name": "CursorAvoidance_Button_2", + "value": "CaretPosition--: " + }, + { + "name": "CursorAvoidance_Button_3", + "value": "SetCaretPosition: " + }, + { + "name": "LoginRegisterPage_Button_3", + "value": "Sign in" + }, + { + "name": "CreateApply_Text_1", + "value": "运动45分钟" + }, + { + "name": "CreateApply_Text_2", + "value": "运动35分钟" + }, + { + "name": "StyledStringHtml_Text_1", + "value": "属性字符串" + }, + { + "name": "StyledStringImageAttachment_Text_1", + "value": "\n品牌相纸 高清冲印30张\n限时直降5.15元 限量增送" + }, + { + "name": "StyledStringImageAttachment_Text_2", + "value": "\n¥16.21 3000+人好评" + }, + { + "name": "StyledStringParagraphStyle_Text_1", + "value": "段落标题\n正文第一段落开始0123456789正文第一段落结束。" + }, + { + "name": "StyledStringSceneExample_Text_1", + "value": "您的豪华钻石已过期1天\n续费可继续享受会员专属权益" + }, + { + "name": "StyledStringSceneExample_Text_2", + "value": "\n¥4.88¥15" + }, + { + "name": "StyledStringSceneExample_Text_3", + "value": "\n02时06分后将失去该优惠" + }, + { + "name": "StyledStringStyle_Text_1", + "value": "运动35分钟 目标达成" + }, + { + "name": "StyledStringStyle_Text_2", + "value": "运动35分钟" + }, + { + "name": "StyledStringStyle_Text_3", + "value": "运动35分钟" + }, + { + "name": "StyledStringStyle_Text_4", + "value": "运动35分钟" + }, + { + "name": "StyledStringStyle_Text_5", + "value": "运动35分钟\n顶顶顶\n得到" + }, + { + "name": "StyledStringStyle_Text_6", + "value": "运动35分钟" + }, + { + "name": "AddBuilderDecoratorContent_Text_1", + "value": "文本文档.txt" + }, + { + "name": "AddBuilderDecoratorContent_Text_2", + "value": "123.45KB" + }, + { + "name": "AddBuilderDecoratorContent_Text_3", + "value": "点击按钮在此处添加builderspan。" + }, + { + "name": "AddEvent_Text_1", + "value": "onReady回调内容是组件内预置文本。" + }, + { + "name": "AddEvent_Text_2", + "value": "改变内容选择区域或编辑状态下的光标位置,触发onSelectionChange回调。" + }, + { + "name": "AddEvent_Text_3", + "value": "触发了onSelectionChange回调,起始范围信息为:(" + }, + { + "name": "AddEvent_Text_4", + "value": "查看回调内容:" + }, + { + "name": "AddEvent_Text_5", + "value": "组件内图文变化前,触发回调。\n图文变化后,触发回调。" + }, + { + "name": "AddEvent_Text_6", + "value": "组件内图文变化前,触发回调:\n" + }, + { + "name": "AddEvent_Text_7", + "value": "\n图文变化后,触发回调:\nrangeBefore:" + }, + { + "name": "AddEvent_Text_8", + "value": "输入法输入内容前,触发回调。\n输入法完成输入后,触发回调。" + }, + { + "name": "AddEvent_Text_9", + "value": "输入法输入内容前,触发aboutToIMEInput回调:\n" + }, + { + "name": "AddEvent_Text_10", + "value": "输入法完成输入后,触发onDidIMEInput回调:\n" + }, + { + "name": "AddEvent_Text_11", + "value": "对此处文本进行复制粘贴操作可触发对应回调。" + }, + { + "name": "AddEvent_Text_12", + "value": "触发onPaste回调\n" + }, + { + "name": "AddEvent_Text_13", + "value": "对此处文本进行复制粘贴操作可触发对应回调。" + }, + { + "name": "AddEvent_Text_14", + "value": "触发onCut回调\n" + }, + { + "name": "AddEvent_Text_15", + "value": "对此处文本进行复制粘贴操作可触发对应回调。" + }, + { + "name": "AddEvent_Text_16", + "value": "触发onCopy回调\n" + }, + { + "name": "AddImageContent_Text_1", + "value": "点击按钮在此处添加image。" + }, + { + "name": "AddSymbolSpanContent_Text_1", + "value": "点击按钮在此处添加symbol。" + }, + { + "name": "AddTextContent_Text_1", + "value": "点击按钮在此处添加text。" + }, + { + "name": "AddTextContent_Text_2", + "value": "新添加一段文字。" + }, + { + "name": "BackplaneHighlighting_Text_1", + "value": "点击按钮在此处选中0-2位置的文本。" + }, + { + "name": "CreateRichEditor_Text_1", + "value": "创建使用属性字符串构建的RichEditor组件。" + }, + { + "name": "CreateRichEditor_Text_2", + "value": "创建不使用属性字符串构建的RichEditor组件。" + }, + { + "name": "GetGraphicInfoInComponent_Text_1", + "value": "点击按钮获取此处span信息。" + }, + { + "name": "GetGraphicInfoInComponent_Text_2", + "value": "查看getSpans返回值:" + }, + { + "name": "SetAttributes_Text_1", + "value": "剪切" + }, + { + "name": "SetAttributes_Text_2", + "value": "复制" + }, + { + "name": "SetAttributes_Text_3", + "value": "粘贴" + }, + { + "name": "SetAttributes_Text_4", + "value": "组件设置了自定义菜单,长按可触发。" + }, + { + "name": "SetAttributes_Text_5", + "value": "组件设置了光标手柄颜色。" + }, + { + "name": "SetAttributes_Text_6", + "value": "此处为提示文本..." + }, + { + "name": "SetAttributes_Text_7", + "value": "组件设置了最大行数\n超出内容将会以滚动显示\n超出1行\n超出2行\n超出3行\n超出4行" + }, + { + "name": "SetAttributes_Text_8", + "value": "组件设置了最大字符数:7" + }, + { + "name": "SetAttributes_Text_9", + "value": "这是一段文本,用来展示选中菜单" + }, + { + "name": "SetUserPresetTextStyles_Text_1", + "value": "点击按钮,改变预设文本样式。" + }, + { + "name": "SymbolAddToText_Text_1", + "value": "单色" + }, + { + "name": "SymbolAddToText_Text_2", + "value": "多色" + }, + { + "name": "SymbolAddToText_Text_3", + "value": "分层" + }, + { + "name": "SymbolAddToText_Text_4", + "value": "无动效" + }, + { + "name": "SymbolAddToText_Text_5", + "value": "整体缩放动效" + }, + { + "name": "SymbolAddToText_Text_6", + "value": "层级动效" + }, + { + "name": "SymbolCustomIconAnimation_Text_1", + "value": "可变颜色动效" + }, + { + "name": "SymbolCustomIconAnimation_Text_2", + "value": "弹跳动效" + }, + { + "name": "SymbolSceneExample_Text_1", + "value": "顺序播放" + }, + { + "name": "SymbolSceneExample_Text_2", + "value": "单曲循环" + }, + { + "name": "SymbolSceneExample_Text_3", + "value": "随机播放" + }, + { + "name": "SymbolSceneExample_Text_4", + "value": "当前播放列表" + }, + { + "name": "SymbolSceneExample_Text_5", + "value": "歌曲一" + }, + { + "name": "SymbolSceneExample_Text_6", + "value": "歌曲二" + }, + { + "name": "SymbolSceneExample_Text_7", + "value": "歌曲三" + }, + { + "name": "SymbolSceneExample_Text_8", + "value": "歌曲四" + }, + { + "name": "SymbolSceneExample_Text_9", + "value": "歌曲五" + }, + { + "name": "SymbolSceneExample_Text_10", + "value": "歌曲六" + }, + { + "name": "SymbolSceneExample_Text_11", + "value": "歌曲七" + }, + { + "name": "SymbolSceneExample_Text_12", + "value": "关闭" + }, + { + "name": "AIMenu_Text_1", + "value": "电话号码:(86) (755) ******** \n \n 链接:www.********.com \n \n 邮箱:***@example.com\n \n 地址:XX省XX市XX区XXXX \n \n 时间:XX年XX月XX日XXXX" + }, + { + "name": "CreateText_Text_1", + "value": "我是一段文本" + }, + { + "name": "SelectMenu_Text_1", + "value": "拦截 id: customMenu2 start:" + }, + { + "name": "SelectMenu_Text_2", + "value": "拦截 COPY start:" + }, + { + "name": "SelectMenu_Text_3", + "value": "不拦截 SELECT_ALL start:" + }, + { + "name": "SelectMenu_Text_4", + "value": "自定义选择菜单弹出时触发该回调" + }, + { + "name": "SelectMenu_Text_5", + "value": "自定义选择菜单关闭时触发该回调" + } + ] +} \ No newline at end of file diff --git a/ArkUISample/TextComponent/entry/src/main/resources/base/media/background.png b/ArkUISample/TextComponent/entry/src/main/resources/base/media/background.png new file mode 100644 index 0000000000000000000000000000000000000000..f939c9fa8cc8914832e602198745f592a0dfa34d Binary files /dev/null and b/ArkUISample/TextComponent/entry/src/main/resources/base/media/background.png differ diff --git a/ArkUISample/TextComponent/entry/src/main/resources/base/media/foreground.png b/ArkUISample/TextComponent/entry/src/main/resources/base/media/foreground.png new file mode 100644 index 0000000000000000000000000000000000000000..4483ddad1f079e1089d685bd204ee1cfe1d01902 Binary files /dev/null and b/ArkUISample/TextComponent/entry/src/main/resources/base/media/foreground.png differ diff --git a/ArkUISample/TextComponent/entry/src/main/resources/base/media/layered_image.json b/ArkUISample/TextComponent/entry/src/main/resources/base/media/layered_image.json new file mode 100644 index 0000000000000000000000000000000000000000..fb49920440fb4d246c82f9ada275e26123a2136a --- /dev/null +++ b/ArkUISample/TextComponent/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/ArkUISample/TextComponent/entry/src/main/resources/base/media/startIcon.png b/ArkUISample/TextComponent/entry/src/main/resources/base/media/startIcon.png new file mode 100644 index 0000000000000000000000000000000000000000..205ad8b5a8a42e8762fbe4899b8e5e31ce822b8b Binary files /dev/null and b/ArkUISample/TextComponent/entry/src/main/resources/base/media/startIcon.png differ diff --git a/ArkUISample/TextComponent/entry/src/main/resources/base/profile/backup_config.json b/ArkUISample/TextComponent/entry/src/main/resources/base/profile/backup_config.json new file mode 100644 index 0000000000000000000000000000000000000000..78f40ae7c494d71e2482278f359ec790ca73471a --- /dev/null +++ b/ArkUISample/TextComponent/entry/src/main/resources/base/profile/backup_config.json @@ -0,0 +1,3 @@ +{ + "allowToBackupRestore": true +} \ No newline at end of file diff --git a/ArkUISample/TextComponent/entry/src/main/resources/base/profile/main_pages.json b/ArkUISample/TextComponent/entry/src/main/resources/base/profile/main_pages.json new file mode 100644 index 0000000000000000000000000000000000000000..2e5e78d67e7c32c013955029202db9008ddb3f08 --- /dev/null +++ b/ArkUISample/TextComponent/entry/src/main/resources/base/profile/main_pages.json @@ -0,0 +1,12 @@ +{ + "src": [ + "pages/Index", + "pages/propertyString/CreateApply", + "pages/propertyString/StyledStringStyle", + "pages/propertyString/StyledStringParagraphStyle", + "pages/propertyString/StyledStringImageAttachment", + "pages/propertyString/StyledStringGestureStyle", + "pages/propertyString/StyledStringHtml", + "pages/propertyString/StyledStringSceneExample" + ] +} \ No newline at end of file diff --git a/ArkUISample/TextComponent/entry/src/main/resources/dark/element/color.json b/ArkUISample/TextComponent/entry/src/main/resources/dark/element/color.json new file mode 100644 index 0000000000000000000000000000000000000000..79b11c2747aec33e710fd3a7b2b3c94dd9965499 --- /dev/null +++ b/ArkUISample/TextComponent/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/ArkUISample/TextComponent/entry/src/mock/mock-config.json5 b/ArkUISample/TextComponent/entry/src/mock/mock-config.json5 new file mode 100644 index 0000000000000000000000000000000000000000..b9a78e201535765168a92d3543c690273ecdc019 --- /dev/null +++ b/ArkUISample/TextComponent/entry/src/mock/mock-config.json5 @@ -0,0 +1,17 @@ +/* + * Copyright (c) 2025 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +{ +} \ No newline at end of file diff --git a/ArkUISample/TextComponent/entry/src/ohosTest/ets/test/Ability.test.ets b/ArkUISample/TextComponent/entry/src/ohosTest/ets/test/Ability.test.ets new file mode 100644 index 0000000000000000000000000000000000000000..0f8ce9a2c012f8fe36114cef65216ef0b6254f41 --- /dev/null +++ b/ArkUISample/TextComponent/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/ArkUISample/TextComponent/entry/src/ohosTest/ets/test/List.test.ets b/ArkUISample/TextComponent/entry/src/ohosTest/ets/test/List.test.ets new file mode 100644 index 0000000000000000000000000000000000000000..7c16bc08c6fb53175fcdc9d628a4d6a9b34bef4c --- /dev/null +++ b/ArkUISample/TextComponent/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/ArkUISample/TextComponent/entry/src/ohosTest/ets/test/index.test.ets b/ArkUISample/TextComponent/entry/src/ohosTest/ets/test/index.test.ets new file mode 100644 index 0000000000000000000000000000000000000000..0587758e31376a3f13229678d2e59b8cb8b84af9 --- /dev/null +++ b/ArkUISample/TextComponent/entry/src/ohosTest/ets/test/index.test.ets @@ -0,0 +1,1614 @@ +/* + * Copyright (c) 2025 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { describe, it, expect, beforeAll, Level } from '@ohos/hypium'; +// 导入测试依赖kit +import { abilityDelegatorRegistry, Driver, ON, MatchPattern, On, Component } from '@kit.TestKit'; +import { UIAbility, Want } from '@kit.AbilityKit'; + +const delegator: abilityDelegatorRegistry.AbilityDelegator = abilityDelegatorRegistry.getAbilityDelegator(); +const bundleName = abilityDelegatorRegistry.getArguments().bundleName; +let abilityDelegator: abilityDelegatorRegistry.AbilityDelegator = abilityDelegatorRegistry.getAbilityDelegator(); +let want: Want; + +async function getResourceString(resource: Resource): Promise { + let manage = abilityDelegator.getAppContext().resourceManager; + let textString: string = await manage.getStringValue(resource); + return textString; +} + +export default function IndexTest() { + + describe('IndexTest', () => { + beforeAll(async () => { + want = { + bundleName: bundleName, + abilityName: 'EntryAbility' + }; + await delegator.startAbility(want); + let driver = Driver.create(); + await driver.delayMs(1000); + const ability: UIAbility = await delegator.getCurrentTopAbility(); + console.info('get top ability'); + expect(ability.context.abilityInfo.name).assertEqual('EntryAbility'); + }) + + /** + * @tc.number UiTest_001 + * @tc.name testCreateText + * @tc.desc 测试文本创建场景示例 + * @tc.level: Level 1 + */ + it('testCreateText', Level.LEVEL1, async (done: Function) => { + console.info('uitest: testCreateText begin'); + let driver = Driver.create(); + let buttonComponent = await driver.findComponent(ON.text('Text', MatchPattern.CONTAINS)); + expect(buttonComponent === null).assertFalse(); + await buttonComponent.click(); + let str = await getResourceString($r('app.string.CreatText_title')); + let sampleButton = await driver.findComponent(ON.text(str, MatchPattern.CONTAINS)); + expect(sampleButton === null).assertFalse(); + await sampleButton.click(); + + str = await getResourceString($r('app.string.CreateText_Text_1')); + let textString = await driver.findComponent(ON.text(str, MatchPattern.CONTAINS)); + str = await getResourceString($r('app.string.module_desc')); + let textResource = await driver.findComponent(ON.text(str, MatchPattern.CONTAINS)); + expect(textString === null).assertFalse(); + expect(textResource === null).assertFalse(); + await driver.pressBack(); + await driver.pressBack(); + console.info('uitest: testCreateText end'); + done(); + }) + + /** + * @tc.number UiTest_002 + * @tc.name testTextSpan + * @tc.desc 测试文本段创建场景示例 + * @tc.level: Level 1 + */ + it('testTextSpan', Level.LEVEL1, async (done: Function) => { + console.info('uitest: testTextSpan begin'); + let driver = Driver.create(); + let componentButton = await driver.findComponent(ON.text('Text', MatchPattern.CONTAINS)); + expect(componentButton === null).assertFalse(); + await componentButton.click(); + let str = await getResourceString($r('app.string.TextSpan_title')); + let sampleButton = await driver.findComponent(ON.text(str, MatchPattern.CONTAINS)); + expect(sampleButton === null).assertFalse(); + await sampleButton.click(); + + str = await getResourceString($r('app.string.TextSpan_textContent_2')); + let textSpan = await driver.findComponent(ON.text(str, MatchPattern.CONTAINS)); + str = await getResourceString($r('app.string.TextSpan_textContent_3')); + let textColorSpan1 = await driver.findComponent(ON.text(str, MatchPattern.CONTAINS)); + str = await getResourceString($r('app.string.TextSpan_textContent_4')); + let textColorSpan2 = await driver.findComponent(ON.text(str, MatchPattern.CONTAINS)); + str = await getResourceString($r('app.string.TextSpan_textContent_5')); + let textColorSpan3 = await driver.findComponent(ON.text(str, MatchPattern.CONTAINS)); + + let uppercase = await driver.findComponent(ON.text('I am Upper-span', MatchPattern.CONTAINS)); + expect(uppercase === null).assertFalse(); + + let textBeforeClick = await driver.findComponent(ON.text('I am Upper-span2', MatchPattern.CONTAINS)); + expect(textBeforeClick === null).assertFalse(); + await textBeforeClick.click(); + str = await getResourceString($r('app.string.TextSpan_textContent_6')); + let textAfterClick = await driver.findComponent(ON.text(str, MatchPattern.CONTAINS)); + + expect(textSpan === null).assertFalse(); + expect(textColorSpan1 === null).assertFalse(); + expect(textColorSpan2 === null).assertFalse(); + expect(textColorSpan3 === null).assertFalse(); + expect(textColorSpan3 === null).assertFalse(); + expect(textAfterClick === null).assertFalse(); + await driver.pressBack(); + await driver.pressBack(); + console.info('uitest: testTextSpan end'); + done(); + }) + + /** + * @tc.number UiTest_003 + * @tc.name testCustomTextStyle + * @tc.desc 测试自定义文本样式场景示例 + * @tc.level: Level 1 + */ + it('testCustomTextStyle', Level.LEVEL1, async (done: Function) => { + console.info('uitest: testCustomTextStyle begin'); + let driver = Driver.create(); + let buttonComponent = await driver.findComponent(ON.text('Text', MatchPattern.CONTAINS)); + expect(buttonComponent === null).assertFalse(); + await buttonComponent.click(); + let str = await getResourceString($r('app.string.CustomTextStyle_title')); + let sampleButton = await driver.findComponent(ON.text(str, MatchPattern.CONTAINS)); + expect(sampleButton === null).assertFalse(); + await sampleButton.click(); + + str = await getResourceString($r('app.string.TextAlign_Start')); + let textLeft = await driver.findComponent(ON.text(str, MatchPattern.CONTAINS)); + str = await getResourceString($r('app.string.TextAlign_Center')); + let textCenter = await driver.findComponent(ON.text(str, MatchPattern.CONTAINS)); + str = await getResourceString($r('app.string.TextAlign_End')); + let textRight = await driver.findComponent(ON.text(str, MatchPattern.CONTAINS)); + + let longText1 = await driver.findComponent(ON.text( + 'This is the setting of textOverflow to Clip text content This is the setting of textOverflow ' + + 'to None text content. This is the setting of textOverflow to Clip text content This is the setting ' + + 'of textOverflow to None text content.', MatchPattern.CONTAINS)); + str = await getResourceString($r('app.string.CustomTextStyle_textContent_1')); + let longText2 = await driver.findComponent(ON.text(str, MatchPattern.CONTAINS)); + str = await getResourceString($r('app.string.CustomTextStyle_textContent_2')); + let longText3 = await driver.findComponent(ON.text(str, MatchPattern.CONTAINS)); + str = await getResourceString($r('app.string.CustomTextStyle_textContent_8')); + let longText4 = await driver.findComponent(ON.text(str, MatchPattern.CONTAINS)); + + let customLineHeight = await driver.findComponent(ON.text( + 'This is the text with the line height set. This is the text with the line height set.', + MatchPattern.CONTAINS)); + let customTextLineAndColor = await driver.findComponent(ON.text('This is the text', MatchPattern.CONTAINS)); + + let scrollComponent: Component = await driver.waitForComponent(ON.id('scroll_'), 1000); + let scrollCenter = await scrollComponent.getBoundsCenter(); + await driver.swipe(scrollCenter.x, scrollCenter.y + 400, scrollCenter.x, scrollCenter.y - 400, 3000); + await driver.waitForIdle(500, 500); + + let customTextBaselineOffset1 = + await driver.findComponent(ON.text('This is the text content with baselineOffset 0.', MatchPattern.CONTAINS)); + let customTextBaselineOffset2 = + await driver.findComponent(ON.text('This is the text content with baselineOffset 30.', MatchPattern.CONTAINS)); + let customTextBaselineOffset3 = + await driver.findComponent(ON.text('This is the text content with baselineOffset -20.', MatchPattern.CONTAINS)); + let customTextLetterSpace1 = + await driver.findComponent(ON.text('This is the text content with letterSpacing 0.', MatchPattern.CONTAINS)); + let customTextLetterSpace2 = + await driver.findComponent(ON.text('This is the text content with letterSpacing 3.', MatchPattern.CONTAINS)); + let customTextLetterSpace3 = + await driver.findComponent(ON.text('This is the text content with letterSpacing -1.', MatchPattern.CONTAINS)); + + await driver.swipe(scrollCenter.x, scrollCenter.y + 400, scrollCenter.x, scrollCenter.y - 400, 3000); + await driver.waitForIdle(500, 500); + + str = await getResourceString($r('app.string.CustomTextStyle_textContent_3')); + let customTheSizeOfText1 = await driver.findComponent(ON.text(str, MatchPattern.CONTAINS)); + str = await getResourceString($r('app.string.CustomTextStyle_textContent_4')); + let customTheSizeOfText2 = await driver.findComponent(ON.text(str, MatchPattern.CONTAINS)); + str = await getResourceString($r('app.string.CustomTextStyle_textContent_5')); + let customTheSizeOfText3 = await driver.findComponent(ON.text(str, MatchPattern.CONTAINS)); + str = await getResourceString($r('app.string.CustomTextStyle_textContent_6')); + let customTheSizeOfText4 = await driver.findComponent(ON.text(str, MatchPattern.CONTAINS)); + let textCase1 = await driver.findComponent(ON.text('This is the text content with textCase set to Normal.', + MatchPattern.CONTAINS)); + let textCase2 = await driver.findComponent(ON.text('This is the text content with textCase set to LowerCase.', + MatchPattern.CONTAINS)); + let textCase3 = await driver.findComponent(ON.text('This is the text content with textCase set to UpperCase.', + MatchPattern.CONTAINS)); + str = await getResourceString($r('app.string.CustomTextStyle_textContent_7')); + let copyOption = await driver.findComponent(ON.text(str, MatchPattern.CONTAINS)); + + expect(textLeft === null).assertFalse(); + expect(textCenter === null).assertFalse(); + expect(textRight === null).assertFalse(); + expect(longText1 === null).assertFalse(); + expect(longText2 === null).assertFalse(); + expect(longText3 === null).assertFalse(); + expect(longText4 === null).assertFalse(); + expect(customLineHeight === null).assertFalse(); + expect(customTextLineAndColor === null).assertFalse(); + expect(customTextBaselineOffset1 === null).assertFalse(); + expect(customTextBaselineOffset2 === null).assertFalse(); + expect(customTextBaselineOffset3 === null).assertFalse(); + expect(customTextLetterSpace1 === null).assertFalse(); + expect(customTextLetterSpace2 === null).assertFalse(); + expect(customTextLetterSpace3 === null).assertFalse(); + expect(customTheSizeOfText1 === null).assertFalse(); + expect(customTheSizeOfText2 === null).assertFalse(); + expect(customTheSizeOfText3 === null).assertFalse(); + expect(customTheSizeOfText4 === null).assertFalse(); + expect(textCase1 === null).assertFalse(); + expect(textCase2 === null).assertFalse(); + expect(textCase3 === null).assertFalse(); + expect(copyOption === null).assertFalse(); + + await driver.pressBack(); + await driver.pressBack(); + console.info('uitest: testCustomTextStyle end'); + done(); + }) + + /** + * @tc.number UiTest_004 + * @tc.name testTextAddEvent + * @tc.desc 测试文本增加事件场景示例 + * @tc.level: Level 1 + */ + it('testTextAddEvent', Level.LEVEL1, async (done: Function) => { + console.info('uitest: testTextAddEvent begin'); + let driver = Driver.create(); + let buttonComponent = await driver.findComponent(ON.text('Text', MatchPattern.CONTAINS)); + expect(buttonComponent === null).assertFalse(); + await buttonComponent.click(); + let str = await getResourceString($r('app.string.TextAddEvent_title')); + let sampleButton = await driver.findComponent(ON.text(str, MatchPattern.CONTAINS)); + expect(sampleButton === null).assertFalse(); + await sampleButton.click(); + + let textClick = await driver.findComponent(ON.id('Click')); + expect(textClick === null).assertFalse(); + await textClick.click(); + str = await getResourceString($r('app.string.TextAddEvent_textContent_2')); + expect(await textClick.getText() === str).assertTrue(); + + await driver.pressBack(); + await driver.pressBack(); + console.info('uitest: testTextAddEvent end'); + done(); + }) + + /** + * @tc.number UiTest_005 + * @tc.name testSelectMenu + * @tc.desc 测试设置选中菜单场景示例 + * @tc.level: Level 1 + */ + it('testSelectMenu', Level.LEVEL1, async (done: Function) => { + console.info('uitest: testSelectMenu begin'); + let driver = Driver.create(); + let buttonComponent = await driver.findComponent(ON.text('Text', MatchPattern.CONTAINS)); + expect(buttonComponent === null).assertFalse(); + await buttonComponent.click(); + let str = await getResourceString($r('app.string.SetSelectionMenu_title')); + let sampleButton = await driver.findComponent(ON.text(str, MatchPattern.CONTAINS)); + expect(sampleButton === null).assertFalse(); + await sampleButton.click(); + + str = await getResourceString($r('app.string.SelectMenu_textContent_1')); + let selectMenuText = await driver.findComponent(ON.text(str, MatchPattern.CONTAINS)); + expect(selectMenuText === null).assertFalse(); + + await driver.pressBack(); + await driver.pressBack(); + console.info('uitest: testSelectMenu end'); + done(); + }) + + /** + * @tc.number UiTest_006 + * @tc.name testAIMenu + * @tc.desc 测试设置AI菜单场景示例 + * @tc.level: Level 1 + */ + it('testAIMenu', Level.LEVEL1, async (done: Function) => { + console.info('uitest: testAIMenu begin'); + let driver = Driver.create(); + let buttonComponent = await driver.findComponent(ON.text('Text', MatchPattern.CONTAINS)); + expect(buttonComponent === null).assertFalse(); + await buttonComponent.click(); + let str = await getResourceString($r('app.string.SetUpAIMenu_title')); + let sampleButton = await driver.findComponent(ON.text(str, MatchPattern.CONTAINS)); + expect(sampleButton === null).assertFalse(); + await sampleButton.click(); + + str = await getResourceString($r('app.string.AIMenu_Text_1')); + let aiMenuText = await driver.findComponent(ON.text(str, MatchPattern.CONTAINS)); + expect(aiMenuText === null).assertFalse(); + + await driver.pressBack(); + await driver.pressBack(); + console.info('uitest: testAIMenu end'); + done(); + }) + + /** + * @tc.number UiTest_007 + * @tc.name testHotSearch + * @tc.desc 测试热搜榜场景示例 + * @tc.level: Level 1 + */ + it('testHotSearch', Level.LEVEL1, async (done: Function) => { + console.info('uitest: testHotSearch begin'); + let driver = Driver.create(); + let buttonComponent = await driver.findComponent(ON.text('Text', MatchPattern.CONTAINS)); + expect(buttonComponent === null).assertFalse(); + await buttonComponent.click(); + let str = await getResourceString($r('app.string.TextHotSearch_title')); + let sampleButton = await driver.findComponent(ON.text(str, MatchPattern.CONTAINS)); + expect(sampleButton === null).assertFalse(); + await sampleButton.click(); + + let textHotSearch1 = await driver.findComponent(ON.text('1')); + let textHotSearch2 = await driver.findComponent(ON.text('2')); + let textHotSearch3 = await driver.findComponent(ON.text('3')); + let textHotSearch4 = await driver.findComponent(ON.text('4')); + expect(textHotSearch1 === null).assertFalse(); + expect(textHotSearch2 === null).assertFalse(); + expect(textHotSearch3 === null).assertFalse(); + expect(textHotSearch4 === null).assertFalse(); + + str = await getResourceString($r('app.string.TextHotSearch_textContent_1')); + let hotText1 = await driver.findComponent(ON.text(str, MatchPattern.CONTAINS)); + str = await getResourceString($r('app.string.TextHotSearch_textContent_2')); + let hotText2 = await driver.findComponent(ON.text(str, MatchPattern.CONTAINS)); + str = await getResourceString($r('app.string.TextHotSearch_textContent_3')); + let hotText3 = await driver.findComponent(ON.text(str, MatchPattern.CONTAINS)); + str = await getResourceString($r('app.string.TextHotSearch_textContent_4')); + let hotText4 = await driver.findComponent(ON.text(str, MatchPattern.CONTAINS)); + str = await getResourceString($r('app.string.TextHotSearch_textContent_5')); + let hotText5 = await driver.findComponent(ON.text(str, MatchPattern.CONTAINS)); + str = await getResourceString($r('app.string.TextHotSearch_textContent_6')); + let hotText6 = await driver.findComponent(ON.text(str, MatchPattern.CONTAINS)); + + expect(hotText1 === null).assertFalse(); + expect(hotText2 === null).assertFalse(); + expect(hotText3 === null).assertFalse(); + expect(hotText4 === null).assertFalse(); + expect(hotText5 === null).assertFalse(); + expect(hotText6 === null).assertFalse(); + + await driver.pressBack(); + await driver.pressBack(); + console.info('uitest: testHotSearch end'); + done(); + }) + + /** + * @tc.number UiTest_008 + * @tc.name testCreateTextInput + * @tc.desc 测试创建文本输入框场景示例 + * @tc.level: Level 1 + */ + it('testCreateTextInput', Level.LEVEL1, async (done: Function) => { + console.info('uitest: testCreateTextInput begin'); + let driver = Driver.create(); + let buttonComponent = await driver.findComponent(ON.text('TextInput', MatchPattern.CONTAINS)); + expect(buttonComponent === null).assertFalse(); + await buttonComponent.click(); + let str = await getResourceString($r('app.string.CreatTextInput_title')); + let sampleButton = await driver.findComponent(ON.text(str, MatchPattern.CONTAINS)); + expect(sampleButton === null).assertFalse(); + await sampleButton.click(); + + let textInput = await driver.findComponent(ON.type('TextInput')); + let textArea = await driver.findComponent(ON.type('TextArea')); + str = await getResourceString($r('app.string.CreatTextInput_textContent')); + let textArea2 = await driver.findComponent(ON.text(str, MatchPattern.CONTAINS)); + expect(textInput === null).assertFalse(); + expect(textArea === null).assertFalse(); + expect(textArea2 === null).assertFalse(); + + await textInput.inputText('textInput'); + await textArea.inputText('textArea'); + + await driver.pressBack(); + await driver.pressBack(); + console.info('uitest: testCreateTextInput end'); + done(); + }) + + /** + * @tc.number UiTest_009-1 + * @tc.name testSetTextInputType + * @tc.desc 测试设置文本输入框类型场景示例 + * @tc.level: Level 1 + */ + it('testSetTextInputType1', Level.LEVEL1, async (done: Function) => { + console.info('uitest: testSetTextInputType1 begin'); + let driver = Driver.create(); + let buttonComponent = await driver.findComponent(ON.text('TextInput', MatchPattern.CONTAINS)); + expect(buttonComponent === null).assertFalse(); + await buttonComponent.click(); + let str = await getResourceString($r('app.string.SetTextInputType_title')); + let sampleButton = await driver.findComponent(ON.text(str, MatchPattern.CONTAINS)); + expect(sampleButton === null).assertFalse(); + await sampleButton.click(); + + let textInput1 = await driver.findComponent(ON.id('Normal')); + let textInput2 = await driver.findComponent(ON.id('Password')); + let textInput3 = await driver.findComponent(ON.id('Email')); + let textInput4 = await driver.findComponent(ON.id('Number')); + + expect(textInput1 === null).assertFalse(); + expect(textInput2 === null).assertFalse(); + expect(textInput3 === null).assertFalse(); + expect(textInput4 === null).assertFalse(); + + await textInput1.inputText('aaa'); + await textInput2.inputText('aaa'); + await textInput3.inputText('123456@example.com'); + await textInput4.inputText('123456789'); + + await driver.pressBack(); + await driver.pressBack(); + + console.info('uitest: testSetTextInputType1 end'); + done(); + }) + + /** + * @tc.number UiTest_009-2 + * @tc.name testSetTextInputType + * @tc.desc 测试设置文本输入框类型场景示例 + * @tc.level: Level 1 + */ + it('testSetTextInputType2', Level.LEVEL1, async (done: Function) => { + console.info('uitest: testSetTextInputType2 begin'); + let driver = Driver.create(); + let buttonComponent = await driver.findComponent(ON.text('TextInput', MatchPattern.CONTAINS)); + expect(buttonComponent === null).assertFalse(); + await buttonComponent.click(); + let str = await getResourceString($r('app.string.SetTextInputType_title')); + let sampleButton = await driver.findComponent(ON.text(str, MatchPattern.CONTAINS)); + expect(sampleButton === null).assertFalse(); + await sampleButton.click(); + + let textInput5 = await driver.findComponent(ON.id('PhoneNumber')); + let textInput6 = await driver.findComponent(ON.id('NUMBER_DECIMAL')); + let textInput7 = await driver.findComponent(ON.id('URL')); + + expect(textInput5 === null).assertFalse(); + expect(textInput6 === null).assertFalse(); + expect(textInput7 === null).assertFalse(); + + await textInput5.inputText('+86 123-0123-0456'); + await textInput6.inputText('9.15'); + await textInput7.inputText('http://www.example.com'); + + await driver.pressBack(); + await driver.pressBack(); + + console.info('uitest: testSetTextInputType2 end'); + done(); + }) + + /** + * @tc.number UiTest_010 + * @tc.name testCustomTextInputStyle + * @tc.desc 测试自定义文本输入框样式场景示例 + * @tc.level: Level 1 + */ + it('testCustomTextInputStyle', Level.LEVEL1, async (done: Function) => { + console.info('uitest: testCustomTextInputStyle begin'); + let driver = Driver.create(); + let buttonComponent = await driver.findComponent(ON.text('TextInput', MatchPattern.CONTAINS)); + expect(buttonComponent === null).assertFalse(); + await buttonComponent.click(); + let str = await getResourceString($r('app.string.CustomTextInputStyle_title')); + let sampleButton = await driver.findComponent(ON.text(str, MatchPattern.CONTAINS)); + expect(sampleButton === null).assertFalse(); + await sampleButton.click(); + + str = await getResourceString($r('app.string.CustomTextInputStyle_textContent_2')); + let textInput = await driver.findComponent(ON.text(str, MatchPattern.CONTAINS)); + expect(textInput === null).assertFalse(); + await textInput.inputText('textInput'); + await driver.pressBack(); + await driver.pressBack(); + console.info('uitest: testCustomTextInputStyle end'); + done(); + }) + + /** + * @tc.number UiTest_011 + * @tc.name testTextInputAddEvent + * @tc.desc 测试文本输入框增加事件场景示例 + * @tc.level: Level 1 + */ + it('testTextInputAddEvent', Level.LEVEL1, async (done: Function) => { + console.info('uitest: testTextInputAddEvent begin'); + let driver = Driver.create(); + let buttonComponent = await driver.findComponent(ON.text('TextInput', MatchPattern.CONTAINS)); + expect(buttonComponent === null).assertFalse(); + await buttonComponent.click(); + let str = await getResourceString($r('app.string.TextInputAddEvent_title')); + let sampleButton = await driver.findComponent(ON.text(str, MatchPattern.CONTAINS)); + expect(sampleButton === null).assertFalse(); + await sampleButton.click(); + + str = await getResourceString($r('app.string.TextInputAddEvent_textContent_2')); + let textInput = await driver.findComponent(ON.type('TextInput')); + expect(textInput === null).assertFalse(); + await textInput.inputText('textInput'); + await driver.pressBack(); + await driver.pressBack(); + console.info('uitest: testTextInputAddEvent end'); + done(); + }) + + /** + * @tc.number UiTest_012 + * @tc.name testTextInputSelectMenu + * @tc.desc 测试设置选中菜单场景示例 + * @tc.level: Level 1 + */ + it('testTextInputSelectMenu', Level.LEVEL1, async (done: Function) => { + console.info('uitest: testTextInputSelectMenu begin'); + let driver = Driver.create(); + let buttonComponent = await driver.findComponent(ON.text('TextInput', MatchPattern.CONTAINS)); + expect(buttonComponent === null).assertFalse(); + await buttonComponent.click(); + let str = await getResourceString($r('app.string.SelectionMenu_title')); + let sampleButton = await driver.findComponent(ON.text(str, MatchPattern.CONTAINS)); + expect(sampleButton === null).assertFalse(); + await sampleButton.click(); + + str = await getResourceString($r('app.string.SelectMenu_textContent_1')); + let selectMenuText = await driver.findComponent(ON.text(str, MatchPattern.CONTAINS)); + expect(selectMenuText === null).assertFalse(); + + await driver.pressBack(); + await driver.pressBack(); + console.info('uitest: testTextInputSelectMenu end'); + done(); + }) + + /** + * @tc.number UiTest_013 + * @tc.name testTextInputAutoFill + * @tc.desc 自动填充 + * @tc.level: Level 1 + */ + it('testTextInputAutoFill', Level.LEVEL1, async (done: Function) => { + console.info('uitest: testTextInputAutoFill begin'); + let driver = Driver.create(); + let buttonComponent = await driver.findComponent(ON.text('TextInput', MatchPattern.CONTAINS)); + expect(buttonComponent === null).assertFalse(); + await buttonComponent.click(); + let str = await getResourceString($r('app.string.Auto_Fill')); + let sampleButton = await driver.findComponent(ON.text(str, MatchPattern.CONTAINS)); + expect(sampleButton === null).assertFalse(); + await sampleButton.click(); + await driver.pressBack(); + await driver.pressBack(); + console.info('uitest: testTextInputAutoFill end'); + done(); + }) + + /** + * @tc.number UiTest_014 + * @tc.name testSetOmissionProperty + * @tc.desc 设置省略属性 + * @tc.level: Level 1 + */ + it('testSetOmissionProperty', Level.LEVEL1, async (done: Function) => { + console.info('uitest: testSetOmissionProperty begin'); + let driver = Driver.create(); + let buttonComponent = await driver.findComponent(ON.text('TextInput', MatchPattern.CONTAINS)); + expect(buttonComponent === null).assertFalse(); + await buttonComponent.click(); + let str = await getResourceString($r('app.string.Set_Omission_Property')); + let sampleButton = await driver.findComponent(ON.text(str, MatchPattern.CONTAINS)); + expect(sampleButton === null).assertFalse(); + await sampleButton.click(); + + str = await getResourceString($r('app.string.Set_Omission_Property_textContent')); + let textInput = await driver.findComponent(ON.type('TextInput', MatchPattern.CONTAINS)); + expect(textInput === null).assertFalse(); + await textInput.click(); + let selectMenuText = await driver.findComponent(ON.text(str, MatchPattern.CONTAINS)); + expect(selectMenuText === null).assertFalse(); + + await driver.pressBack(); + await driver.pressBack(); + console.info('uitest: testSetOmissionProperty end'); + done(); + }) + + /** + * @tc.number UiTest_015 + * @tc.name testKeyboardAvoidance + * @tc.desc 测试键盘避让场景示例 + * @tc.level: Level 1 + */ + it('testKeyboardAvoidance', Level.LEVEL1, async (done: Function) => { + console.info('uitest: testKeyboardAvoidance begin'); + let driver = Driver.create(); + let buttonComponent = await driver.findComponent(ON.text('TextInput', MatchPattern.CONTAINS)); + expect(buttonComponent === null).assertFalse(); + await buttonComponent.click(); + let str = await getResourceString($r('app.string.KeyboardAvoidance_title')); + let sampleButton = await driver.findComponent(ON.text(str, MatchPattern.CONTAINS)); + expect(sampleButton === null).assertFalse(); + await sampleButton.click(); + + let textInput = await driver.findComponent(ON.type('TextInput')); + await textInput.inputText('textInput'); + await driver.pressBack(); + await driver.pressBack(); + console.info('uitest: testKeyboardAvoidance end'); + done(); + }) + + /** + * @tc.number UiTest_016 + * @tc.name testCursorAvoidance + * @tc.desc 光标避让 + * @tc.level: Level 1 + */ + it('testCursorAvoidance', Level.LEVEL1, async (done: Function) => { + console.info('uitest: testCursorAvoidance begin'); + let driver = Driver.create(); + let buttonComponent = await driver.findComponent(ON.text('TextInput', MatchPattern.CONTAINS)); + expect(buttonComponent === null).assertFalse(); + await buttonComponent.click(); + let scrollComponent: Component = await driver.waitForComponent(ON.id('scroll_'), 1000); + let scrollCenter = await scrollComponent.getBoundsCenter(); + await driver.swipe(scrollCenter.x, scrollCenter.y + 400, scrollCenter.x, scrollCenter.y - 400, 3000); + await driver.waitForIdle(500, 500); + let str = await getResourceString($r('app.string.CursorAvoidance_title')); + let sampleButton = await driver.findComponent(ON.text(str, MatchPattern.CONTAINS)); + expect(sampleButton === null).assertFalse(); + await sampleButton.click(); + + let TextArea = await driver.findComponent(ON.type('TextArea')); + await TextArea.click(); + await driver.pressBack(); + await driver.pressBack(); + console.info('uitest: testCursorAvoidance end'); + done(); + }) + + /** + * @tc.number UiTest_017 + * @tc.name testLoginRegisterPage + * @tc.desc 测试登录/注册场景示例 + * @tc.level: Level 1 + */ + it('testLoginRegisterPage', Level.LEVEL1, async (done: Function) => { + console.info('uitest: testLoginRegisterPage begin'); + let driver = Driver.create(); + let buttonComponent = await driver.findComponent(ON.text('TextInput', MatchPattern.CONTAINS)); + expect(buttonComponent === null).assertFalse(); + await buttonComponent.click(); + let scrollComponent: Component = await driver.waitForComponent(ON.id('scroll_'), 1000); + let scrollCenter = await scrollComponent.getBoundsCenter(); + await driver.swipe(scrollCenter.x, scrollCenter.y + 400, scrollCenter.x, scrollCenter.y - 400, 3000); + await driver.waitForIdle(500, 500); + let str = await getResourceString($r('app.string.LoginRegisterPage_title')); + let sampleButton = await driver.findComponent(ON.text(str, MatchPattern.CONTAINS)); + expect(sampleButton === null).assertFalse(); + await sampleButton.click(); + + let username = await driver.findComponent(ON.id('username')); + let password = await driver.findComponent(ON.id('password')); + expect(username === null).assertFalse(); + expect(password === null).assertFalse(); + await username.inputText('username'); + await password.inputText('password'); + await driver.pressBack(); + await driver.pressBack(); + await driver.pressBack(); + console.info('uitest: testLoginRegisterPage end'); + done(); + }) + + /** + * @tc.number UiTest_018 + * @tc.name testCreateRichEditor + * @tc.desc 创建RichEditor组件 + * @tc.level: Level 1 + */ + it('testCreateRichEditor', Level.LEVEL1, async (done: Function) => { + console.info('uitest: testCreateRichEditor begin'); + let driver = Driver.create(); + let buttonComponent = await driver.findComponent(ON.text('RichEditor', MatchPattern.CONTAINS)); + expect(buttonComponent === null).assertFalse(); + await buttonComponent.click(); + let str = await getResourceString($r('app.string.Create_RichEditor_Component_title')); + let sampleButton = await driver.findComponent(ON.text(str, MatchPattern.CONTAINS)); + expect(sampleButton === null).assertFalse(); + await sampleButton.click(); + str = await getResourceString($r('app.string.Create_RichEditor_Component_title_1')); + let richEditor1 = await driver.findComponent(ON.text(str, MatchPattern.CONTAINS)); + str = await getResourceString($r('app.string.Create_RichEditor_Component_title_2')); + let richEditor2 = await driver.findComponent(ON.text(str, MatchPattern.CONTAINS)); + expect(richEditor1 === null).assertFalse(); + expect(richEditor2 === null).assertFalse(); + + await driver.pressBack(); + await driver.waitForIdle(2000, 2000); + await driver.pressBack(); + console.info('uitest: testCreateRichEditor end'); + done(); + }) + + /** + * @tc.number UiTest_019 + * @tc.name testSetAttributes + * @tc.desc 设置属性 + * @tc.level: Level 1 + */ + it('testSetAttributes', Level.LEVEL1, async (done: Function) => { + console.info('uitest: testSetAttributes begin'); + let driver = Driver.create(); + let buttonComponent = await driver.findComponent(ON.text('RichEditor', MatchPattern.CONTAINS)); + expect(buttonComponent === null).assertFalse(); + await buttonComponent.click(); + let str = await getResourceString($r('app.string.Set_Attributes_title')); + let sampleButton = await driver.findComponent(ON.text(str, MatchPattern.CONTAINS)); + expect(sampleButton === null).assertFalse(); + await sampleButton.click(); + let scrollComponent: Component = await driver.waitForComponent(ON.id('scroll_'), 1000); + let scrollCenter = await scrollComponent.getBoundsCenter(); + str = await getResourceString($r('app.string.Set_Attributes_title_1')); + let richEditor1 = await driver.findComponent(ON.text(str, MatchPattern.CONTAINS)); + str = await getResourceString($r('app.string.Set_Attributes_title_2')); + let richEditor2 = await driver.findComponent(ON.text(str, MatchPattern.CONTAINS)); + expect(richEditor1 === null).assertFalse(); + expect(richEditor2 === null).assertFalse(); + await driver.swipe(scrollCenter.x, scrollCenter.y + 400, scrollCenter.x, scrollCenter.y - 400, 3000); + await driver.waitForIdle(500, 500); + str = await getResourceString($r('app.string.Set_Attributes_title_3')); + let richEditor3 = await driver.findComponent(ON.text(str, MatchPattern.CONTAINS)); + str = await getResourceString($r('app.string.Set_Attributes_title_4')); + let richEditor4 = await driver.findComponent(ON.text(str, MatchPattern.CONTAINS)); + str = await getResourceString($r('app.string.Set_Attributes_title_5')); + let richEditor5 = await driver.findComponent(ON.text(str, MatchPattern.CONTAINS)); + str = await getResourceString($r('app.string.Set_Attributes_title_6')); + let richEditor6 = await driver.findComponent(ON.text(str, MatchPattern.CONTAINS)); + expect(richEditor3 === null).assertFalse(); + expect(richEditor4 === null).assertFalse(); + expect(richEditor5 === null).assertFalse(); + expect(richEditor6 === null).assertFalse(); + await driver.waitForIdle(500, 500); + await driver.pressBack(); + await driver.delayMs(1000); + await driver.pressBack(); + await driver.delayMs(1000); + console.info('uitest: testSetAttributes end'); + done(); + }) + + /** + * @tc.number UiTest_020 + * @tc.name testAddEvent + * @tc.desc 添加事件 + * @tc.level: Level 1 + */ + it('testAddEvent', Level.LEVEL1, async (done: Function) => { + console.info('uitest: testAddEvent begin'); + let driver = Driver.create(); + await driver.waitForIdle(500, 500); + let buttonComponent = await driver.findComponent(ON.text('RichEditor', MatchPattern.CONTAINS)); + expect(buttonComponent === null).assertFalse(); + await buttonComponent.click(); + let str = await getResourceString($r('app.string.Add_Event_title')); + let sampleButton = await driver.findComponent(ON.text(str, MatchPattern.CONTAINS)); + expect(sampleButton === null).assertFalse(); + await sampleButton.click(); + let scrollComponent: Component = await driver.waitForComponent(ON.id('scroll_'), 1000); + let scrollCenter = await scrollComponent.getBoundsCenter(); + str = await getResourceString($r('app.string.Add_Event_title_1')); + let richEditor1 = await driver.findComponent(ON.text(str, MatchPattern.CONTAINS)); + str = await getResourceString($r('app.string.Add_Event_title_2')); + let richEditor2 = await driver.findComponent(ON.text(str, MatchPattern.CONTAINS)); + str = await getResourceString($r('app.string.Add_Event_title_3')); + let richEditor3 = await driver.findComponent(ON.text(str, MatchPattern.CONTAINS)); + str = await getResourceString($r('app.string.Add_Event_title_4')); + let richEditor4 = await driver.findComponent(ON.text(str, MatchPattern.CONTAINS)); + expect(richEditor1 === null).assertFalse(); + expect(richEditor2 === null).assertFalse(); + expect(richEditor3 === null).assertFalse(); + expect(richEditor4 === null).assertFalse(); + + await driver.swipe(scrollCenter.x, scrollCenter.y + 400, scrollCenter.x, scrollCenter.y - 500, 3000); + await driver.waitForIdle(500, 500); + str = await getResourceString($r('app.string.Add_Event_title_5')); + let richEditor5 = await driver.findComponent(ON.text(str, MatchPattern.CONTAINS)); + str = await getResourceString($r('app.string.Add_Event_title_6')); + let richEditor6 = await driver.findComponent(ON.text(str, MatchPattern.CONTAINS)); + str = await getResourceString($r('app.string.Add_Event_title_7')); + let richEditor7 = await driver.findComponent(ON.text(str, MatchPattern.CONTAINS)); + expect(richEditor5 === null).assertFalse(); + expect(richEditor6 === null).assertFalse(); + expect(richEditor7 === null).assertFalse(); + await driver.waitForIdle(500, 500); + await driver.pressBack(); + await driver.waitForIdle(2000, 2000); + await driver.pressBack(); + console.info('uitest: testAddEvent end'); + done(); + }) + + /** + * @tc.number UiTest_021 + * @tc.name testSetUserPresetTextStyles + * @tc.desc 通过setTypingStyle设置用户预设的文本样式 + * @tc.level: Level 1 + */ + it('testSetUserPresetTextStyles', Level.LEVEL1, async (done: Function) => { + console.info('uitest: testSetUserPresetTextStyles begin'); + let driver = Driver.create(); + let buttonComponent = await driver.findComponent(ON.text('RichEditor', MatchPattern.CONTAINS)); + expect(buttonComponent === null).assertFalse(); + await buttonComponent.click(); + let str = await getResourceString($r('app.string.Set_User_PresetText_Styles_title')); + let sampleButton = await driver.findComponent(ON.text(str, MatchPattern.CONTAINS)); + expect(sampleButton === null).assertFalse(); + await sampleButton.click(); + await driver.pressBack(); + await driver.waitForIdle(2000, 2000); + await driver.pressBack(); + console.info('uitest: testSetUserPresetTextStyles end'); + done(); + }) + + /** + * @tc.number UiTest_022 + * @tc.name testBackplaneHighlighting + * @tc.desc 通过setSelection设置组件内的内容选中时部分背板高亮 + * @tc.level: Level 1 + */ + it('testBackplaneHighlighting', Level.LEVEL1, async (done: Function) => { + console.info('uitest: testBackplaneHighlighting begin'); + let driver = Driver.create(); + let buttonComponent = await driver.findComponent(ON.text('RichEditor', MatchPattern.CONTAINS)); + expect(buttonComponent === null).assertFalse(); + await buttonComponent.click(); + let str = await getResourceString($r('app.string.Backplane_Highlighting_title')); + let sampleButton = await driver.findComponent(ON.text(str, MatchPattern.CONTAINS)); + expect(sampleButton === null).assertFalse(); + await sampleButton.click(); + await driver.pressBack(); + await driver.waitForIdle(2000, 2000); + await driver.pressBack(); + console.info('uitest: testBackplaneHighlighting end'); + done(); + }) + + /** + * @tc.number UiTest_023 + * @tc.name testAddTextContent + * @tc.desc 添加文本内容 + * @tc.level: Level 1 + */ + it('testAddTextContent', Level.LEVEL1, async (done: Function) => { + console.info('uitest: testAddTextContent begin'); + let driver = Driver.create(); + let buttonComponent = await driver.findComponent(ON.text('RichEditor', MatchPattern.CONTAINS)); + expect(buttonComponent === null).assertFalse(); + await buttonComponent.click(); + let str = await getResourceString($r('app.string.Add_TextContent_title')); + let sampleButton = await driver.findComponent(ON.text(str, MatchPattern.CONTAINS)); + expect(sampleButton === null).assertFalse(); + await sampleButton.click(); + let button = await driver.findComponent(ON.text('addTextSpan')); + expect(button === null).assertFalse(); + await button.click(); + str = await getResourceString($r('app.string.AddTextContent_Text_2')); + let richEditor1 = await driver.findComponent(ON.text(str, MatchPattern.CONTAINS)); + expect(richEditor1 === null).assertFalse(); + await driver.pressBack(); + await driver.waitForIdle(2000, 2000); + await driver.pressBack(); + console.info('uitest: testAddTextContent end'); + done(); + }) + + /** + * @tc.number UiTest_024 + * @tc.name testAddImageContent + * @tc.desc 添加图片内容 + * @tc.level: Level 1 + */ + it('testAddImageContent', Level.LEVEL1, async (done: Function) => { + console.info('uitest: testAddImageContent begin'); + let driver = Driver.create(); + let buttonComponent = await driver.findComponent(ON.text('RichEditor', MatchPattern.CONTAINS)); + expect(buttonComponent === null).assertFalse(); + await buttonComponent.click(); + let str = await getResourceString($r('app.string.Add_ImageContent_title')); + let sampleButton = await driver.findComponent(ON.text(str, MatchPattern.CONTAINS)); + expect(sampleButton === null).assertFalse(); + await sampleButton.click(); + let button = await driver.findComponent(ON.text('addImageSpan')); + expect(button === null).assertFalse(); + await button.click(); + str = await getResourceString($r('app.string.AddImageContent_Text_1')); + let richEditor1 = await driver.findComponent(ON.text(str, MatchPattern.CONTAINS)); + expect(richEditor1 === null).assertFalse(); + await driver.pressBack(); + await driver.waitForIdle(2000, 2000); + await driver.pressBack(); + console.info('uitest: testAddImageContent end'); + done(); + }) + + /** + * @tc.number UiTest_025 + * @tc.name testAddBuilderDecoratorContent + * @tc.desc 添加@Builder装饰器修饰的内容 + * @tc.level: Level 1 + */ + it('testAddBuilderDecoratorContent', Level.LEVEL1, async (done: Function) => { + console.info('uitest: testAddBuilderDecoratorContent begin'); + let driver = Driver.create(); + let buttonComponent = await driver.findComponent(ON.text('RichEditor', MatchPattern.CONTAINS)); + expect(buttonComponent === null).assertFalse(); + await buttonComponent.click(); + let str = await getResourceString($r('app.string.Add_Builder_DecoratorContent_title')); + let sampleButton = await driver.findComponent(ON.text(str, MatchPattern.CONTAINS)); + expect(sampleButton === null).assertFalse(); + await sampleButton.click(); + let button = await driver.findComponent(ON.text('addBuilderSpan')); + expect(button === null).assertFalse(); + await button.click(); + str = await getResourceString($r('app.string.AddBuilderDecoratorContent_Text_3')); + let richEditor1 = await driver.findComponent(ON.text(str, MatchPattern.CONTAINS)); + expect(richEditor1 === null).assertFalse(); + await driver.pressBack(); + await driver.waitForIdle(2000, 2000); + await driver.pressBack(); + console.info('uitest: testAddBuilderDecoratorContent end'); + done(); + }) + + /** + * @tc.number UiTest_026 + * @tc.name testAddSymbolSpanContent + * @tc.desc 添加SymbolSpan内容 + * @tc.level: Level 1 + */ + it('testAddSymbolSpanContent', Level.LEVEL1, async (done: Function) => { + console.info('uitest: testAddSymbolSpanContent begin'); + let driver = Driver.create(); + let buttonComponent = await driver.findComponent(ON.text('RichEditor', MatchPattern.CONTAINS)); + expect(buttonComponent === null).assertFalse(); + await buttonComponent.click(); + let scrollComponent: Component = await driver.waitForComponent(ON.id('scroll_'), 1000); + let scrollCenter = await scrollComponent.getBoundsCenter(); + await driver.swipe(scrollCenter.x, scrollCenter.y + 400, scrollCenter.x, scrollCenter.y - 400, 3000); + await driver.waitForIdle(500, 500); + let str = await getResourceString($r('app.string.Add_SymbolSpanContent_title')); + let sampleButton = await driver.findComponent(ON.text(str, MatchPattern.CONTAINS)); + expect(sampleButton === null).assertFalse(); + await sampleButton.click(); + let button = await driver.findComponent(ON.text('addSymbolSpan')); + expect(button === null).assertFalse(); + await button.click(); + str = await getResourceString($r('app.string.AddSymbolSpanContent_Text_1')); + let richEditor1 = await driver.findComponent(ON.text(str, MatchPattern.CONTAINS)); + expect(richEditor1 === null).assertFalse(); + await driver.pressBack(); + await driver.waitForIdle(2000, 2000); + await driver.pressBack(); + console.info('uitest: testAddSymbolSpanContent end'); + done(); + }) + + /** + * @tc.number UiTest_027 + * @tc.name testGetGraphicInfoInComponent + * @tc.desc 获取组件内图文信息 + * @tc.level: Level 1 + */ + it('testGetGraphicInfoInComponent', Level.LEVEL1, async (done: Function) => { + console.info('uitest: testGetGraphicInfoInComponent begin'); + let driver = Driver.create(); + let buttonComponent = await driver.findComponent(ON.text('RichEditor', MatchPattern.CONTAINS)); + expect(buttonComponent === null).assertFalse(); + await buttonComponent.click(); + let scrollComponent: Component = await driver.waitForComponent(ON.id('scroll_'), 1000); + let scrollCenter = await scrollComponent.getBoundsCenter(); + await driver.swipe(scrollCenter.x, scrollCenter.y + 400, scrollCenter.x, scrollCenter.y - 400, 3000); + await driver.waitForIdle(500, 500); + let str = await getResourceString($r('app.string.Get_GraphicInfo_In_Component_title')); + let sampleButton = await driver.findComponent(ON.text(str, MatchPattern.CONTAINS)); + expect(sampleButton === null).assertFalse(); + await sampleButton.click(); + let button = await driver.findComponent(ON.text('getSpans')); + expect(button === null).assertFalse(); + await button.click(); + str = await getResourceString($r('app.string.GetGraphicInfoInComponent_Text_1')); + let richEditor1 = await driver.findComponent(ON.text(str, MatchPattern.CONTAINS)); + expect(richEditor1 === null).assertFalse(); + await driver.pressBack(); + await driver.waitForIdle(2000, 2000); + await driver.pressBack(); + console.info('uitest: testGetGraphicInfoInComponent end'); + done(); + }) + + /** + * @tc.number UiTest_028 + * @tc.name testCreatSymbolGlyph + * @tc.desc 测试创建图标场景示例 + * @tc.level: Level 1 + */ + it('testCreatSymbolGlyph', Level.LEVEL1, async (done: Function) => { + console.info('uitest: testCreatSymbolGlyph begin'); + let driver = Driver.create(); + let buttonComponent = await driver.findComponent(ON.text('SymbolGlyph', MatchPattern.CONTAINS)); + expect(buttonComponent === null).assertFalse(); + await buttonComponent.click(); + let str = await getResourceString($r('app.string.CreatSymbolGlyph_title')); + let sampleButton = await driver.findComponent(ON.text(str, MatchPattern.CONTAINS)); + expect(sampleButton === null).assertFalse(); + await sampleButton.click(); + + let symbolGlyph = await driver.findComponent(ON.type('SymbolGlyph')); + expect(symbolGlyph === null).assertFalse(); + + await driver.pressBack(); + await driver.waitForIdle(2000, 2000); + await driver.pressBack(); + console.info('uitest: testCreatSymbolGlyph end'); + done(); + }) + + /** + * @tc.number UiTest_029 + * @tc.name testSymbolGlyphSpanAddToText + * @tc.desc 测试添加到文本场景示例 + * @tc.level: Level 1 + */ + it('testSymbolGlyphSpanAddToText', Level.LEVEL1, async (done: Function) => { + console.info('uitest: testSymbolGlyphSpanAddToText begin'); + let driver = Driver.create(); + let buttonComponent = await driver.findComponent(ON.text('SymbolGlyph', MatchPattern.CONTAINS)); + expect(buttonComponent === null).assertFalse(); + await buttonComponent.click(); + let str = await getResourceString($r('app.string.SymbolGlyphSpanAddToText_title')); + let sampleButton = await driver.findComponent(ON.text(str, MatchPattern.CONTAINS)); + expect(sampleButton === null).assertFalse(); + await sampleButton.click(); + + let symbolSpan1 = await driver.findComponent(ON.id('1')); + expect(symbolSpan1 === null).assertFalse(); + + let text2 = await driver.findComponent(ON.text('48')); + expect(text2 === null).assertFalse(); + let text3 = await driver.findComponent(ON.text('72')); + expect(text3 === null).assertFalse(); + let text4 = await driver.findComponent(ON.text('96')); + expect(text4 === null).assertFalse(); + + let symbolSpan2 = await driver.findComponent(ON.id('2')); + expect(symbolSpan2 === null).assertFalse(); + let symbolSpan3 = await driver.findComponent(ON.id('3')); + expect(symbolSpan3 === null).assertFalse(); + let symbolSpan4 = await driver.findComponent(ON.id('4')); + expect(symbolSpan4 === null).assertFalse(); + + let scrollComponent: Component = await driver.waitForComponent(ON.id('scroll_'), 1000); + let scrollCenter = await scrollComponent.getBoundsCenter(); + await driver.swipe(scrollCenter.x, scrollCenter.y + 400, scrollCenter.x, scrollCenter.y - 400, 3000); + await driver.waitForIdle(500, 500); + + let text5 = await driver.findComponent(ON.text('Light')); + expect(text5 === null).assertFalse(); + let text6 = await driver.findComponent(ON.text('Normal')); + expect(text6 === null).assertFalse(); + let text7 = await driver.findComponent(ON.text('Bold')); + expect(text7 === null).assertFalse(); + let text8 = await driver.findComponent(ON.text('Black')); + expect(text8 === null).assertFalse(); + let text9 = await driver.findComponent(ON.text('Green')); + expect(text9 === null).assertFalse(); + let text10 = await driver.findComponent(ON.text('Pink')); + expect(text10 === null).assertFalse(); + str = await getResourceString($r('app.string.SymbolAddToText_Text_1')); + let text11 = await driver.findComponent(ON.text(str)); + expect(text11 === null).assertFalse(); + str = await getResourceString($r('app.string.SymbolAddToText_Text_2')); + let text12 = await driver.findComponent(ON.text(str)); + expect(text12 === null).assertFalse(); + str = await getResourceString($r('app.string.SymbolAddToText_Text_3')); + let text13 = await driver.findComponent(ON.text(str)); + expect(text13 === null).assertFalse(); + str = await getResourceString($r('app.string.SymbolAddToText_Text_4')); + let text14 = await driver.findComponent(ON.text(str)); + expect(text14 === null).assertFalse(); + str = await getResourceString($r('app.string.SymbolAddToText_Text_5')); + let text15 = await driver.findComponent(ON.text(str)); + expect(text15 === null).assertFalse(); + str = await getResourceString($r('app.string.SymbolAddToText_Text_6')); + let text16 = await driver.findComponent(ON.text(str)); + expect(text16 === null).assertFalse(); + + let symbolSpan5 = await driver.findComponent(ON.id('5')); + expect(symbolSpan5 === null).assertFalse(); + let symbolSpan6 = await driver.findComponent(ON.id('6')); + expect(symbolSpan6 === null).assertFalse(); + let symbolSpan7 = await driver.findComponent(ON.id('7')); + expect(symbolSpan7 === null).assertFalse(); + let symbolSpan8 = await driver.findComponent(ON.id('8')); + expect(symbolSpan8 === null).assertFalse(); + let symbolSpan9 = await driver.findComponent(ON.id('9')); + expect(symbolSpan9 === null).assertFalse(); + let symbolSpan10 = await driver.findComponent(ON.id('10')); + expect(symbolSpan10 === null).assertFalse(); + let symbolSpan11 = await driver.findComponent(ON.id('11')); + expect(symbolSpan11 === null).assertFalse(); + let symbolSpan12 = await driver.findComponent(ON.id('12')); + expect(symbolSpan12 === null).assertFalse(); + let symbolSpan13 = await driver.findComponent(ON.id('13')); + expect(symbolSpan13 === null).assertFalse(); + let symbolSpan14 = await driver.findComponent(ON.id('14')); + expect(symbolSpan14 === null).assertFalse(); + let symbolSpan15 = await driver.findComponent(ON.id('15')); + expect(symbolSpan15 === null).assertFalse(); + let symbolSpan16 = await driver.findComponent(ON.id('16')); + expect(symbolSpan16 === null).assertFalse(); + + await driver.pressBack(); + await driver.pressBack(); + console.info('uitest: testSymbolGlyphSpanAddToText end'); + done(); + }) + + /** + * @tc.number UiTest_030 + * @tc.name testSymbolGlyphSpanCustomIconAnimation + * @tc.desc 测试自定义图标动效场景示例 + * @tc.level: Level 1 + */ + it('testSymbolGlyphSpanCustomIconAnimation', Level.LEVEL1, async (done: Function) => { + console.info('uitest: testSymbolGlyphSpanCustomIconAnimation begin'); + let driver = Driver.create(); + await driver.waitForIdle(500, 500); + let buttonComponent = await driver.findComponent(ON.text('SymbolGlyph', MatchPattern.CONTAINS)); + expect(buttonComponent === null).assertFalse(); + await buttonComponent.click(); + let str = await getResourceString($r('app.string.SymbolGlyphSpanCustomIconAnimation_title')); + let sampleButton = await driver.findComponent(ON.text(str, MatchPattern.CONTAINS)); + expect(sampleButton === null).assertFalse(); + await sampleButton.click(); + + str = await getResourceString($r('app.string.SymbolCustomIconAnimation_Text_1')); + let text1 = await driver.findComponent(ON.text(str)); + expect(text1 === null).assertFalse(); + let symbolGlyph1 = await driver.findComponent(ON.id('1')); + expect(symbolGlyph1 === null).assertFalse(); + str = await getResourceString($r('app.string.SymbolGlyphSpanCustomIconAnimation_Button_1')); + let button1 = await driver.findComponent(ON.text(str)); + expect(button1 === null).assertFalse(); + await button1.click(); + str = await getResourceString($r('app.string.SymbolGlyphSpanCustomIconAnimation_Button_2')); + expect(await button1.getText() === str).assertTrue(); + + str = await getResourceString($r('app.string.SymbolCustomIconAnimation_Text_2')); + let text2 = await driver.findComponent(ON.text(str)); + expect(text2 === null).assertFalse(); + let symbolGlyph2 = await driver.findComponent(ON.id('2')); + expect(symbolGlyph2 === null).assertFalse(); + let button2 = await driver.findComponent(ON.text('trigger')); + expect(button2 === null).assertFalse(); + await button1.click(); + await driver.waitForIdle(500, 500); + await driver.pressBack(); + await driver.delayMs(1000); + await driver.pressBack(); + console.info('uitest: testSymbolGlyphSpanCustomIconAnimation end'); + done(); + }) + + /** + * @tc.number UiTest_031 + * @tc.name testSymbolGlyphSpanAddEvent + * @tc.desc 测试添加事件场景示例 + * @tc.level: Level 1 + */ + it('testSymbolGlyphSpanAddEvent', Level.LEVEL1, async (done: Function) => { + console.info('uitest: testSymbolGlyphSpanAddEvent begin'); + let driver = Driver.create(); + await driver.waitForIdle(500, 500); + let buttonComponent = await driver.findComponent(ON.text('SymbolGlyph', MatchPattern.CONTAINS)); + expect(buttonComponent === null).assertFalse(); + await buttonComponent.click(); + let str = await getResourceString($r('app.string.SymbolGlyphSpanAddEvent_title')); + let sampleButton = await driver.findComponent(ON.text(str, MatchPattern.CONTAINS)); + expect(sampleButton === null).assertFalse(); + await sampleButton.click(); + + let symbolGlyph = await driver.findComponent(ON.id('symbolGlyph1')); + expect(symbolGlyph === null).assertFalse(); + await symbolGlyph.click(); + await driver.waitForIdle(500, 500); + await driver.delayMs(1000); + await driver.pressBack(); + await driver.waitForIdle(2000, 2000); + await driver.pressBack(); + console.info('uitest: testSymbolGlyphSpanAddEvent end'); + done(); + }) + + /** + * @tc.number UiTest_032 + * @tc.name testSymbolGlyphSpanSceneExample + * @tc.desc 测试播放列表场景示例 + * @tc.level: Level 1 + */ + it('testSymbolGlyphSpanSceneExample', Level.LEVEL1, async (done: Function) => { + console.info('uitest: testSymbolGlyphSpanSceneExample begin'); + let driver = Driver.create(); + await driver.waitForIdle(500, 500); + let buttonComponent = await driver.findComponent(ON.text('SymbolGlyph', MatchPattern.CONTAINS)); + expect(buttonComponent === null).assertFalse(); + await buttonComponent.click(); + let str = await getResourceString($r('app.string.SymbolGlyphSpanSceneExample_title')); + let sampleButton = await driver.findComponent(ON.text(str, MatchPattern.CONTAINS)); + expect(sampleButton === null).assertFalse(); + await sampleButton.click(); + + let text1 = await driver.findComponent(ON.id('text1')); + expect(text1 === null).assertFalse(); + let symbolGlyph1 = await driver.findComponent(ON.id('symbolGlyph1')); + expect(symbolGlyph1 === null).assertFalse(); + str = await getResourceString($r('app.string.SymbolSceneExample_Text_1')); + let text = await driver.findComponent(ON.text(str)); + expect(text === null).assertFalse(); + await text.click(); + str = await getResourceString($r('app.string.SymbolSceneExample_Text_2')); + expect(await text.getText() === str).assertTrue(); + await text.click(); + str = await getResourceString($r('app.string.SymbolSceneExample_Text_3')); + expect(await text.getText() === str).assertTrue(); + let text2 = await driver.findComponent(ON.id('text2')); + expect(text2 === null).assertFalse(); + let text3 = await driver.findComponent(ON.id('text3')); + expect(text3 === null).assertFalse(); + let text4 = await driver.findComponent(ON.id('text4')); + expect(text4 === null).assertFalse(); + + str = await getResourceString($r('app.string.SymbolSceneExample_Text_5')); + let text5 = await driver.findComponent(ON.text(str)); + expect(text5 === null).assertFalse(); + let symbolGlyph2 = await driver.findComponent(ON.id('symbolGlyph2')); + expect(symbolGlyph2 === null).assertFalse(); + let symbolGlyph3 = await driver.findComponent(ON.id('symbolGlyph3')); + expect(symbolGlyph3 === null).assertFalse(); + str = await getResourceString($r('app.string.SymbolSceneExample_Text_6')); + let text6 = await driver.findComponent(ON.text(str)); + expect(text6 === null).assertFalse(); + let symbolGlyph4 = await driver.findComponent(ON.id('symbolGlyph4')); + expect(symbolGlyph4 === null).assertFalse(); + let symbolGlyph5 = await driver.findComponent(ON.id('symbolGlyph5')); + expect(symbolGlyph5 === null).assertFalse(); + str = await getResourceString($r('app.string.SymbolSceneExample_Text_7')); + let text7 = await driver.findComponent(ON.text(str)); + expect(text7 === null).assertFalse(); + let symbolGlyph6 = await driver.findComponent(ON.id('symbolGlyph6')); + expect(symbolGlyph6 === null).assertFalse(); + let symbolGlyph7 = await driver.findComponent(ON.id('symbolGlyph7')); + expect(symbolGlyph7 === null).assertFalse(); + str = await getResourceString($r('app.string.SymbolSceneExample_Text_8')); + let text8 = await driver.findComponent(ON.text(str)); + expect(text8 === null).assertFalse(); + let symbolGlyph8 = await driver.findComponent(ON.id('symbolGlyph8')); + expect(symbolGlyph8 === null).assertFalse(); + let symbolGlyph9 = await driver.findComponent(ON.id('symbolGlyph9')); + expect(symbolGlyph9 === null).assertFalse(); + str = await getResourceString($r('app.string.SymbolSceneExample_Text_9')); + let text9 = await driver.findComponent(ON.text(str)); + expect(text9 === null).assertFalse(); + let symbolGlyph10 = await driver.findComponent(ON.id('symbolGlyph10')); + expect(symbolGlyph10 === null).assertFalse(); + let symbolGlyph11 = await driver.findComponent(ON.id('symbolGlyph11')); + expect(symbolGlyph11 === null).assertFalse(); + str = await getResourceString($r('app.string.SymbolSceneExample_Text_10')); + let text10 = await driver.findComponent(ON.text(str)); + expect(text10 === null).assertFalse(); + let symbolGlyph12 = await driver.findComponent(ON.id('symbolGlyph12')); + expect(symbolGlyph12 === null).assertFalse(); + let symbolGlyph13 = await driver.findComponent(ON.id('symbolGlyph13')); + expect(symbolGlyph13 === null).assertFalse(); + str = await getResourceString($r('app.string.SymbolSceneExample_Text_11')); + let text11 = await driver.findComponent(ON.text(str)); + expect(text11 === null).assertFalse(); + let symbolGlyph14 = await driver.findComponent(ON.id('symbolGlyph14')); + expect(symbolGlyph14 === null).assertFalse(); + let symbolGlyph15 = await driver.findComponent(ON.id('symbolGlyph15')); + expect(symbolGlyph15 === null).assertFalse(); + str = await getResourceString($r('app.string.SymbolSceneExample_Text_12')); + let text12 = await driver.findComponent(ON.text(str)); + expect(text12 === null).assertFalse(); + + await driver.pressBack(); + await driver.waitForIdle(2000, 2000); + await driver.pressBack(); + console.info('uitest: testSymbolGlyphSpanSceneExample end'); + done(); + }) + + /** + * @tc.number UiTest_033 + * @tc.name testCreateApply + * @tc.desc 测试创建并应用属性字符串场景示例 + * @tc.level: Level 1 + */ + it('testCreateApply', Level.LEVEL1, async (done: Function) => { + console.info('uitest: testCreateApply begin'); + let driver = Driver.create(); + let buttonComponent = await driver.findComponent(ON.text('StyledString', MatchPattern.CONTAINS)); + expect(buttonComponent === null).assertFalse(); + await buttonComponent.click(); + let str = await getResourceString($r('app.string.Create_Apply_StyledString_MutableStyledString_title')); + let sampleButton = await driver.findComponent(ON.text(str, MatchPattern.CONTAINS)); + expect(sampleButton === null).assertFalse(); + await sampleButton.click(); + + str = await getResourceString($r('app.string.CreateApply_Text_1')); + let styledString = await driver.findComponent(ON.text(str)); + expect(styledString === null).assertFalse(); + str = await getResourceString($r('app.string.CreateApply_Text_2')); + let mutableStyledString = await driver.findComponent(ON.text(str)); + expect(mutableStyledString === null).assertFalse(); + + await driver.pressBack(); + await driver.waitForIdle(2000, 2000); + await driver.pressBack(); + console.info('uitest: testCreateApply end'); + done(); + }) + + /** + * @tc.number UiTest_034 + * @tc.name testStyledStringStyle + * @tc.desc 测试设置文本样式场景示例 + * @tc.level: Level 1 + */ + it('testStyledStringStyle', Level.LEVEL1, async (done: Function) => { + console.info('uitest: testStyledStringStyle begin'); + let driver = Driver.create(); + let buttonComponent = await driver.findComponent(ON.text('StyledString', MatchPattern.CONTAINS)); + expect(buttonComponent === null).assertFalse(); + await buttonComponent.click(); + let str = await getResourceString($r('app.string.StyledStringStyle_title')); + let sampleButton = await driver.findComponent(ON.text(str, MatchPattern.CONTAINS)); + expect(sampleButton === null).assertFalse(); + await sampleButton.click(); + + let mutableStyledString1 = await driver.findComponent(ON.id('1')); + expect(mutableStyledString1 === null).assertFalse(); + let mutableStyledString2 = await driver.findComponent(ON.id('2')); + expect(mutableStyledString2 === null).assertFalse(); + let mutableStyledString3 = await driver.findComponent(ON.id('3')); + expect(mutableStyledString3 === null).assertFalse(); + let mutableStyledString4 = await driver.findComponent(ON.id('4')); + expect(mutableStyledString4 === null).assertFalse(); + let mutableStyledString5 = await driver.findComponent(ON.id('5')); + expect(mutableStyledString5 === null).assertFalse(); + let mutableStyledString6 = await driver.findComponent(ON.id('6')); + expect(mutableStyledString6 === null).assertFalse(); + + await driver.pressBack(); + await driver.waitForIdle(2000, 2000); + await driver.pressBack(); + console.info('uitest: testStyledStringStyle end'); + done(); + }) + + /** + * @tc.number UiTest_035 + * @tc.name testStyledStringParagraphStyle + * @tc.desc 测试设置段落样式场景示例 + * @tc.level: Level 1 + */ + it('testStyledStringParagraphStyle', Level.LEVEL1, async (done: Function) => { + console.info('uitest: testStyledStringParagraphStyle begin'); + let driver = Driver.create(); + let buttonComponent = await driver.findComponent(ON.text('StyledString', MatchPattern.CONTAINS)); + expect(buttonComponent === null).assertFalse(); + await buttonComponent.click(); + let str = await getResourceString($r('app.string.StyledStringParagraphStyle_title')); + let sampleButton = await driver.findComponent(ON.text(str, MatchPattern.CONTAINS)); + expect(sampleButton === null).assertFalse(); + await sampleButton.click(); + + str = await getResourceString($r('app.string.StyledStringParagraphStyle_Text_1')); + let mutableStyledString1 = + await driver.findComponent(ON.text(str)); + expect(mutableStyledString1 === null).assertFalse(); + let button = await driver.findComponent(ON.text('change')); + expect(button === null).assertFalse(); + await button.click(); + await driver.waitForIdle(500, 500); + + await driver.pressBack(); + await driver.waitForIdle(2000, 2000); + await driver.pressBack(); + console.info('uitest: testStyledStringParagraphStyle end'); + done(); + }) + + /** + * @tc.number UiTest_036 + * @tc.name testStyledStringImageAttachment + * @tc.desc 测试使用图片场景示例 + * @tc.level: Level 1 + */ + it('testStyledStringImageAttachment', Level.LEVEL1, async (done: Function) => { + console.info('uitest: testStyledStringImageAttachment begin'); + let driver = Driver.create(); + let buttonComponent = await driver.findComponent(ON.text('StyledString', MatchPattern.CONTAINS)); + expect(buttonComponent === null).assertFalse(); + await buttonComponent.click(); + let str = await getResourceString($r('app.string.StyledStringImageAttachment_title')); + let sampleButton = await driver.findComponent(ON.text(str, MatchPattern.CONTAINS)); + expect(sampleButton === null).assertFalse(); + await sampleButton.click(); + + str = await getResourceString($r('app.string.StyledStringImageAttachment_Button_1')); + let button = await driver.findComponent(ON.text(str)); + expect(button === null).assertFalse(); + await button.click(); + await driver.waitForIdle(500, 500); + let text1 = await driver.findComponent(ON.id('text1')); + expect(text1 === null).assertFalse(); + + await driver.pressBack(); + await driver.waitForIdle(2000, 2000); + await driver.pressBack(); + console.info('uitest: testStyledStringImageAttachment end'); + done(); + }) + + /** + * @tc.number UiTest_037 + * @tc.name testStyledStringGestureStyle + * @tc.desc 测试设置事件场景示例 + * @tc.level: Level 1 + */ + it('testStyledStringGestureStyle', Level.LEVEL1, async (done: Function) => { + console.info('uitest: testStyledStringGestureStyle begin'); + let driver = Driver.create(); + let buttonComponent = await driver.findComponent(ON.text('StyledString', MatchPattern.CONTAINS)); + expect(buttonComponent === null).assertFalse(); + await buttonComponent.click(); + let str = await getResourceString($r('app.string.TStyledStringGestureStyle_title')); + let sampleButton = await driver.findComponent(ON.text(str, MatchPattern.CONTAINS)); + expect(sampleButton === null).assertFalse(); + await sampleButton.click(); + + let text1 = await driver.findComponent(ON.id('text1')); + expect(text1 === null).assertFalse(); + + await driver.pressBack(); + await driver.waitForIdle(2000, 2000); + await driver.pressBack(); + console.info('uitest: testStyledStringGestureStyle end'); + done(); + }) + + /** + * @tc.number UiTest_038 + * @tc.name testStyledStringHtml + * @tc.desc 测试格式转换场景示例 + * @tc.level: Level 1 + */ + it('testStyledStringHtml', Level.LEVEL1, async (done: Function) => { + console.info('uitest: testStyledStringHtml begin'); + let driver = Driver.create(); + let buttonComponent = await driver.findComponent(ON.text('StyledString', MatchPattern.CONTAINS)); + expect(buttonComponent === null).assertFalse(); + await buttonComponent.click(); + let str = await getResourceString($r('app.string.StyledStringHtml_title')); + let sampleButton = await driver.findComponent(ON.text(str, MatchPattern.CONTAINS)); + expect(sampleButton === null).assertFalse(); + await sampleButton.click(); + + str = await getResourceString($r('app.string.StyledStringHtml_Button_1')); + let addButton = await driver.findComponent(ON.text(str)); + expect(addButton === null).assertFalse(); + await addButton.click(); + await driver.waitForIdle(500, 500); + let text1 = await driver.findComponent(ON.id('text1')); + expect(text1 === null).assertFalse(); + + let toHtmlButton = await driver.findComponent(ON.text('toHtml')); + expect(toHtmlButton === null).assertFalse(); + await toHtmlButton.click(); + await driver.waitForIdle(500, 500); + let text3 = await driver.findComponent(ON.id('text3')); + expect(text3 === null).assertFalse(); + + let fromHtmlButton = await driver.findComponent(ON.text('fromHtml')); + expect(fromHtmlButton === null).assertFalse(); + await fromHtmlButton.click(); + await driver.waitForIdle(500, 500); + let text2 = await driver.findComponent(ON.id('text2')); + expect(text2 === null).assertFalse(); + + await driver.pressBack(); + await driver.waitForIdle(3000, 3000); + await driver.pressBack(); + console.info('uitest: testStyledStringHtml end'); + done(); + }) + + /** + * @tc.number UiTest_039 + * @tc.name testStyledStringSceneExample + * @tc.desc 测试会员过期提示场景示例 + * @tc.level: Level 1 + */ + it('testStyledStringSceneExample', Level.LEVEL1, async (done: Function) => { + console.info('uitest: testStyledStringSceneExample begin'); + let driver = Driver.create(); + let buttonComponent = await driver.findComponent(ON.text('StyledString', MatchPattern.CONTAINS)); + expect(buttonComponent === null).assertFalse(); + await buttonComponent.click(); + let str = await getResourceString($r('app.string.StyledStringSceneExample_title')); + let sampleButton = await driver.findComponent(ON.text(str, MatchPattern.CONTAINS)); + expect(sampleButton === null).assertFalse(); + await sampleButton.click(); + + let text1 = await driver.findComponent(ON.id('text1')); + expect(text1 === null).assertFalse(); + str = await getResourceString($r('app.string.StyledStringSceneExample_Button_1')); + let button = await driver.findComponent(ON.text(str)); + expect(button === null).assertFalse(); + + await driver.pressBack(); + await driver.waitForIdle(2000, 2000); + await driver.pressBack(); + console.info('uitest: testStyledStringSceneExample end'); + done(); + }) + + /** + * @tc.number UiTest_040 + * @tc.name testTextDrawingDisplay + * @tc.desc 测试Text组件的文本绘制与显示场景示例 + * @tc.level: Level 1 + */ + it('testTextDrawingDisplay', Level.LEVEL1, async (done: Function) => { + console.info('uitest: testTextDrawingDisplay begin'); + let driver = Driver.create(); + let buttonComponent = await driver.findComponent(ON.text('NDK', MatchPattern.CONTAINS)); + expect(buttonComponent === null).assertFalse(); + await buttonComponent.click(); + let str = await getResourceString($r('app.string.TextDrawingDisplay_NDK_title')); + let sampleButton = await driver.findComponent(ON.text(str, MatchPattern.CONTAINS)); + expect(sampleButton === null).assertFalse(); + await sampleButton.click(); + + let text = await driver.findComponent(ON.type('Text')); + expect(text === null).assertFalse(); + + await driver.pressBack(); + await driver.pressBack(); + console.info('uitest: testTextDrawingDisplay end'); + done(); + }) + + /** + * @tc.number UiTest_041 + * @tc.name testListenTextBoxEvents + * @tc.desc 测试输入框文本事件监听场景示例 + * @tc.level: Level 1 + */ + it('testListenTextBoxEvents', Level.LEVEL1, async (done: Function) => { + console.info('uitest: testListenTextBoxEvents begin'); + let driver = Driver.create(); + let buttonComponent = await driver.findComponent(ON.text('NDK', MatchPattern.CONTAINS)); + expect(buttonComponent === null).assertFalse(); + await buttonComponent.click(); + let str = await getResourceString($r('app.string.ListenTextBoxEvents_NDK_title')); + let sampleButton = await driver.findComponent(ON.text(str, MatchPattern.CONTAINS)); + expect(sampleButton === null).assertFalse(); + await sampleButton.click(); + + let textArea = await driver.findComponent(ON.type('TextArea')); + expect(textArea === null).assertFalse(); + + await driver.pressBack(); + await driver.pressBack(); + console.info('uitest: testListenTextBoxEvents end'); + done(); + }) + }) +} \ No newline at end of file diff --git a/ArkUISample/TextComponent/entry/src/ohosTest/module.json5 b/ArkUISample/TextComponent/entry/src/ohosTest/module.json5 new file mode 100644 index 0000000000000000000000000000000000000000..c3fd9dda3040d888d9d8b0b62bcb5d3b6fbeb614 --- /dev/null +++ b/ArkUISample/TextComponent/entry/src/ohosTest/module.json5 @@ -0,0 +1,27 @@ +/* + * Copyright (c) 2025 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +{ + "module": { + "name": "entry_test", + "type": "feature", + "deviceTypes": [ + "default", + "tablet" + ], + "deliveryWithInstall": true, + "installationFree": false + } +} diff --git a/ArkUISample/TextComponent/entry/src/test/List.test.ets b/ArkUISample/TextComponent/entry/src/test/List.test.ets new file mode 100644 index 0000000000000000000000000000000000000000..f1186b1f53c3a70930921c5dbd1417332bec56c9 --- /dev/null +++ b/ArkUISample/TextComponent/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/ArkUISample/TextComponent/entry/src/test/LocalUnit.test.ets b/ArkUISample/TextComponent/entry/src/test/LocalUnit.test.ets new file mode 100644 index 0000000000000000000000000000000000000000..7fc57c77dbf76d8df08a2b802a55b948e3fcf968 --- /dev/null +++ b/ArkUISample/TextComponent/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/ArkUISample/TextComponent/hvigor/hvigor-config.json5 b/ArkUISample/TextComponent/hvigor/hvigor-config.json5 new file mode 100644 index 0000000000000000000000000000000000000000..d584c19c247db9a7caee4b606bb931aa9279c637 --- /dev/null +++ b/ArkUISample/TextComponent/hvigor/hvigor-config.json5 @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2025 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +{ + "modelVersion": "5.0.1", + "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/ArkUISample/TextComponent/hvigorfile.ts b/ArkUISample/TextComponent/hvigorfile.ts new file mode 100644 index 0000000000000000000000000000000000000000..2a5e543f190732c159beb574dfc9fa37bc94e156 --- /dev/null +++ b/ArkUISample/TextComponent/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. */ +} diff --git a/ArkUISample/TextComponent/oh-package.json5 b/ArkUISample/TextComponent/oh-package.json5 new file mode 100644 index 0000000000000000000000000000000000000000..e41bae026aab3b50d0abb42fece08ba43b4a772b --- /dev/null +++ b/ArkUISample/TextComponent/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": "5.0.1", + "description": "Please describe the basic information.", + "dependencies": { + }, + "devDependencies": { + "@ohos/hypium": "1.0.19", + "@ohos/hamock": "1.0.0" + } +} diff --git a/ArkUISample/TextComponent/screenshots/device/image1.png b/ArkUISample/TextComponent/screenshots/device/image1.png new file mode 100644 index 0000000000000000000000000000000000000000..bf96a4175ed623325acd0dfe3cbc57e23a6f9c66 Binary files /dev/null and b/ArkUISample/TextComponent/screenshots/device/image1.png differ diff --git a/ArkUISample/TextComponent/screenshots/device/image2.jpeg b/ArkUISample/TextComponent/screenshots/device/image2.jpeg new file mode 100644 index 0000000000000000000000000000000000000000..8516710ce8b4ac1f3790841aa45d0302809e7c25 Binary files /dev/null and b/ArkUISample/TextComponent/screenshots/device/image2.jpeg differ diff --git a/ArkUISample/TextComponent/screenshots/device/image2.png b/ArkUISample/TextComponent/screenshots/device/image2.png new file mode 100644 index 0000000000000000000000000000000000000000..00b228d632b28003a8d2f515b667a583b485a6ce Binary files /dev/null and b/ArkUISample/TextComponent/screenshots/device/image2.png differ diff --git a/ArkUISample/TextComponent/screenshots/device/image3.jpeg b/ArkUISample/TextComponent/screenshots/device/image3.jpeg new file mode 100644 index 0000000000000000000000000000000000000000..ad6f0ba651630c7a10d878035860f8bd406676f2 Binary files /dev/null and b/ArkUISample/TextComponent/screenshots/device/image3.jpeg differ diff --git a/ArkUISample/TextComponent/screenshots/device/image3.png b/ArkUISample/TextComponent/screenshots/device/image3.png new file mode 100644 index 0000000000000000000000000000000000000000..9f6b9bd84e5506b9f62b1ef4d857d18ec0c5d268 Binary files /dev/null and b/ArkUISample/TextComponent/screenshots/device/image3.png differ