diff --git a/ArkUI/AppScope/app.json5 b/ArkUI/AppScope/app.json5 new file mode 100644 index 0000000000000000000000000000000000000000..8bff5a306558a4808d775ab15e41b6d3fdcd176e --- /dev/null +++ b/ArkUI/AppScope/app.json5 @@ -0,0 +1,10 @@ +{ + "app": { + "bundleName": "com.example.newsdemo", + "vendor": "example", + "versionCode": 1000000, + "versionName": "1.0.0", + "icon": "$media:layered_image", + "label": "$string:app_name" + } +} diff --git a/ArkUI/AppScope/resources/base/element/string.json b/ArkUI/AppScope/resources/base/element/string.json new file mode 100644 index 0000000000000000000000000000000000000000..c90fc83afa24888d48cfea70e9ebf4703348a0f9 --- /dev/null +++ b/ArkUI/AppScope/resources/base/element/string.json @@ -0,0 +1,8 @@ +{ + "string": [ + { + "name": "app_name", + "value": "ArkUIKit" + } + ] +} diff --git a/ArkUI/AppScope/resources/base/media/background.png b/ArkUI/AppScope/resources/base/media/background.png new file mode 100644 index 0000000000000000000000000000000000000000..923f2b3f27e915d6871871deea0420eb45ce102f Binary files /dev/null and b/ArkUI/AppScope/resources/base/media/background.png differ diff --git a/ArkUI/AppScope/resources/base/media/foreground.png b/ArkUI/AppScope/resources/base/media/foreground.png new file mode 100644 index 0000000000000000000000000000000000000000..97014d3e10e5ff511409c378cd4255713aecd85f Binary files /dev/null and b/ArkUI/AppScope/resources/base/media/foreground.png differ diff --git a/ArkUI/AppScope/resources/base/media/layered_image.json b/ArkUI/AppScope/resources/base/media/layered_image.json new file mode 100644 index 0000000000000000000000000000000000000000..fb49920440fb4d246c82f9ada275e26123a2136a --- /dev/null +++ b/ArkUI/AppScope/resources/base/media/layered_image.json @@ -0,0 +1,7 @@ +{ + "layered-image": + { + "background" : "$media:background", + "foreground" : "$media:foreground" + } +} \ No newline at end of file diff --git a/ArkUI/build-profile.json5 b/ArkUI/build-profile.json5 new file mode 100644 index 0000000000000000000000000000000000000000..03ac3a3ae9dd397844173066e5d5ee21b49455a1 --- /dev/null +++ b/ArkUI/build-profile.json5 @@ -0,0 +1,41 @@ +{ + "app": { + "signingConfigs": [], + "products": [ + { + "name": "default", + "signingConfig": "default", + "compatibleSdkVersion": "5.0.4(16)", + "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/ArkUI/code-linter.json5 b/ArkUI/code-linter.json5 new file mode 100644 index 0000000000000000000000000000000000000000..073990fa45394e1f8e85d85418ee60a8953f9b99 --- /dev/null +++ b/ArkUI/code-linter.json5 @@ -0,0 +1,32 @@ +{ + "files": [ + "**/*.ets" + ], + "ignore": [ + "**/src/ohosTest/**/*", + "**/src/test/**/*", + "**/src/mock/**/*", + "**/node_modules/**/*", + "**/oh_modules/**/*", + "**/build/**/*", + "**/.preview/**/*" + ], + "ruleSet": [ + "plugin:@performance/recommended", + "plugin:@typescript-eslint/recommended" + ], + "rules": { + "@security/no-unsafe-aes": "error", + "@security/no-unsafe-hash": "error", + "@security/no-unsafe-mac": "warn", + "@security/no-unsafe-dh": "error", + "@security/no-unsafe-dsa": "error", + "@security/no-unsafe-ecdsa": "error", + "@security/no-unsafe-rsa-encrypt": "error", + "@security/no-unsafe-rsa-sign": "error", + "@security/no-unsafe-rsa-key": "error", + "@security/no-unsafe-dsa-key": "error", + "@security/no-unsafe-dh-key": "error", + "@security/no-unsafe-3des": "error" + } +} \ No newline at end of file diff --git a/ArkUI/entry/build-profile.json5 b/ArkUI/entry/build-profile.json5 new file mode 100644 index 0000000000000000000000000000000000000000..4d611879c7913fb0610c686e2399258ab3a6dad1 --- /dev/null +++ b/ArkUI/entry/build-profile.json5 @@ -0,0 +1,28 @@ +{ + "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/ArkUI/entry/hvigorfile.ts b/ArkUI/entry/hvigorfile.ts new file mode 100644 index 0000000000000000000000000000000000000000..7bf4382c4dab1ccf9f03093a9f510d1e238ac919 --- /dev/null +++ b/ArkUI/entry/hvigorfile.ts @@ -0,0 +1,6 @@ +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/ArkUI/entry/obfuscation-rules.txt b/ArkUI/entry/obfuscation-rules.txt new file mode 100644 index 0000000000000000000000000000000000000000..272efb6ca3f240859091bbbfc7c5802d52793b0b --- /dev/null +++ b/ArkUI/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/ArkUI/entry/oh-package.json5 b/ArkUI/entry/oh-package.json5 new file mode 100644 index 0000000000000000000000000000000000000000..248c3b7541a589682a250f86a6d3ecf7414d2d6a --- /dev/null +++ b/ArkUI/entry/oh-package.json5 @@ -0,0 +1,10 @@ +{ + "name": "entry", + "version": "1.0.0", + "description": "Please describe the basic information.", + "main": "", + "author": "", + "license": "", + "dependencies": {} +} + diff --git a/ArkUI/entry/src/main/ets/entryability/EntryAbility.ets b/ArkUI/entry/src/main/ets/entryability/EntryAbility.ets new file mode 100644 index 0000000000000000000000000000000000000000..508880af8c33aa838016d1cd4b2c68be2f447540 --- /dev/null +++ b/ArkUI/entry/src/main/ets/entryability/EntryAbility.ets @@ -0,0 +1,44 @@ +import { AbilityConstant, ConfigurationConstant, UIAbility, Want } from '@kit.AbilityKit'; +import { hilog } from '@kit.PerformanceAnalysisKit'; +import { window } from '@kit.ArkUI'; + +const DOMAIN = 0x0000; + +export default class EntryAbility extends UIAbility { + onCreate(want: Want, launchParam: AbilityConstant.LaunchParam): void { + this.context.getApplicationContext().setColorMode(ConfigurationConstant.ColorMode.COLOR_MODE_NOT_SET); + hilog.info(DOMAIN, 'testTag', '%{public}s', 'Ability onCreate'); + } + + onDestroy(): void { + hilog.info(DOMAIN, 'testTag', '%{public}s', 'Ability onDestroy'); + } + + onWindowStageCreate(windowStage: window.WindowStage): void { + // Main window is created, set main page for this ability + hilog.info(DOMAIN, 'testTag', '%{public}s', 'Ability onWindowStageCreate'); + + windowStage.loadContent('pages/Index', (err) => { + if (err.code) { + hilog.error(DOMAIN, 'testTag', 'Failed to load the content. Cause: %{public}s', JSON.stringify(err)); + return; + } + hilog.info(DOMAIN, 'testTag', 'Succeeded in loading the content.'); + }); + } + + onWindowStageDestroy(): void { + // Main window is destroyed, release UI related resources + hilog.info(DOMAIN, 'testTag', '%{public}s', 'Ability onWindowStageDestroy'); + } + + onForeground(): void { + // Ability has brought to foreground + hilog.info(DOMAIN, 'testTag', '%{public}s', 'Ability onForeground'); + } + + onBackground(): void { + // Ability has back to background + hilog.info(DOMAIN, 'testTag', '%{public}s', 'Ability onBackground'); + } +} \ No newline at end of file diff --git a/ArkUI/entry/src/main/ets/entrybackupability/EntryBackupAbility.ets b/ArkUI/entry/src/main/ets/entrybackupability/EntryBackupAbility.ets new file mode 100644 index 0000000000000000000000000000000000000000..8e4de99282050bad799ac892eb85ac5449364a51 --- /dev/null +++ b/ArkUI/entry/src/main/ets/entrybackupability/EntryBackupAbility.ets @@ -0,0 +1,16 @@ +import { hilog } from '@kit.PerformanceAnalysisKit'; +import { BackupExtensionAbility, BundleVersion } from '@kit.CoreFileKit'; + +const DOMAIN = 0x0000; + +export default class EntryBackupAbility extends BackupExtensionAbility { + async onBackup() { + hilog.info(DOMAIN, 'testTag', 'onBackup ok'); + await Promise.resolve(); + } + + async onRestore(bundleVersion: BundleVersion) { + hilog.info(DOMAIN, 'testTag', 'onRestore ok %{public}s', JSON.stringify(bundleVersion)); + await Promise.resolve(); + } +} \ No newline at end of file diff --git a/ArkUI/entry/src/main/ets/pages/AddComponentInTabbar.ets b/ArkUI/entry/src/main/ets/pages/AddComponentInTabbar.ets new file mode 100644 index 0000000000000000000000000000000000000000..530f370ae142fc995e21b4d7c2a01eeaf36edf10 --- /dev/null +++ b/ArkUI/entry/src/main/ets/pages/AddComponentInTabbar.ets @@ -0,0 +1,197 @@ +/* +* 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. +*/ + +/* +* FAQ:如何在Tabs的tabBar中添加其他组件 +*/ + +// DocsCode 1 +import { componentUtils } from '@kit.ArkUI'; + +@Entry +@Component +struct TabsDemo { + @State tabArray: Array = [0, 1, 2]; + @State tabArrayVal: number = this.tabArray.length - 1; + @State currentIndex: number = 0; + @State animationDuration: number = 300; + @State indicatorLeftMargin: number = 0; + @State indicatorWidth: number = 0; + private controller: TabsController = new TabsController(); + private tabsWidth: number = 0; + + // 单独的页签 + @Builder + tab(tabName: string, tabItem: number, tabIndex: number) { + Row({ space: 20 }) { + Text(tabName).fontSize(18) + .fontColor(tabItem === this.currentIndex ? Color.Red : Color.Black) + .id(tabIndex.toString()) + .onAreaChange((oldValue: Area, newValue: Area) => { + if (this.currentIndex === tabIndex && (this.indicatorLeftMargin === 0 || this.indicatorWidth === 0)) { + if (newValue.position.x !== undefined) { + let positionX = Number.parseFloat(newValue.position.x.toString()); + this.indicatorLeftMargin = Number.isNaN(positionX) ? 0 : positionX; + } + let width = Number.parseFloat(newValue.width.toString()); + this.indicatorWidth = Number.isNaN(width) ? 0 : width; + } + }) + } + .justifyContent(FlexAlign.Center) + .constraintSize({ minWidth: 35 }) + .width(80) + .height(35) + .borderRadius({ + topLeft: 10, + topRight: 10 + }) + .onClick(() => { + this.controller.changeIndex(tabIndex); + this.currentIndex = tabIndex; + }) + } + + build() { + Column() { + // 页签 + Stack({ alignContent: Alignment.TopStart }) { + Scroll() { + Row() { + ForEach(this.tabArray, (item: number, index: number) => { + this.tab('页签' + item, item, index); + }) + Text('+') + .width(36) + .height(50) + .fontSize(28) + .borderRadius(5) + .padding({ + left: 5, + bottom: 2 + }) + .onClick(() => { + this.tabArray.push(++this.tabArrayVal); + }) + } + .justifyContent(FlexAlign.SpaceBetween) + } + .align(Alignment.Start) + .scrollable(ScrollDirection.Horizontal) + .scrollBar(BarState.Off) + .width('100%') + + Column() + .width(this.indicatorWidth) + .height(2) + .backgroundColor(Color.Red) + .borderRadius(2) + .margin({ + left: this.indicatorLeftMargin, + top: 38 + }) + } + .width('100%') + + Tabs({ barPosition: BarPosition.Start, controller: this.controller }) { + ForEach(this.tabArray, (item: number, index: number) => { + TabContent() { + Text('我是页面' + item + '的内容') + .height(300) + .width('100%') + .fontSize(30) + .textAlign(TextAlign.Center) + } + .backgroundColor(Color.Pink) + }) + } + .onAreaChange((oldValue: Area, newValue: Area) => { + let width = Number.parseFloat(newValue.width.toString()); + this.tabsWidth = Number.isNaN(width) ? 0 : width; + }) + .barWidth('100%') + .barHeight(0) + .width('100%') + .height('100%') + .backgroundColor('#F1F3F5') + .animationDuration(this.animationDuration) + .onChange((index: number) => { + this.currentIndex = index; // 监听索引index的变化,实现页签内容的切换。 + }) + .onAnimationStart((index: number, targetIndex: number, event: TabsAnimationEvent) => { + // 切换动画开始时触发该回调。下划线跟着页面一起滑动,同时宽度渐变。 + this.currentIndex = targetIndex; + let targetIndexInfo = this.getTextInfo(targetIndex); + this.startAnimateTo(this.animationDuration, targetIndexInfo.left, targetIndexInfo.width); + }) + .onAnimationEnd((index: number, event: TabsAnimationEvent) => { + // 切换动画结束时触发该回调。下划线动画停止。 + let currentIndicatorInfo = this.getCurrentIndicatorInfo(index, event); + this.startAnimateTo(0, currentIndicatorInfo.left, currentIndicatorInfo.width); + }) + .onGestureSwipe((index: number, event: TabsAnimationEvent) => { + // 在页面跟手滑动过程中,逐帧触发该回调。 + let currentIndicatorInfo = this.getCurrentIndicatorInfo(index, event); + this.currentIndex = currentIndicatorInfo.index; + this.indicatorLeftMargin = currentIndicatorInfo.left; + this.indicatorWidth = currentIndicatorInfo.width; + }) + } + .height('100%') + } + + // 获取组件大小、位置、平移缩放旋转及仿射矩阵属性信息。 + private getTextInfo(index: number): Record { + let modePosition: componentUtils.ComponentInfo = componentUtils.getRectangleById(index.toString()); + return { 'left': this.getUIContext().px2vp(modePosition.windowOffset.x), 'width': this.getUIContext().px2vp(modePosition.size.width) }; + } + + private getCurrentIndicatorInfo(index: number, event: TabsAnimationEvent): Record { + let nextIndex = index; + if (index > 0 && event.currentOffset > 0) { + nextIndex--; + } else if (index < 3 && event.currentOffset < 0) { + nextIndex++; + } + let indexInfo = this.getTextInfo(index); + let nextIndexInfo = this.getTextInfo(nextIndex); + let swipeRatio = Math.abs(event.currentOffset / this.tabsWidth); + // 页面滑动超过一半,tabBar切换到下一页。 + let currentIndex = swipeRatio > 0.5 ? nextIndex : index; + let currentLeft = indexInfo.left + (nextIndexInfo.left - indexInfo.left) * swipeRatio; + let currentWidth = indexInfo.width + (nextIndexInfo.width - indexInfo.width) * swipeRatio; + return { 'index': currentIndex, 'left': currentLeft, 'width': currentWidth }; + } + + private startAnimateTo(duration: number, leftMargin: number, width: number) { + animateTo({ + // 动画时长 + duration: duration, + // 动画曲线 + curve: Curve.Linear, + // 播放次数 + iterations: 1, + // 动画模式 + playMode: PlayMode.Normal, + onFinish: () => { + console.info('play end'); + } + }, () => { + this.indicatorLeftMargin = leftMargin; + this.indicatorWidth = width; + }) + } +} +// DocsCode 1 \ No newline at end of file diff --git a/ArkUI/entry/src/main/ets/pages/AvoidAreaHeight.ets b/ArkUI/entry/src/main/ets/pages/AvoidAreaHeight.ets new file mode 100644 index 0000000000000000000000000000000000000000..5e5b7334f3269441ed0fe7833574f6438906e4fe --- /dev/null +++ b/ArkUI/entry/src/main/ets/pages/AvoidAreaHeight.ets @@ -0,0 +1,56 @@ +/* +* 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. +*/ + +/* +* FAQ:如何获取屏幕顶部状态栏、底部导航栏和导航条的高度 +*/ + +// DocsCode 1 +import { window } from '@kit.ArkUI'; +import { BusinessError } from '@kit.BasicServicesKit'; + +@Entry +@Component +struct GetAvoidAreaHeight { + context = this.getUIContext(); + + build() { + Column() { + Button('GetAvoidAreaHeight') + .onClick(() => { + let type1 = window.AvoidAreaType.TYPE_SYSTEM; + let type2 = window.AvoidAreaType.TYPE_NAVIGATION_INDICATOR; + window.getLastWindow(this.context.getHostContext()).then((data) => { + // 获取系统默认区域,一般包括状态栏、导航栏 + let avoidArea1 = data.getWindowAvoidArea(type1); + // 顶部状态栏高度 + let statusBarHeight = avoidArea1.topRect.height; + // 底部导航栏高度 + let bottomNavHeight = avoidArea1.bottomRect.height; + // 获取导航条区域 + let avoidArea2 = data.getWindowAvoidArea(type2); + // 获取到导航条区域的高度 + let indicatorHeight = avoidArea2.bottomRect.height; + console.info(`statusBarHeight is ${statusBarHeight}`); + console.info(`bottomNavHeight is ${bottomNavHeight}`); + console.info(`indicatorHeight is ${indicatorHeight}`); + }).catch((err: BusinessError) => { + console.error(`Failed to obtain the window. Cause: ${JSON.stringify(err)}`); + }); + }) + } + } +} +// DocsCode 1 \ No newline at end of file diff --git a/ArkUI/entry/src/main/ets/pages/BottomNavBarHeight.ets b/ArkUI/entry/src/main/ets/pages/BottomNavBarHeight.ets new file mode 100644 index 0000000000000000000000000000000000000000..802349bb96e4a74844bc87c61d269d3ab43ccd3e --- /dev/null +++ b/ArkUI/entry/src/main/ets/pages/BottomNavBarHeight.ets @@ -0,0 +1,47 @@ +/* +* 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. +*/ + +/* +* FAQ:如何获取底部手势横条的高度 +*/ + +// DocsCode 1 + +import { window } from '@kit.ArkUI'; +import { BusinessError } from '@kit.BasicServicesKit'; + +@Entry +@Component +struct GetBottomNavBarHeight { + context = this.getUIContext(); + + build() { + Column() { + Button('获取底部手势横条的高度') + .onClick(() => { + let type = window.AvoidAreaType.TYPE_NAVIGATION_INDICATOR; + window.getLastWindow(this.context.getHostContext()).then((data) => { + let avoidArea = data.getWindowAvoidArea(type); + // 获取到导航条区域的高度 + let bottomRectHeight = avoidArea.bottomRect.height; + console.info(`window bottomRectHeight is: ${bottomRectHeight}`); + }).catch((err: BusinessError) => { + console.error(`Failed to obtain the window. Cause: ${JSON.stringify(err)}`); + }); + }) + } + } +} +// DocsCode 1 \ No newline at end of file diff --git a/ArkUI/entry/src/main/ets/pages/BottomPopsUpAsTheTopOfKeyboard.ets b/ArkUI/entry/src/main/ets/pages/BottomPopsUpAsTheTopOfKeyboard.ets new file mode 100644 index 0000000000000000000000000000000000000000..3e51055e380dbe149a5255aaabb6398861518383 --- /dev/null +++ b/ArkUI/entry/src/main/ets/pages/BottomPopsUpAsTheTopOfKeyboard.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. +*/ + +/* +* FAQ:输入框拉起键盘时,如何将底部布局弹起到键盘顶部 +*/ + +// DocsCode 1 +import { window } from '@kit.ArkUI'; + +@Entry +struct BottomPopsUpAsTheTopOfKeyboard { + context = this.getUIContext(); + scroller: Scroller = new Scroller(); + private arr: number[] = [0, 1, 2, 3, 4, 5]; + @State scrollHeight: number = 0; + @State isRebuild: boolean = false; + @State keyHeight: number = 0; + @State text: string = ''; + aboutToAppear() { + window.getLastWindow(this.context.getHostContext()).then(currentWindow => { + // 设置窗口的布局为沉浸式布局 + currentWindow.setWindowLayoutFullScreen(true); + let property = currentWindow.getWindowProperties(); + // 初始化窗口高度 + let avoidArea = currentWindow.getWindowAvoidArea(window.AvoidAreaType.TYPE_KEYBOARD); + this.scrollHeight = px2vp(property.windowRect.height - avoidArea.bottomRect.height); + // 监听软键盘的隐藏和显示 + currentWindow.on('avoidAreaChange', data => { + if (data.type == window.AvoidAreaType.TYPE_KEYBOARD) { + this.keyHeight = px2vp(data.area.bottomRect.height); + this.scrollHeight = + px2vp(currentWindow.getWindowProperties().windowRect.height - data.area.bottomRect.height); + return; + } + }) + }) + } + build() { + Stack({ alignContent: Alignment.TopStart }) { + Column() { + Scroll(this.scroller) { + Column() { + TextInput({ text: this.text, placeholder: 'input your word...' }) + .placeholderFont({ + size: 14, + weight: 400 + }) + .width(320) + .height(40) + .margin(200) + .fontSize(14) + .fontColor(Color.Black) + .backgroundColor(Color.White) + ForEach(this.arr, (item: number) => { + Text(item.toString()) + .width('90%') + .height(150) + .backgroundColor(0xFFFFFF) + .borderRadius(15) + .fontSize(16) + .textAlign(TextAlign.Center) + .margin({ top: 10 }) + }) + } + .width('100%') + } + .width('100%') + .height(this.scrollHeight) + .layoutWeight(1) + Text('这是一个测试文本') + .width('100%') + .height(50) + .backgroundColor(Color.Red) + .margin({ bottom: this.keyHeight }) + } + .width('100%') + .height('100%') + .justifyContent(FlexAlign.Start) + } + .width('100%') + .height('100%') + .backgroundColor(0xDCDCDC) + } +} +// DocsCode 1 \ No newline at end of file diff --git a/ArkUI/entry/src/main/ets/pages/BottomSlideAndOut.ets b/ArkUI/entry/src/main/ets/pages/BottomSlideAndOut.ets new file mode 100644 index 0000000000000000000000000000000000000000..dffdc8b352854701346e29299b2c0f2713d0eee8 --- /dev/null +++ b/ArkUI/entry/src/main/ets/pages/BottomSlideAndOut.ets @@ -0,0 +1,75 @@ +/* +* 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. +*/ + +/* +* FAQ:自定义组件间如何实现从底部滑入滑出的效果 +*/ + +// DocsCode 1 +@Entry +@Component +struct ComponentTransition { + @State flag: boolean = true; + + build() { + Stack({ alignContent: Alignment.Bottom }) { + if (this.flag) { + ComponentChild1({ flag: $flag }) + .transition({ type: TransitionType.Insert,translate: { x: 0, y: 200 } }) + } + if (!this.flag) { + ComponentChild2({ flag: $flag }) + .transition({ type: TransitionType.Insert, translate: { x: 0, y: 200 } }) + } + }.height('100%').width('100%') + } +} + +@Component +struct ComponentChild1 { + @Link flag: boolean + + build() { + Column() { + Image($r('app.media.ic_banner01'))//resources\base\media路径 + .width('100%') + .height(200) + .onClick(() => { + this.getUIContext().animateTo({ duration: 1000 }, () => { + this.flag = !this.flag; + }) + }) + } + } +} + +@Component +struct ComponentChild2 { + @Link flag: boolean + + build() { + Column() { + Image($r('app.media.ic_banner02'))//resources\base\media路径 + .width('100%') + .height(200) + .onClick(() => { + this.getUIContext().animateTo({ duration: 1000 }, () => { + this.flag = !this.flag; + }) + }) + } + } +} +// DocsCode 1 \ No newline at end of file diff --git a/ArkUI/entry/src/main/ets/pages/ControlLevelOfCustomDialog.ets b/ArkUI/entry/src/main/ets/pages/ControlLevelOfCustomDialog.ets new file mode 100644 index 0000000000000000000000000000000000000000..fb27722af6eecd5f2ae29f48d9cae8ba964a2ee4 --- /dev/null +++ b/ArkUI/entry/src/main/ets/pages/ControlLevelOfCustomDialog.ets @@ -0,0 +1,176 @@ +/* +* 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. +*/ + +/* +* FAQ:如何控制CustomDialog显示层级 +*/ + +// DocsCode 1 +@Component +struct Test1 { + @State message: string = 'Hello World'; + + build() { + NavDestination() { + Row() { + Column() { + Text(this.message) + .fontSize(50) + .fontWeight(FontWeight.Bold) + } + .width('100%') + } + .height('100%') + } + .onBackPressed(() => { + this.getUIContext().getPromptAction().showToast({ message: '123' }); + return false; + }) + } +} + +@Entry +@Component +struct CustomDialogDisplayLevel { + @Provide('pageInfos') pageInfos: NavPathStack = new NavPathStack(); + @State textValue: string = '输入'; + // 显隐控制设置为不占用 + @State visible: Visibility = Visibility.None; + + @Builder + pageMap(name: string) { + if (name === 'pageOne') { + Test1() + } + } + + build() { + Navigation(this.pageInfos) { + Column() { + Stack() { + Row() { + Column() { + Text('我是第一个页面') + .fontSize(30) + .fontWeight(FontWeight.Bold) + Button('按钮') + .onClick(() => { + console.info('hit me!'); + if (this.visible === Visibility.Visible) { + this.visible = Visibility.None; + } else { + this.visible = Visibility.Visible; + } + }) + .backgroundColor(0x777474) + .fontColor(0x000000) + } + .height('100%') + .width('100%') + .justifyContent(FlexAlign.Start) + .alignItems(HorizontalAlign.Center) + } + .height('100%') + .backgroundColor('#FFF') + + Text('') + .onClick(() => { + if (this.visible === Visibility.Visible) { + this.visible = Visibility.None; + } else { + this.visible = Visibility.Visible; + } + }) + .width('100%') + .height('100%') + // 透明度可以自己调节一下 + .opacity(0.5) + .backgroundColor(Color.Black) + .visibility(this.visible) + Column() { + GridRow({ + columns: { + xs: 1, + sm: 4, + md: 8, + lg: 12 + }, + breakpoints: { + value: ['400vp', '600vp', '800vp'], + reference: BreakpointsReference.WindowSize + }, + }) { + GridCol({ + span: { + xs: 1, + sm: 2, + md: 4, + lg: 8 + }, + offset: { + xs: 0, + sm: 1, + md: 2, + lg: 2 + } + }) { + Column() { + Text('安全隐私') + .fontSize(20) + .margin({ + top: 10, + bottom: 10 + }) + Text('是否跳转到隐私详情页面?') + .fontSize(16) + .margin({ bottom: 10 }) + Flex({ justifyContent: FlexAlign.SpaceAround }) { + Button('取消') + .onClick(() => { + if (this.visible === Visibility.Visible) { + this.visible = Visibility.None; + } else { + this.visible = Visibility.Visible; + } + }) + .backgroundColor(0xffffff) + .fontColor(Color.Black) + Button('确定') + .onClick(() => { + this.pageInfos.pushPath({ name: 'pageOne' }); + }) + .backgroundColor(0xffffff) + .fontColor(Color.Red) + } + .margin({ bottom: 10 }) + } + .backgroundColor(0xffffff) + .visibility(this.visible) + .clip(true) + .borderRadius(20) + } + } + } + //设置弹窗宽度 + .width('100%') + } + } + .width('100%') + .margin({ top: 5 }) + } + .navDestination(this.pageMap) + } +} +// DocsCode 1 \ No newline at end of file diff --git a/ArkUI/entry/src/main/ets/pages/CopyContentDirectlyClipboard.ets b/ArkUI/entry/src/main/ets/pages/CopyContentDirectlyClipboard.ets new file mode 100644 index 0000000000000000000000000000000000000000..35d966b2293018309b89a228eb766e8488e5cca1 --- /dev/null +++ b/ArkUI/entry/src/main/ets/pages/CopyContentDirectlyClipboard.ets @@ -0,0 +1,65 @@ +/* +* 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. +*/ + +/* +* FAQ:如何将内容直接复制到剪贴板 +*/ + +// DocsCode 1 +import { pasteboard } from '@kit.BasicServicesKit'; + +@Entry +@Component +struct CopyText { + private textContent: string = '复制我'; + + build() { + Column() { + Text(this.textContent) + .fontSize(20) + .borderRadius(9) + .borderWidth(1) + .padding({ + left: 8, + right: 8 + }) + .fontColor($r('sys.color.ohos_id_color_text_primary')) + .fontWeight(FontWeight.Medium) + .opacity($r('sys.float.ohos_id_alpha_content_secondary')) + .onClick(() => copyText(this.textContent)) + } + .width('100%') + .height('100%') + .justifyContent(FlexAlign.Center) + .alignSelf(ItemAlign.Center) + } +} + +// 定义方法 +function copyText(text: string) { + // 创建剪贴板内容对象 + const pasteboardData = pasteboard.createData(pasteboard.MIMETYPE_TEXT_PLAIN, text); + // 获取系统剪贴板对象 + const systemPasteboard = pasteboard.getSystemPasteboard(); + systemPasteboard.setData(pasteboardData); // 将数据放入剪贴板 + systemPasteboard.getData().then((data) => { // 读取剪贴板内容 + if (data) { + this.getUIContext().getPromptAction().showToast({ message: '复制成功' }); + } else { + this.getUIContext().getPromptAction().showToast({ message: '复制失败' }); + } + }) +} +// DocsCode 1 \ No newline at end of file diff --git a/ArkUI/entry/src/main/ets/pages/CustomDialogVariableToPage.ets b/ArkUI/entry/src/main/ets/pages/CustomDialogVariableToPage.ets new file mode 100644 index 0000000000000000000000000000000000000000..15cc7dedd2b15c0f8cf2baa58a8d9e2614944c7b --- /dev/null +++ b/ArkUI/entry/src/main/ets/pages/CustomDialogVariableToPage.ets @@ -0,0 +1,157 @@ +/* +* 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. +*/ + +/* +* FAQ:自定义弹窗中的变量如何传递给页面 +*/ + +// DocsCode 1 +@CustomDialog +struct CustomDialog01 { + @Link inputValue: string; + controller: CustomDialogController; + + build() { + Column() { + Text('Change text') + .fontSize(20) + .margin({ top: 10, bottom: 10 }) + TextInput({ placeholder: '', text: this.inputValue }) + .height(60) + .width('90%') + .onChange((value: string) => { + this.inputValue = value; + }) + } + } +} + +@Entry +@Component +struct DialogDemo01 { + @State inputValue: string = 'click me'; + dialogController: CustomDialogController = new CustomDialogController({ + builder: CustomDialog01({ + inputValue: $inputValue + }) + }) + + build() { + Column() { + Button(this.inputValue) + .onClick(() => { + this.dialogController.open(); + }) + .backgroundColor(0x317aff) + } + .width('100%') + .margin({ top: 5 }) + } +} +// DocsCode 1 + +// DocsCode 2 +@CustomDialog +struct CustomDialog02 { + private inputValue: string = ''; + changeInputValue: (val: string) => void = () => { + }; + controller: CustomDialogController; + + build() { + Column() { + Text('Change text') + .fontSize(20) + .margin({ top: 10, bottom: 10 }) + TextInput({ placeholder: '', text: this.inputValue }) + .height(60) + .width('90%') + .onChange((value: string) => { + this.changeInputValue(value); + }) + } + } +} + +@Entry +@Component +struct DialogDemo02 { + @State inputValue: string = 'click me'; + dialogController: CustomDialogController = new CustomDialogController({ + builder: CustomDialog02({ + inputValue: this.inputValue, + changeInputValue: (val: string) => { + this.inputValue = val; + } + }) + }) + + build() { + Column() { + Button(this.inputValue) + .onClick(() => { + this.dialogController.open(); + }) + .backgroundColor(0x317aff) + } + .width('100%') + .margin({ top: 5 }) + } +} +// DocsCode 2 + +// DocsCode 3 +let storage = LocalStorage.getShared(); +@CustomDialog +struct CustomDialog03 { + @LocalStorageLink('inputVal') inputValue: string = ''; + controller: CustomDialogController; + + build() { + Column() { + Text('Change text') + .fontSize(20) + .margin({ top: 10, bottom: 10 }) + TextInput({ placeholder: '', text: this.inputValue }) + .height(60) + .width('90%') + .onChange((value: string) => { + this.inputValue = value; + }) + } + } +} + +@Entry(storage) +@Component +struct DialogDemo03 { + @LocalStorageLink('inputVal') inputValue: string = 'click me'; + dialogController: CustomDialogController = new CustomDialogController({ + builder: CustomDialog03() + }); + + build() { + Column() { + Button(this.inputValue) + .onClick(() => { + this.dialogController.open(); + }) + .backgroundColor(0x317aff) + } + .width('100%') + .margin({ top: 5 }) + } +} +// DocsCode 3 \ No newline at end of file diff --git a/ArkUI/entry/src/main/ets/pages/ExcavationScreenAdaptation.ets b/ArkUI/entry/src/main/ets/pages/ExcavationScreenAdaptation.ets new file mode 100644 index 0000000000000000000000000000000000000000..dd3c105a7b08674612350e069a20df5b9ee7b586 --- /dev/null +++ b/ArkUI/entry/src/main/ets/pages/ExcavationScreenAdaptation.ets @@ -0,0 +1,158 @@ +/* +* 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. +*/ + +/* +* FAQ:如何完成挖孔屏的适配 +*/ + +// DocsCode 1 +onWindowStageCreate(windowStage: window.WindowStage): void { + AppStorage.setOrCreate('context', windowStage); + windowStage.getMainWindow((err: BusinessError, data) => { + let errCode: number = err.code; + // 设置窗口为全屏显示状态 + data.setWindowLayoutFullScreen(true); + // 设置顶部状态栏为隐藏状态 + let names: Array<'status' | 'navigation'> = []; + data.setWindowSystemBarEnable(names, (err: BusinessError) => { + if (err.code) { + console.error('Failed to set the system bar to be visible. Cause:' + JSON.stringify(err)); + return; + } + console.info('Succeeded in setting the system bar to be visible.'); + }); + }) + // ... +} +// DocsCode 1 + +// DocsCode 2 +import { display, window } from '@kit.ArkUI'; +import { common } from '@kit.AbilityKit'; +import { batteryInfo } from '@kit.BasicServicesKit'; + +class TextMargin { + left: number = 0; // 状态栏左偏移量 + right: number = 0; // 状态栏右偏移量 +} + +@Entry +@Component +struct Index { + @State date: Date = new Date(); + @State currentTime: string = ''; // 顶部状态栏时间 + @State boundingRect: display.Rect[] = []; // 不可用区域数据 + @State screenWidth: number = 0; // 屏幕宽度 + @State displayClass: display.Display | null = null; + @State topTextMargin: TextMargin = { left: 0, right: 0 }; // 顶部状态栏偏移量 + @StorageLink('context') context: common.UIAbilityContext | undefined = + AppStorage.get('context'); // 获取UIAbilityContext + + aboutToAppear(): void { + this.displayClass = display.getDefaultDisplaySync(); + display.getDefaultDisplaySync().getCutoutInfo((err, data) => { + if (err.code !== 0) { + console.log('getCutoutInfo failed. error is:', JSON.stringify(err)); + return; + } + this.boundingRect = data.boundingRects; + this.topTextMargin = this.getBoundingRectPosition(); + }) + // 获取小时 + let hours = this.date.getHours(); + // 获取分钟 + let minutes = this.date.getMinutes(); + // 分钟小于10在前面加0 + this.currentTime = hours.toString() + ':' + (minutes < 10 ? '0' + minutes : minutes.toString()); + } + + // 退出当前页面时将窗口重新设置成初始状态 + aboutToDisappear() { + if (this.context !== undefined) { + window.getLastWindow(this.context, async (err, data) => { + if (err.code !== 0) { + console.log('getLastWindow failed. error is:', JSON.stringify(err)); + data.setWindowSystemBarEnable(['status', 'navigation']); + data.setWindowLayoutFullScreen(false); + } + }) + } + } + + getBoundingRectPosition(): TextMargin { + if (this.boundingRect !== null && this.displayClass !== null && this.boundingRect[0] !== undefined) { + // 不可用区域右侧到屏幕右边界的距离:屏幕宽度减去左侧宽度和不可用区域宽度 + let boundingRectRight: number = + this.displayClass.width - (this.boundingRect[0].left + this.boundingRect[0].width); + // 不可用区域左侧到屏幕左边界的距离:getCutoutInfo接口可以直接获取 + let boundingRectLeft: number = this.boundingRect[0].left; + // 部分设备不可用区域在中间时存在左右距离会有10像素以内的差距,获取到的左右距离差值绝对值小于10都按照不可用区域位于中间处理 + if (Math.abs(boundingRectLeft - boundingRectRight) <= 10) { + return { left: 0, right: 0 }; + } + if (boundingRectLeft > boundingRectRight) { + // 不可用区域在右边 + return { left: 0, right: this.displayClass.width - boundingRectLeft }; + } else if (boundingRectLeft < boundingRectRight) { + // 不可用区域在左边 + return { left: this.boundingRect[0].left + this.boundingRect[0].width, right: 0 }; + } + } + return { left: 0, right: 0 }; + } + + build() { + Stack() { + Image($r('app.media.digging_hole_screen_2048game')) + .objectFit(ImageFit.Fill) + .width('100%') + .height('100%') + .onClick(() => { + this.getUIContext().getPromptAction().showToast({ + message: '该功能暂未开发', + duration: 2000 + }) + }) + Column() { + Flex({ direction: FlexDirection.Row, justifyContent: FlexAlign.SpaceBetween }) { + Text(this.currentTime) // 时间 + .fontSize(16) + .fontColor(Color.Black) + .fontWeight(FontWeight.Regular) + .padding({ left: 12 }) + .margin({ + left: this.getUIContext().px2vp(this.topTextMargin.left), + top: 14 + }) // 获取的偏移量单位为px需要进行转换 + Text(batteryInfo.batterySOC.toString() + '%')// 电池电量 + .fontSize(16) + .fontColor(Color.Black) + .fontWeight(FontWeight.Regular) + .padding({ right: 16 }) + .margin({ + right: this.getUIContext().px2vp(this.topTextMargin.right), + top: 14 + }) // 获取的偏移量单位为px需要进行转换 + } + .width('100%') + } + .width('100%') + } + .width('100%') + .height('100%') + .alignContent(Alignment.TopStart) + } +} +// DocsCode 2 \ No newline at end of file diff --git a/ArkUI/entry/src/main/ets/pages/FontSetting.ets b/ArkUI/entry/src/main/ets/pages/FontSetting.ets new file mode 100644 index 0000000000000000000000000000000000000000..46af49f7cbce0d7fb6205b2dd34a3ad4ebd4fc65 --- /dev/null +++ b/ArkUI/entry/src/main/ets/pages/FontSetting.ets @@ -0,0 +1,44 @@ +/* +* 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. +*/ + +/* +* FAQ:如何设置Text的字体,可以不受系统设置里显示字体大小的影响 +*/ + +// DocsCode 1 +@Entry +@Component +struct CustomDialogDisplayLevel { + @State message: string = 'hello world'; + + build() { + Column() { + Text(this.message) + .fontSize(53) // 默认单位为fp,会跟随系统显示大小变化 + Text(this.message) + .fontSize(this.getUIContext().px2fp(160) + 'px') // 使用像素单位,不会跟随系统显示大小变化 + Blank() + .color(0xff0000) + .height(30) + .width(226) + .margin({ bottom: 20 }) // 默认单位 vp会跟随系统显示大小变化 + Blank() + .color(0xff0000) + .height(30 + 'px') + .width(this.getUIContext().px2vp(672) + 'px') // 使用像素单位,不会跟随系统显示大小变化 + } + } +} +// DocsCode 1 \ No newline at end of file diff --git a/ArkUI/entry/src/main/ets/pages/FullNavigationSubcomponent.ets b/ArkUI/entry/src/main/ets/pages/FullNavigationSubcomponent.ets new file mode 100644 index 0000000000000000000000000000000000000000..e19a6ff3eec55d627e209511a62b6f919a2b5720 --- /dev/null +++ b/ArkUI/entry/src/main/ets/pages/FullNavigationSubcomponent.ets @@ -0,0 +1,49 @@ +/* +* 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. +*/ + +/* +* FAQ:Navigation容器中,如何设置子组件的高度为100%,撑满父容器 +*/ + +// DocsCode 1 +import { window } from '@kit.ArkUI'; + +@Entry +@Component +struct FullNavigationSubcomponent { + context = this.getUIContext(); + + onPageShow(): void { + window.getLastWindow(this.context.getHostContext(), (err, win) => { + win.setWindowLayoutFullScreen(true); + }) + } + + build() { + Navigation() { + Column() { + } + .width('100%') + .height('100%') + .backgroundColor(Color.Black) + } + .width('100%') + .height('100%') + .title('个性化设置') + .titleMode(NavigationTitleMode.Mini) + .backgroundColor(Color.Grey) + } +} +// DocsCode 1 \ No newline at end of file diff --git a/ArkUI/entry/src/main/ets/pages/GetAppInformation.ets b/ArkUI/entry/src/main/ets/pages/GetAppInformation.ets new file mode 100644 index 0000000000000000000000000000000000000000..4ce18e94d4aa91cf1286a43702ce14660b4276ac --- /dev/null +++ b/ArkUI/entry/src/main/ets/pages/GetAppInformation.ets @@ -0,0 +1,39 @@ +/* +* 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. +*/ + +/* +* FAQ:如何获取App版本号,版本名,屏幕分辨率等信息 +*/ + +// DocsCode 1 +import { BusinessError } from '@kit.BasicServicesKit'; +import { bundleManager } from '@kit.AbilityKit'; +// ... +bundleManager.getBundleInfoForSelf(bundleManager.BundleFlag.GET_BUNDLE_INFO_WITH_APPLICATION).then((bundleInfo)=>{ + let versionName = bundleInfo.versionName;//应用版本名 + let versionNo = bundleInfo.versionCode;//应用版本号 +}).catch((error: BusinessError )=>{ + console.error("get bundleInfo failed,error is "+error) +}) +// DocsCode 1 + +// DocsCode 2 +import { common } from '@kit.AbilityKit'; +// ... +context = this.getUIContext(); + +let context = this.context.getHostContext() as common.UIAbilityContext; +let screenDensity = context.config.screenDensity; +// DocsCode 2 diff --git a/ArkUI/entry/src/main/ets/pages/GetComponentRenderingTime.ets b/ArkUI/entry/src/main/ets/pages/GetComponentRenderingTime.ets new file mode 100644 index 0000000000000000000000000000000000000000..632ddf74d34ab65a7668a3bf9754b30a133a004a --- /dev/null +++ b/ArkUI/entry/src/main/ets/pages/GetComponentRenderingTime.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. +*/ + +/* +* FAQ:如何获取组件渲染完成时间 +*/ + +// DocsCode 1 +import { inspector } from '@kit.ArkUI'; + +@Entry +@Component +struct GetComponentRenderTime { + @State startTime: number = 0; + private listener: inspector.ComponentObserver = this.getUIContext().getUIInspector().createComponentObserver('IMAGE_ID'); + private onDrawComplete = () => { + // 2.图片组件绘制完成的时间 + console.info('onDrawComplete', new Date().getTime()); + }; + + aboutToAppear() { + // 1.渲染开始的时间 + this.startTime = new Date().getTime(); + console.info('aboutToAppear', this.startTime); + + // layout: 组件布局完成 + // draw: 组件绘制完成 + this.listener.on('draw', this.onDrawComplete); + } + + aboutToDisappear() { + // 销毁之前取消注册回调 + this.listener.off('draw', this.onDrawComplete); + } + + build() { + Column() { + Flex({ direction: FlexDirection.Column, alignItems: ItemAlign.Start }) { + Row({ space: 5 }) { + Image($r('app.media.app_icon')) + .width(110) + .height(110) + .id('IMAGE_ID') + } + } + } + .height(320) + .width(360) + .padding({ + right: 10, + top: 10 + }) + } +} +// DocsCode 1 \ No newline at end of file diff --git a/ArkUI/entry/src/main/ets/pages/GetCoordinatesFromTouchPoint.ets b/ArkUI/entry/src/main/ets/pages/GetCoordinatesFromTouchPoint.ets new file mode 100644 index 0000000000000000000000000000000000000000..d8540b111863f1c34e8cb3c54c24309c17e12455 --- /dev/null +++ b/ArkUI/entry/src/main/ets/pages/GetCoordinatesFromTouchPoint.ets @@ -0,0 +1,97 @@ +/* +* 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. +*/ + +/* +* FAQ:如何在长按手势回调方法里获取手指触摸点的坐标 +*/ + +// DocsCode 1 +@Component +struct CoordinatesOfTheFingerTouchPoint { + @State count: number = 0; + private touchAreaRight: number = 0; + private touchAreaBottom: number = 0; + @State positionX: number = 0; + @State positionY: number = 0; + @State gestureEventInfo: string = ''; + + build() { + Column() { + Row() { + Column() { + Text('+') + .fontSize(28) + .position({ x: this.positionX, y: this.positionY }) + } + .height(200) + .width('100%') + .backgroundColor('#F1F3F5') + .onAreaChange((oldValue: Area, newValue: Area) => { + this.touchAreaRight = newValue.width as number; + this.touchAreaBottom = newValue.height as number; + }) + .gesture( + // 以下组合手势为顺序识别,当长按手势事件未正常触发时则不会触发拖动手势事件 + GestureGroup(GestureMode.Sequence, + LongPressGesture({ repeat: true }) + .onAction((event: GestureEvent) => { + if (event.repeat) { + this.count++; + } + }), + PanGesture() + .onActionStart(() => { + this.getUIContext().getPromptAction().showToast({ message: 'Pan start', duration: 1000 }); + }) + .onActionUpdate((event: GestureEvent) => { + for (let i = 0; i < event.fingerList.length; i++) { + if (event.fingerList[i] == undefined + || event.fingerList[i].localX < 0 + || event.fingerList[i].localY < 0 + || event.fingerList[i].localX > this.touchAreaRight + || event.fingerList[i].localY > this.touchAreaBottom) { + return; + } + this.positionX = event.fingerList[i].localX; + this.positionY = event.fingerList[i].localY; + } + this.gestureEventInfo = 'sequence gesture\n' + 'LongPress onAction' + this.count + + '\nX:' + this.positionX + '\nY:' + this.positionY; + }) + .onActionEnd(() => { + this.getUIContext().getPromptAction().showToast({ message: 'Pan end', duration: 1000 }); + }) + ) + .onCancel(() => { + this.getUIContext().getPromptAction().showToast({ message: '取消', duration: 1000 }); + }) + ) + } + .padding(12) + .borderRadius(24) + .backgroundColor(Color.White) + + Text(this.gestureEventInfo) + .fontSize(18) + .width('100%') + .textAlign(TextAlign.Start) + .padding({ left: 18, top: 30 }) + } + .height('100%') + .width('100%') + .backgroundColor('#F1F3F5') + } +} +// DocsCode 1 \ No newline at end of file diff --git a/ArkUI/entry/src/main/ets/pages/GetDarkModeColorSync.ets b/ArkUI/entry/src/main/ets/pages/GetDarkModeColorSync.ets new file mode 100644 index 0000000000000000000000000000000000000000..660648f0639428d153aa9f7a29ddc68f6c6dec62 --- /dev/null +++ b/ArkUI/entry/src/main/ets/pages/GetDarkModeColorSync.ets @@ -0,0 +1,31 @@ +/* +* 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. +*/ + +/* +* FAQ:如何在系统深色模式下使用getColorSync(resource)返回深色颜色值 +*/ + +// DocsCode 1 +this.getUIContext().getHostContext()!.resourceManager.getColorSync($r('app.color.xxx').id); +// DocsCode 1 + +// DocsCode 2 +"metadata": [ + { + "name": "ContextResourceConfigLoadFromParentTemp", + "value": "true" + } +] +// DocsCode 2 \ No newline at end of file diff --git a/ArkUI/entry/src/main/ets/pages/GetHorizontalAndVerticalScreenStatus.ets b/ArkUI/entry/src/main/ets/pages/GetHorizontalAndVerticalScreenStatus.ets new file mode 100644 index 0000000000000000000000000000000000000000..540bb6d40fc7136899553d2bf90958278f2b69a7 --- /dev/null +++ b/ArkUI/entry/src/main/ets/pages/GetHorizontalAndVerticalScreenStatus.ets @@ -0,0 +1,87 @@ +/* +* 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. +*/ + +/* +* FAQ:如何获取设备屏幕横竖屏状态 +*/ + +// DocsCode 1 +import { mediaquery, UIContext } from '@kit.ArkUI'; + +// 在 EntryAbility 中存储 context +const context = AppStorage.get("context") as UIContext; +let listener = context.getMediaQuery().matchMediaSync('(orientation: landscape)'); //监听横屏事件 +function onPortrait(mediaQueryResult: mediaquery.MediaQueryResult) { + console.info('mediaQueryResult.matches:' + mediaQueryResult.matches) + if (mediaQueryResult.matches) { + // do something here + } else { + // do something here + } +} +listener.on('change', onPortrait) // 注册回调 +listener.off('change', onPortrait) // 取消注册回调 + +@Entry +@Component +struct Index { + build() { + Column() { + Column() { + Text('test') + } + .width('100%') + } + .height('100%') + .width('100%') + .justifyContent(FlexAlign.End) + } +} +// DocsCode 1 + +// DocsCode 2 +import { display, window } from '@kit.ArkUI'; + +@Entry +@Component +struct windowRotation { + build() { + Text("Scroll Area") + .width("100%") + .height("100%") + .backgroundColor(0X330000FF) + .fontSize(16) + .textAlign(TextAlign.Center) + .onClick(() => { + window.getLastWindow(this.getUIContext().getHostContext(), (err, win) => { + let cutOutInfo = win.getWindowAvoidArea(window.AvoidAreaType.TYPE_SYSTEM_GESTURE) + console.log(JSON.stringify(cutOutInfo)) + if (window.Orientation.AUTO_ROTATION) { + let rotation: number = display.getDefaultDisplaySync().orientation // 获取当前屏幕的枚举值 + console.log('' + rotation); + if (rotation == 0) { + console.log("CutOutInfo 竖屏数据: " + JSON.stringify(cutOutInfo)); + } else if (rotation == 1) { + console.log("CutOutInfo 横屏数据: " + JSON.stringify(cutOutInfo)); + } else if (rotation == 2) { + console.log("CutOutInfo 反向竖屏数据: " + JSON.stringify(cutOutInfo)); + } else { + console.log("CutOutInfo 反向横屏数据: " + JSON.stringify(cutOutInfo)); + } + } + }) + }) + }} +// DocsCode 2 \ No newline at end of file diff --git a/ArkUI/entry/src/main/ets/pages/GetRouterBackParam.ets b/ArkUI/entry/src/main/ets/pages/GetRouterBackParam.ets new file mode 100644 index 0000000000000000000000000000000000000000..5ff4d98fe9ee02aa437cfd18a8b4bb50d875d8d6 --- /dev/null +++ b/ArkUI/entry/src/main/ets/pages/GetRouterBackParam.ets @@ -0,0 +1,34 @@ +/* +* 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. +*/ + +/* +* FAQ:如何获取router.back传递的参数 +*/ + +// DocsCode 1 +class InfoTmp { + age: number = 0 +} + +class RouTmp { + id: object = () => { + } + info: InfoTmp = new InfoTmp() +} + +const params: RouTmp = this.getUIContext().getRouter().getParams() as RouTmp; // 获取传递过来的参数对象 +const id: object = params.id // 获取id属性的值 +const age: number = params.info.age // 获取age属性的值 +// DocsCode 1 \ No newline at end of file diff --git a/ArkUI/entry/src/main/ets/pages/GetTextWidth.ets b/ArkUI/entry/src/main/ets/pages/GetTextWidth.ets new file mode 100644 index 0000000000000000000000000000000000000000..b929b0ebc4df286119781e7c2ffe7c61c02611e9 --- /dev/null +++ b/ArkUI/entry/src/main/ets/pages/GetTextWidth.ets @@ -0,0 +1,39 @@ +/* +* 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. +*/ + +/* +* FAQ:如何获取Text组件中文字的宽度 +*/ + +// DocsCode 1 +@Entry +@Component +struct Index { + @State textWidth: number = this.getUIContext().getMeasureUtils().measureText({ + textContent: "Hello word", + fontSize: '50px' + }) + + build() { + Row() { + Column() { + Text(`The width of 'Hello World': ${this.textWidth}`) + } + .width('100%') + } + .height('100%') + } +} +// DocsCode 1 \ No newline at end of file diff --git a/ArkUI/entry/src/main/ets/pages/GetWindowStageInstanceInPage.ets b/ArkUI/entry/src/main/ets/pages/GetWindowStageInstanceInPage.ets new file mode 100644 index 0000000000000000000000000000000000000000..bfad6ed8f1ef8c3a1680b1f3dcd08433555cdbce --- /dev/null +++ b/ArkUI/entry/src/main/ets/pages/GetWindowStageInstanceInPage.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. +*/ + +/* +* FAQ:如何在Page中获取WindowStage实例 +*/ + +// DocsCode 1 +import { UIAbility } from '@kit.AbilityKit'; +import { hilog } from '@kit.PerformanceAnalysisKit'; +import { window } from '@kit.ArkUI'; + +export default class EntryAbility extends UIAbility { + // ... + 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.'); + }); + console.info('windowStage+++', JSON.stringify(windowStage)) + AppStorage.setAndLink('windowStage', windowStage) + } + + // ... +} +// DocsCode 1 + +// DocsCode 2 +// Index.ets +import common from '@ohos.app.ability.common'; + +@Entry +@Component +struct Index { + @State showAbility: string = 'get windowStage' + + build() { + Row() { + Column() { + Text(this.showAbility) + .fontSize(30) + .fontWeight(FontWeight.Bold) + .onClick(() => { + let context = this.getUIContext().getHostContext() as common.UIAbilityContext; + console.info('获取到的WindowStage实例:',JSON.stringify(context.windowStage)) + }); + } + .width('100%') + } + .height('100%') + } +} +// DocsCode 2 \ No newline at end of file diff --git a/ArkUI/entry/src/main/ets/pages/HandleDraw9PatchReplacementRegimen.ets b/ArkUI/entry/src/main/ets/pages/HandleDraw9PatchReplacementRegimen.ets new file mode 100644 index 0000000000000000000000000000000000000000..b2c2afa90c5bb4b5c2ad180f91b011a0bb06a07b --- /dev/null +++ b/ArkUI/entry/src/main/ets/pages/HandleDraw9PatchReplacementRegimen.ets @@ -0,0 +1,74 @@ +/* +* 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. +*/ + +/* +* FAQ:是否有处理"9图"(又称"draw9patch"、".9图"、"点9图"等)的平替方案 +*/ + +// DocsCode 1 +@Entry +@Component +struct NineMapPrinciple { + build() { + Row() { + Image($r('app.media.startIcon')) + .resizable({ slice: { top: 10, left: 10, bottom: 50, right: 50 } }) + } + .height('50%') + } +} +// DocsCode 1 + + +// DocsCode 2 +@Entry +@Component +struct ChatBubbleStretchDemo { + @State text: string = 'Hello World Hello World Hello World Hello World'; + @State left: number = 10; + @State right: number = 10; + @State top: number = 10; + @State bottom: number = 10; + @State line: number = 2; + @State textSize: SizeOptions = this.getUIContext().getMeasureUtils().measureTextSize({ + textContent: this.text + }); + + build() { + Column() { + Stack() { + Image($r('app.media.lightBluexhdpi')) + .width(px2vp(Number(`${this.textSize.width}`)) < 350 ? 60 + px2vp + (Number(`${this.textSize.width}`)) : 350) + .height(this.text.length < 40 ? 50 + px2vp(Number(`${this.textSize.height}`)) + : 50 + (px2vp(Number(`${this.textSize.height}`)) * this.line)) + .resizable({ + slice: { + top: `${this.top}px`, + left: `${this.left}px`, + bottom: `${this.bottom}px`, + right: `${this.right}px` + } + }) + Text(this.text) + } + .width(350) + .height(200) + } + .height('100%') + .width('100%') + } +} +// DocsCode 2 \ No newline at end of file diff --git a/ArkUI/entry/src/main/ets/pages/ImageCanNotUseBindContextMenu.ets b/ArkUI/entry/src/main/ets/pages/ImageCanNotUseBindContextMenu.ets new file mode 100644 index 0000000000000000000000000000000000000000..916712871edc98fdca0c7b156224454d4fa24944 --- /dev/null +++ b/ArkUI/entry/src/main/ets/pages/ImageCanNotUseBindContextMenu.ets @@ -0,0 +1,55 @@ +/* +* 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. +*/ + +/* +* FAQ:Image无法使用bindContextMenu +*/ + +// DocsCode 1 +@Entry +@Component +struct Index { + @Builder + MenuBuilder() { + Flex({ direction: FlexDirection.Column, alignItems: ItemAlign.Center, justifyContent: FlexAlign.Center }) { + Button('Test ContextMenu1') + Divider().strokeWidth(2).margin(5).color(Color.Black) + Button('Test ContextMenu2') + Divider().strokeWidth(2).margin(5).color(Color.Black) + Button('Test ContextMenu3') + } + .width(200) + .height(160) + } + + build() { + Flex({ direction: FlexDirection.Column, alignItems: ItemAlign.Center, justifyContent: FlexAlign.Center }) { + Column() { + Image($r('app.media.icon')) + .draggable(false) + .width('100vp') + } + .bindContextMenu(this.MenuBuilder, ResponseType.LongPress) + .onDragStart(() => { + // 拖拽时关闭菜单 + this.getUIContext().getContextMenuController().close() + }) + + } + .width('100%') + .height('100%') + } +} +// DocsCode 1 \ No newline at end of file diff --git a/ArkUI/entry/src/main/ets/pages/Index.ets b/ArkUI/entry/src/main/ets/pages/Index.ets new file mode 100644 index 0000000000000000000000000000000000000000..8e2d24ad42693fc877d51bb7820f0a9da68fa135 --- /dev/null +++ b/ArkUI/entry/src/main/ets/pages/Index.ets @@ -0,0 +1,23 @@ +@Entry +@Component +struct Index { + @State message: string = 'Hello World'; + + build() { + RelativeContainer() { + Text(this.message) + .id('HelloWorld') + .fontSize($r('app.float.page_text_font_size')) + .fontWeight(FontWeight.Bold) + .alignRules({ + center: { anchor: '__container__', align: VerticalAlign.Center }, + middle: { anchor: '__container__', align: HorizontalAlign.Center } + }) + .onClick(() => { + this.message = 'Welcome'; + }) + } + .height('100%') + .width('100%') + } +} \ No newline at end of file diff --git a/ArkUI/entry/src/main/ets/pages/InertialSlidingEffect.ets b/ArkUI/entry/src/main/ets/pages/InertialSlidingEffect.ets new file mode 100644 index 0000000000000000000000000000000000000000..81c2ee26be66aad1a8b914fc13b3c927a511bfb0 --- /dev/null +++ b/ArkUI/entry/src/main/ets/pages/InertialSlidingEffect.ets @@ -0,0 +1,83 @@ +/* +* 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. +*/ + +/* +* FAQ:如何实现手指离开屏幕后的惯性滑动效果 +*/ + +// DocsCode 1 +@Entry +@Component +struct PanGestureExample { + @State offsetX: number = 0; + @State offsetY: number = 0; + @State positionX: number = 0; + @State positionY: number = 0; + private panOption: PanGestureOptions = new PanGestureOptions({ direction: PanDirection.Up | PanDirection.Down }); + + build() { + Column() { + Text('PanGesture offset:\nX: ' + this.offsetX + '\n' + 'Y: ' + this.offsetY) + } + .height(300) + .width(300) + .padding(20) + .border({ width: 3 }) + .margin(30) + .translate({ x: this.offsetX, y: this.offsetY, z: 0 }) // 以组件左上角为坐标原点进行移动 + // 上下拖动触发该手势事件 + .gesture( + PanGesture(this.panOption) + .onActionStart((event?: GestureEvent) => { + console.info('Pan start'); + }) + .onActionUpdate((event?: GestureEvent) => { + if (event) { + this.getUIContext().animateTo({ + curve: Curve.LinearOutSlowIn, + iterations: 1, + tempo: 10000, + playMode: PlayMode.Normal, + onFinish: () => { + console.info('play end'); + } + }, () => { + this.offsetX = this.positionX + event.offsetX; + this.offsetY = this.positionY + event.offsetY; + }) + } + }) + .onActionEnd((event?: GestureEvent) => { + if (event) { + this.getUIContext().animateTo({ + curve: Curve.LinearOutSlowIn, + iterations: 1, + playMode: PlayMode.Normal, + onFinish: () => { + console.info('play end'); + } + }, () => { + this.offsetX = this.positionX + event.offsetX * 2; + this.offsetY = this.positionY + event.offsetY * 2; + }) + } + this.positionX = this.offsetX; + this.positionY = this.offsetY; + console.info('Pan end'); + }) + ) + } +} +// DocsCode 1 \ No newline at end of file diff --git a/ArkUI/entry/src/main/ets/pages/ListFoldAnimationEffect.ets b/ArkUI/entry/src/main/ets/pages/ListFoldAnimationEffect.ets new file mode 100644 index 0000000000000000000000000000000000000000..87efb505b4c9db1e406b009f667cec51025450ff --- /dev/null +++ b/ArkUI/entry/src/main/ets/pages/ListFoldAnimationEffect.ets @@ -0,0 +1,77 @@ +/* +* 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. +*/ + +/* +* FAQ:如何实现List的折叠动画效果 +*/ + +// DocsCode 1 +@Entry +@Component +struct ListCollapseExpand { + private arr: number[] = [0, 1, 2, 3, 4, 5, 6]; + @State isContentShow: boolean = true; + @State selectItem: number = 0; + + build() { + Column() { + List({ initialIndex: 0 }) { + ForEach(this.arr, (item: number, index: number) => { + ListItem() { + Column() { + Row() { + Text(item.toString()) + Button(this.isContentShow && this.selectItem === item ? '收起' : '展开') + .onClick(() => { + this.getUIContext().animateTo({ + duration: 300, + onFinish: () => { + console.info('animation end'); + } + }, () => { + this.isContentShow = !this.isContentShow; + this.selectItem = item; + }) + }) + } + .width('100%') + .justifyContent(FlexAlign.SpaceBetween) + + if (this.isContentShow && this.selectItem === item) { + Text('这是内容区域') + .backgroundColor(Color.Gray) + .width('100%') + .height(100) + } + } + .backgroundColor(0xFFFFFF) + .width('100%') + .padding({ + top: 12, + bottom: 12 + }) + .margin({ top: 10 }) + } + }, (item: string) => item.toString()) + } + .scrollBar(BarState.Off) + .height('100%') + .width('100%') + } + .backgroundColor(0xF1F3F5) + .padding(12) + } +} +// DocsCode 1 \ No newline at end of file diff --git a/ArkUI/entry/src/main/ets/pages/ListenForScreenRotation.ets b/ArkUI/entry/src/main/ets/pages/ListenForScreenRotation.ets new file mode 100644 index 0000000000000000000000000000000000000000..53a445ba30fe13461c5ec84f3479439fb80359e1 --- /dev/null +++ b/ArkUI/entry/src/main/ets/pages/ListenForScreenRotation.ets @@ -0,0 +1,33 @@ +/* +* 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. +*/ + +/* +* FAQ:如何监听屏幕旋转 +*/ + +// DocsCode 1 +import { mediaquery, UIContext } from '@kit.ArkUI'; +const context = AppStorage.get("context") as UIContext; +let listener = context.getMediaQuery().matchMediaSync('(orientation: landscape)'); // 监听横屏事件 +function onPortrait(mediaQueryResult: mediaquery.MediaQueryResult) { + if (mediaQueryResult.matches) { + // do something here + } else { + // do something here + } +} +listener.on('change', onPortrait) // 注册回调 +listener.off('change', onPortrait) // 取消注册回调 +// DocsCode 1 \ No newline at end of file diff --git a/ArkUI/entry/src/main/ets/pages/PrivacyDetailsPage.ets b/ArkUI/entry/src/main/ets/pages/PrivacyDetailsPage.ets new file mode 100644 index 0000000000000000000000000000000000000000..63f2cab96a38dadf988359e74e7a81ab40518bc8 --- /dev/null +++ b/ArkUI/entry/src/main/ets/pages/PrivacyDetailsPage.ets @@ -0,0 +1,153 @@ +/* +* 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. +*/ + +/* +* FAQ:如何使当前页面弹窗在页面跳转返回之后还存在(隐私详情页场景) +*/ + +// DocsCode 1 +@Component +struct DialogJumpRetained { + @State visible: Visibility = Visibility.None; + + build() { + Stack() { + Row() { + Column() { + Text('Hello World') + .fontSize(50) + .fontWeight(FontWeight.Bold) + Button('click') + .onClick(() => { + if (this.visible === Visibility.Visible) { + this.visible = Visibility.None; + } else { + this.visible = Visibility.Visible; + } + }) + .backgroundColor(0x777474) + .fontColor(0x000000) + } + .width('100%') + } + .height('100%') + .backgroundColor(Color.Orange) + + Text('') + .onClick(() => { + if (this.visible == Visibility.Visible) { + this.visible = Visibility.None; + } else { + this.visible = Visibility.Visible; + } + }) + .width('100%') + .height('100%') + .opacity(0.5) + .backgroundColor(0x000000) + .visibility(this.visible) + Column() { + GridRow({ + columns: { + xs: 1, + sm: 4, + md: 8, + lg: 12 + }, + breakpoints: { + value: ['400vp', '600vp', '800vp'], + reference: BreakpointsReference.WindowSize + } + }) { + GridCol({ + span: { + xs: 1, + sm: 2, + md: 4, + lg: 8 + }, + offset: { + xs: 0, + sm: 1, + md: 2, + lg: 2 + } + }) { + Column() { + Text('隐私弹窗') + .fontSize(20) + .margin({ + top: 10, + bottom: 10 + }) + Text('是否查看隐私详情') + .fontSize(16) + .margin({ bottom: 10 }) + Flex({ justifyContent: FlexAlign.SpaceAround }) { + Button('关闭弹窗') + .onClick(() => { + if (this.visible === Visibility.Visible) { + this.visible = Visibility.None; + } else { + this.visible = Visibility.Visible; + } + }).backgroundColor(0xffffff).fontColor(Color.Black) + Button('跳转详情页') + .onClick(() => { + this.getUIContext().getRouter().pushUrl({ + url: 'pages/Second' + }); + }) + .backgroundColor(0xffffff) + .fontColor(Color.Red) + } + .margin({ bottom: 10 }) + } + .backgroundColor(0xffffff) + .visibility(this.visible) + .clip(true) + .borderRadius(20) + } + } + } + .width('95%') + } + } +} +// DocsCode 1 + +// DocsCode 2 +@Entry +@Component +struct Second { + @State message: string = '隐私详情页'; + build() { + Row() { + Column() { + Text(this.message) + .fontSize(50) + .fontWeight(FontWeight.Bold) + Button('返回').onClick(() => { + this.getUIContext().getRouter().back({ + url: 'pages/DialogJumpRetained' + }); + }) + } + .width('100%') + } + .height('100%') + } +} +// DocsCode 2 \ No newline at end of file diff --git a/ArkUI/entry/src/main/ets/pages/ReplaceDefaultTimeSet.ets b/ArkUI/entry/src/main/ets/pages/ReplaceDefaultTimeSet.ets new file mode 100644 index 0000000000000000000000000000000000000000..decf141b2fc999312ef8b4855e3cd3069036f0c8 --- /dev/null +++ b/ArkUI/entry/src/main/ets/pages/ReplaceDefaultTimeSet.ets @@ -0,0 +1,334 @@ +/* +* 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. +*/ + +/* +* FAQ:Grid onItemDragStart默认时间设置替代方案、以及多列GridItem实现通用示例 +*/ + +// DocsCode 1 +import { curves } from '@kit.ArkUI'; + +@Entry +@Component +struct Page { + //元素数组 + @State numbers: number[] = []; + @State row: number = 4; + //元素数组中最后一个元素的索引 + @State lastIndex: number = 0; + @State dragItem: number = -1; + @State scaleItem: number = -1; + @State item: number = -1; + @State offsetX: number = 0; + @State offsetY: number = 0; + // row 设置网格列数 + private str: string = ''; + private dragRefOffsetx: number = 0; + private dragRefOffsety: number = 0; + private FIX_VP_X: number = 108; + private FIX_VP_Y: number = 120; + + aboutToAppear() { + for (let i = 1; i <= 110; i++) { + this.numbers.push(i); + } + this.lastIndex = this.numbers.length - 1; + + // 多列 + for (let i = 0; i < this.row; i++) { + this.str = this.str + '1fr '; + } + } + + itemMove(index: number, newIndex: number): void { + if (!this.isDraggable(newIndex)) { + return; + } + let tmp = this.numbers.splice(index, 1); + this.numbers.splice(newIndex, 0, tmp[0]); + } + + //向下滑 + down(index: number): void { + // 指定固定GridItem不响应事件 + if (!this.isDraggable(index + this.row)) { + return; + } + this.offsetY -= this.FIX_VP_Y; + this.dragRefOffsety += this.FIX_VP_Y; + // 多列 + this.itemMove(index, index + this.row); + } + + //向下滑(右下角为空) + down2(index: number): void { + if (!this.isDraggable(index + 3)) { + return; + } + this.offsetY -= this.FIX_VP_Y; + this.dragRefOffsety += this.FIX_VP_Y; + this.itemMove(index, index + 3); + } + + //向上滑 + up(index: number): void { + if (!this.isDraggable(index - this.row)) { + return; + } + this.offsetY += this.FIX_VP_Y; + this.dragRefOffsety -= this.FIX_VP_Y; + this.itemMove(index, index - this.row); + } + + //向左滑 + left(index: number): void { + if (!this.isDraggable(index - 1)) { + return; + } + this.offsetX += this.FIX_VP_X; + this.dragRefOffsetx -= this.FIX_VP_X; + this.itemMove(index, index - 1); + } + + //向右滑 + right(index: number): void { + if (!this.isDraggable(index + 1)) { + return; + } + this.offsetX -= this.FIX_VP_X; + this.dragRefOffsetx += this.FIX_VP_X; + this.itemMove(index, index + 1); + } + + //向右下滑 + lowerRight(index: number): void { + if (!this.isDraggable(index + this.row + 1)) { + return; + } + this.offsetX -= this.FIX_VP_X; + this.dragRefOffsetx += this.FIX_VP_X; + this.offsetY -= this.FIX_VP_Y; + this.dragRefOffsety += this.FIX_VP_Y; + this.itemMove(index, index + this.row + 1); + } + + //向右上滑 + upperRight(index: number): void { + if (!this.isDraggable(index - (this.row - 1))) { + return; + } + this.offsetX -= this.FIX_VP_X; + this.dragRefOffsetx += this.FIX_VP_X; + this.offsetY += this.FIX_VP_Y; + this.dragRefOffsety -= this.FIX_VP_Y; + this.itemMove(index, index - (this.row - 1)); + } + + //向左下滑 + lowerLeft(index: number): void { + if (!this.isDraggable(index + (this.row - 1))) { + return; + } + this.offsetX += this.FIX_VP_X; + this.dragRefOffsetx -= this.FIX_VP_X; + this.offsetY -= this.FIX_VP_Y; + this.dragRefOffsety += this.FIX_VP_Y; + this.itemMove(index, index + (this.row - 1)); + } + + //向左上滑 + upperLeft(index: number): void { + if (!this.isDraggable(index - (this.row + 1))) { + return; + } + this.offsetX += this.FIX_VP_X; + this.dragRefOffsetx -= this.FIX_VP_X; + this.offsetY += this.FIX_VP_Y; + this.dragRefOffsety -= this.FIX_VP_Y; + this.itemMove(index, index - (this.row + 1)); + } + + //通过元素的索引,控制对应元素是否能移动排序 + isDraggable(index: number): boolean { + return index > -1; //恒成立,所有元素均可移动排序 + } + + build() { + Column() { + Grid() { + ForEach(this.numbers, (item: number) => { + GridItem() { + Text(item + '') + .fontSize(16) + .width('100%') + .textAlign(TextAlign.Center) + .height(100) + .borderRadius(10) + .backgroundColor(0xFFFFFF) + .shadow(this.scaleItem == item ? { + radius: 70, + color: '#15000000', + offsetX: 0, + offsetY: 0 + } : + { + radius: 0, + color: '#15000000', + offsetX: 0, + offsetY: 0 + }) + .animation({ + curve: Curve.Sharp, + duration: 300 + }) + } + .onAreaChange((_oldVal, newVal) => { + // 多列 + this.FIX_VP_X = Math.round(newVal.width as number); + this.FIX_VP_Y = Math.round(newVal.height as number); + }) + // 指定固定GridItem不响应事件 + .hitTestBehavior(this.isDraggable(this.numbers.indexOf(item)) ? HitTestMode.Default : HitTestMode.None) + .scale({ x: this.scaleItem === item ? 1.05 : 1, y: this.scaleItem === item ? 1.05 : 1 }) + .zIndex(this.dragItem === item ? 1 : 0) + .translate(this.dragItem === item ? { x: this.offsetX, y: this.offsetY } : { x: 0, y: 0 }) + .padding(10) + .gesture( + //以下组合手势为顺序识别,当长按手势事件未正常触发时则不会触发拖动手势事件 + GestureGroup(GestureMode.Sequence, + LongPressGesture({ + repeat: true, + duration: 50 + })//控制触发拖动的长按事件的时间,默认500毫秒,设置小于0为默认值,这里设置为50毫秒 + .onAction((_event?: GestureEvent) => { + this.getUIContext().animateTo({ + curve: Curve.Friction, + duration: 300 + }, () => { + this.scaleItem = item; + }); + }) + .onActionEnd(() => { + this.getUIContext().animateTo({ + curve: Curve.Friction, + duration: 300 + }, () => { + this.scaleItem = -1; + }); + }), + PanGesture({ + fingers: 1, + direction: null, + distance: 0 + }) + .onActionStart(() => { + this.dragItem = item; + this.dragRefOffsetx = 0; + this.dragRefOffsety = 0; + }) + .onActionUpdate((event: GestureEvent) => { + this.offsetY = event.offsetY - this.dragRefOffsety; + this.offsetX = event.offsetX - this.dragRefOffsetx; + + this.getUIContext().animateTo({ curve: curves.interpolatingSpring(0, 1, 400, 38) }, () => { + let index = this.numbers.indexOf(this.dragItem); + // 44 宽度一半 减间距 + if (this.offsetY >= this.FIX_VP_Y / 2 && + (this.offsetX <= this.FIX_VP_X / 2 && this.offsetX >= -this.FIX_VP_X / 2) + && (index + this.row <= this.lastIndex)) { + //向下滑 + this.down(index); + } else if (this.offsetY <= -this.FIX_VP_Y / 2 && + (this.offsetX <= this.FIX_VP_X / 2 && this.offsetX >= -this.FIX_VP_X / 2) + && index - this.row >= 0) { + //向上滑 + this.up(index); + } else if (this.offsetX >= this.FIX_VP_X / 2 && + (this.offsetY <= this.FIX_VP_Y / 2 && this.offsetY >= -this.FIX_VP_Y / 2) + && !(((index - (this.row - 1)) % this.row === 0) || index === this.lastIndex)) { + // ) { + //向右滑 + this.right(index); + } else if (this.offsetX <= -this.FIX_VP_X / 2 && + (this.offsetY <= this.FIX_VP_Y / 2 && this.offsetY >= -this.FIX_VP_Y / 2) + && !(index % this.row === 0)) { + //向左滑 + this.left(index); + } else if (this.offsetX >= this.FIX_VP_X / 2 && this.offsetY >= this.FIX_VP_Y / 2 + && ((index + this.row + 1 <= this.lastIndex && !((index - (this.row - 1)) % this.row === 0)) || + !((index - (this.row - 1)) % this.row === 0))) { + //向右下滑 + this.lowerRight(index); + } else if (this.offsetX >= this.FIX_VP_X / 2 && this.offsetY <= -this.FIX_VP_Y / 2 + && !((index - this.row < 0) || ((index - (this.row - 1)) % this.row === 0))) { + //向右上滑 + this.upperRight(index); + } else if (this.offsetX <= -this.FIX_VP_X / 2 && this.offsetY >= this.FIX_VP_Y / 2 + && (!(index % this.row === 0) && (index + (this.row - 1) <= this.lastIndex))) { + //向左下滑 + this.lowerLeft(index); + } else if (this.offsetX <= -this.FIX_VP_X / 2 && this.offsetY <= -this.FIX_VP_Y / 2 + && !((index <= this.row - 1) || (index % this.row === 0))) { + //向左上滑 + this.upperLeft(index); + } else if (this.offsetX >= this.FIX_VP_X / 2 && this.offsetY >= this.FIX_VP_Y / 2 + && (index === this.lastIndex)) { + //向右下滑(右下角为空) + this.down2(index); + } + }); + }) + .onActionEnd(() => { + this.getUIContext().animateTo({ + curve: curves.interpolatingSpring(0, 1, 400, 38) + }, () => { + this.dragItem = -1; + }); + this.getUIContext().animateTo({ + curve: curves.interpolatingSpring(14, 1, 170, 17), + delay: 150 + }, () => { + this.scaleItem = -1; + }); + }) + ) + .onCancel(() => { + this.getUIContext().animateTo({ + curve: curves.interpolatingSpring(0, 1, 400, 38) + }, () => { + this.dragItem = -1; + }); + this.getUIContext().animateTo({ + curve: curves.interpolatingSpring(14, 1, 170, 17) + }, () => { + this.scaleItem = -1; + }); + }) + ) + }, (item: number) => item.toString()) + } + .width('90%') + .editMode(true) + .scrollBar(BarState.Off) + // 多列 + .columnsTemplate(this.str) + } + .width('100%') + .height('100%') + .backgroundColor('#0D182431') + .padding({ top: 5 }) + } +} +// DocsCode 1 \ No newline at end of file diff --git a/ArkUI/entry/src/main/ets/pages/ResourceNesting.ets b/ArkUI/entry/src/main/ets/pages/ResourceNesting.ets new file mode 100644 index 0000000000000000000000000000000000000000..f0bd07b7e88f31050450569504e114d1febd0345 --- /dev/null +++ b/ArkUI/entry/src/main/ets/pages/ResourceNesting.ets @@ -0,0 +1,39 @@ +/* +* 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. +*/ + +/* +* FAQ:通过$r访问应用资源是否支持嵌套形式 +*/ + +// DocsCode 1 +@Entry +@Component +struct Page16 { + context = this.getUIContext(); + + build() { + Row() { + Column() { + Text($r('app.string.EntryAbility1_label2', + this.context.getHostContext()!.resourceManager.getStringSync($r('app.string.EntryAbility_label'))))//resources\base\element\string.json + .fontSize(50) + .fontWeight(FontWeight.Bold) + } + .width('100%') + } + .height('100%') + } +} +// DocsCode 1 \ No newline at end of file diff --git a/ArkUI/entry/src/main/ets/pages/ScreenRotation.ets b/ArkUI/entry/src/main/ets/pages/ScreenRotation.ets new file mode 100644 index 0000000000000000000000000000000000000000..db5697100dd3f9bed1d002f37feec2a8edda66ef --- /dev/null +++ b/ArkUI/entry/src/main/ets/pages/ScreenRotation.ets @@ -0,0 +1,53 @@ +/* +* 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. +*/ + +/* +* FAQ:如何设置窗口旋转 +*/ + +// DocsCode 1 +AppStorage.setOrCreate('windowStage',windowStage); +// DocsCode 1 + +// DocsCode 2 +import { display, window } from '@kit.ArkUI'; + +@Component +struct ScreenRotation { + windowStage: window.WindowStage = AppStorage.get('windowStage') as window.WindowStage; + // 获取主窗口的方式 + mainWin: window.Window = this.windowStage.getMainWindowSync(); + context = this.getUIContext(); + + onPageShow() { + // 获取最上层窗口的方式 + window.getLastWindow(this.context.getHostContext()); + this.mainWin.setPreferredOrientation(window.Orientation.LANDSCAPE); + // 使用display接口获取当前旋转方向,可以放置在监听中持续获取 + display.getDefaultDisplaySync().rotation; + } + + build() { + Row() { + Column({ space: 10 }) { + Text('屏幕旋转demo') + .fontSize(25) + .margin(20) + .fontColor(0x3399FF) + }.width('100%') + }.height('100%').backgroundColor(Color.White) + } +} +// DocsCode 2 \ No newline at end of file diff --git a/ArkUI/entry/src/main/ets/pages/ScreenorizontalVerticalStatus.ets b/ArkUI/entry/src/main/ets/pages/ScreenorizontalVerticalStatus.ets new file mode 100644 index 0000000000000000000000000000000000000000..1cfc999248a7c61039f9cc138e2d2d7f009ef49a --- /dev/null +++ b/ArkUI/entry/src/main/ets/pages/ScreenorizontalVerticalStatus.ets @@ -0,0 +1,87 @@ +/* +* 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. +*/ + +/* +* FAQ:如何监听当前屏幕的横竖屏状态?如何实现页面跟随屏幕横竖屏自动旋转 +*/ + +// DocsCode 1 +import { window, display } from '@kit.ArkUI'; + +const TAG = 'foo' +const ORIENTATION: Array = ['垂直', '水平', '反向垂直', '反向水平'] + +@Entry +@Component +struct ScreenTest { + context = this.getUIContext(); + @State rotation: number = 0 + @State message: string = ORIENTATION[this.rotation] + + aboutToAppear() { + this.setOrientation() + + let callback = async () => { + // ... + } + try { + display.on("change", callback); // 监听屏幕状态改变 + } catch (exception) { + console.error(TAG, 'Failed to register callback. Code: ' + JSON.stringify(exception)); + } + } + + setOrientation() { + try { + window.getLastWindow(this.context.getHostContext(), (err, data) => { // 获取window实例 + if (err.code) { + console.error(TAG, 'Failed to obtain the top window. Cause: ' + JSON.stringify(err)); + return; + } + let windowClass = data; + console.info(TAG, 'Succeeded in obtaining the top window. Data: ' + JSON.stringify(data)); + + let orientation = window.Orientation.AUTO_ROTATION; // 设置窗口方向为传感器自动旋转模式。 + try { + windowClass.setPreferredOrientation(orientation, (err) => { + if (err.code) { + console.error(TAG, 'Failed to set window orientation. Cause: ' + JSON.stringify(err)); + return; + } + console.info(TAG, 'Succeeded in setting window orientation.'); + }); + } catch (exception) { + console.error(TAG, 'Failed to set window orientation. Cause: ' + JSON.stringify(exception)); + } + ; + }); + } catch (exception) { + console.error(TAG, 'Failed to obtain the top window. Cause: ' + JSON.stringify(exception)); + } + ; + } + + build() { + Row() { + Column() { + Text(`${this.rotation}`).fontSize(25) + Text(`${this.message}`).fontSize(25) + } + .width("100%") + } + .height("100%") + } +} +// DocsCode 1 \ No newline at end of file diff --git a/ArkUI/entry/src/main/ets/pages/SetClickEventInCustomspan.ets b/ArkUI/entry/src/main/ets/pages/SetClickEventInCustomspan.ets new file mode 100644 index 0000000000000000000000000000000000000000..8075a5bc9cc4654586bcd48d1406ff571c9e3c75 --- /dev/null +++ b/ArkUI/entry/src/main/ets/pages/SetClickEventInCustomspan.ets @@ -0,0 +1,80 @@ +/* +* 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. +*/ + +/* +* FAQ:如何设置customspan不同位置的点击事件 +*/ + +// DocsCode 1 +@Entry +@Component +struct Index { + controller: RichEditorController = new RichEditorController(); + option: RichEditorOptions = { controller: this.controller }; + + @Builder + comment() { + Row() { + Text() { + Span('123123123') + ImageSpan($r('app.media.startIcon')).width(20).height(20) + Span('ggggggggggggggggggggggxxxxxxxxxxxxxxxxxxxxxxx') + } + .maxLines(1) + .wordBreak(WordBreak.BREAK_ALL) + .textOverflow({ overflow: TextOverflow.Ellipsis }) + .constraintSize({ + maxWidth: '90%' + }) + + Image($r('app.media.startIcon')) + .width(25) + .height(25) + .onClick(() => { + this.getUIContext().getPromptAction().showToast({ + message: '点我删除' + }) + }) + } + .width('100%') + .align(Alignment.Center) + .padding({ + top: 5, + bottom: 5 + }) + .borderRadius(20) + .backgroundColor(Color.Gray) + } + + build() { + Column() { + Column() { + RichEditor(this.option) + .onReady(() => { + this.controller.addBuilderSpan(() => this.comment()) + }) + .borderWidth(1) + .borderColor(Color.Green) + .width('100%') + .height('30%') + } + .borderWidth(1) + .borderColor(Color.Red) + .width('100%') + .height('70%') + } + } +} +// DocsCode 1 \ No newline at end of file diff --git a/ArkUI/entry/src/main/ets/pages/SetOffsetInBindPopup.ets b/ArkUI/entry/src/main/ets/pages/SetOffsetInBindPopup.ets new file mode 100644 index 0000000000000000000000000000000000000000..dc4e33a7bc594496324c05aaac78b4eaffec709e --- /dev/null +++ b/ArkUI/entry/src/main/ets/pages/SetOffsetInBindPopup.ets @@ -0,0 +1,100 @@ +/* +* 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. +*/ + +/* +* FAQ:bindPopup适配Web组件长按菜单功能,如何设置offset控制弹窗的偏移 +*/ + +// DocsCode 1 +import { webview } from '@kit.ArkWeb'; + +@Entry +@Component +struct BindPopupOffset { + controller: webview.WebviewController = new webview.WebviewController(); + private result: WebContextMenuResult | undefined = undefined; + @State linkUrl: string = ''; + @State offsetX: number = 0; + @State offsetY: number = 0; + @State showMenu: boolean = false; + + @Builder + MenuBuilder() { + Menu() { + MenuItem({ + content: '复制图片', + }) + .width(100) + .height(50) + .onClick(() => { + this.result?.copyImage(); + this.showMenu = false; + }) + MenuItem({ + content: '剪切' + }) + .width(100) + .height(50) + .onClick(() => { + this.result?.cut(); + this.showMenu = false; + }) + } + .width(150) + .backgroundColor('#eeeeee') + } + + build() { + Column() { + Row() + .width(0) + .height(0) + .position({ x: 0, y: 0 }) + .bindPopup(this.showMenu, + { + builder: this.MenuBuilder(), + enableArrow: false, + placement: Placement.LeftTop, + targetSpace: 0, + shadow: { + radius: 0 + }, + offset: { + x: this.offsetX - 7, + y: this.offsetY + }, + mask: false, + onStateChange: (e) => { + if (!e.isVisible) { + this.showMenu = false; + this.result!.closeContextMenu(); + } + } + }) + + Web({ src: $rawfile('index.html'), controller: this.controller })//触发自定义弹窗 + .onContextMenuShow((event) => { + if (event) { + this.result = event.result; + this.showMenu = true; + this.offsetX = Math.max(this.getUIContext().px2vp(event?.param.x() ?? 0) - 0, 0); + this.offsetY = Math.max(this.getUIContext().px2vp(event?.param.y() ?? 0) - 0, 0); + } + return true; + }) + } + } +} +// DocsCode 1 \ No newline at end of file diff --git a/ArkUI/entry/src/main/ets/pages/SetWindowPrivacyModeInPage.ets b/ArkUI/entry/src/main/ets/pages/SetWindowPrivacyModeInPage.ets new file mode 100644 index 0000000000000000000000000000000000000000..eba8e7a5fabdcf74b1dae960266679a54d5b297f --- /dev/null +++ b/ArkUI/entry/src/main/ets/pages/SetWindowPrivacyModeInPage.ets @@ -0,0 +1,175 @@ +/* +* 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. +*/ + +/* +* FAQ:如何实现防截屏功能 +*/ + +// DocsCode 1 +"requestPermissions": [ + {"name": "ohos.permission.PRIVACY_WINDOW"} +] +// DocsCode 1 + +// DocsCode 2 +import { AbilityConstant, ConfigurationConstant, UIAbility, Want } from '@kit.AbilityKit'; +import { hilog } from '@kit.PerformanceAnalysisKit'; +import { window } from '@kit.ArkUI'; +import { BusinessError } from '@kit.BasicServicesKit'; + +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.getMainWindow((err: BusinessError, data) => { + let errCode: number = err.code; + if (errCode) { + console.error('Failed to obtain the main window. Cause: ' + JSON.stringify(err)); + return; + } + let windowClass: window.Window = data; + console.info('Succeeded in obtaining the main window. Data: ' + JSON.stringify(data)); + // 设置窗口隐私模式 + let isPrivacyMode: boolean = true; + try { + windowClass.setWindowPrivacyMode(isPrivacyMode, (err: BusinessError) => { + const errCode: number = err.code; + if (errCode) { + console.error('Failed to set the window to privacy mode. Cause:' + JSON.stringify(err)); + return; + } + console.info('Succeeded in setting the window to privacy mode.'); + }); + } catch (exception) { + console.error('Failed to set the window to privacy mode. Cause:' + JSON.stringify(exception)); + } + }) + windowStage.loadContent('pages/Index', (err, data) => { + if (err.code) { + hilog.error(0x0000, 'testTag', 'Failed to load the content. Cause: %{public}s', JSON.stringify(err) ?? ''); + return; + } + hilog.info(0x0000, 'testTag', 'Succeeded in loading the content. Data: %{public}s', JSON.stringify(data) ?? ''); + }); + } + + onWindowStageDestroy(): 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'); + } +} +// DocsCode 2 + +// DocsCode 3 +"requestPermissions": [ + {"name": "ohos.permission.PRIVACY_WINDOW"} +] +// DocsCode 3 + +// DocsCode 4 +import { BusinessError } from '@kit.BasicServicesKit'; +import { common } from '@kit.AbilityKit'; +import { window } from '@kit.ArkUI'; + +class windowUtils { + static setWindowPrivacyModeInPage(context: common.UIAbilityContext, isFlag: boolean) { + window.getLastWindow(context).then((lastWindow) => { + lastWindow.setWindowPrivacyMode(isFlag, (err: BusinessError) => { + const errCode: number = err.code; + if (errCode) { + console.error('Failed to set the window to privacy mode. 1Cause:' + JSON.stringify(err)); + return; + } + console.info('Succeeded in setting the window to privacy mode.'); + }); + }) + } +} + +@Entry +@Component +struct Index { + @State message: string = 'hello world'; + @Provide('NavPathStack') pageStack: NavPathStack = new NavPathStack(); + context = this.getUIContext(); + + @Builder + PagesMap(name: string) { + if (name === 'Index') { + Index(); + } else if (name === 'PageOne') { + PageOne(); + } + } + + build() { + Navigation(this.pageStack) { + Column() { + Button('pushPath', { stateEffect: true, type: ButtonType.Capsule }) + .width('80%') + .height(40) + .margin(20) + .onClick(() => { + this.pageStack.pushPath({ name: 'PageOne' }) //将name指定的NavDestination页面信息入栈 + }) + } + } + .navDestination(this.PagesMap) + .onNavBarStateChange((isVisible: boolean) => { + // 导航栏显示状态切换时触发该回调 + console.info('------>isVisible:' + isVisible) + windowUtils.setWindowPrivacyModeInPage(this.context.getHostContext() as common.UIAbilityContext, isVisible); + }) + } +} + +@Component +struct PageOne { + @Consume('NavPathStack') pageStack: NavPathStack; + + build() { + NavDestination() { + Column() { + Text('PageOne') + } + } + .title('pageOne') + .onBackPressed(() => { + const popDestinationInfo = this.pageStack.pop(); // 弹出路由栈栈顶元素 + return true; + }) + } +} +// DocsCode 4 \ No newline at end of file diff --git a/ArkUI/entry/src/main/ets/pages/SettingScreenBrightness.ets b/ArkUI/entry/src/main/ets/pages/SettingScreenBrightness.ets new file mode 100644 index 0000000000000000000000000000000000000000..7c3536cbf57c85a5a7462d02e3076c60a2a1711b --- /dev/null +++ b/ArkUI/entry/src/main/ets/pages/SettingScreenBrightness.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. +*/ + +/* +* FAQ:如何设置屏幕亮度 +*/ + +// DocsCode 1 +AppStorage.setOrCreate('windowStage',windowStage); +// DocsCode 1 + +// DocsCode 2 +import { window } from '@kit.ArkUI' + +@Component +struct SettingScreenBrightness { + context = this.getUIContext(); + + windowStage: window.WindowStage = AppStorage.get('windowStage') as window.WindowStage; + // 获取主窗口的方式 + mainWin: window.Window = this.windowStage.getMainWindowSync(); + + aboutToAppear(): void { + // 修改brightness即可改变屏幕亮度 + let brightness = 1; + this.windowStage = AppStorage.get('windowStage') as window.WindowStage; + // 获取主窗口的方式 + this.mainWin = this.windowStage.getMainWindowSync(); + // 获取最上层窗口的方式 + window.getLastWindow(this.context.getHostContext()); + try { + this.mainWin.setWindowBrightness(brightness, (err) => { + if (err.code) { + console.error('Failed to set the brightness. Cause: ' + JSON.stringify(err)); + return; + } + console.info('Succeeded in setting the brightness.'); + }); + } catch (exception) { + console.error('Failed to set the brightness. Cause: ' + JSON.stringify(exception)); + } + } + + build() { + Row() { + Column({ space: 10 }) { + Text('屏幕亮度设置demo') + .fontSize(25) + .margin(20) + .fontColor(0x3399FF) + }.width('100%') + }.height('100%').backgroundColor(Color.White) + } +} +// DocsCode 2 \ No newline at end of file diff --git a/ArkUI/entry/src/main/ets/pages/SharePopup.ets b/ArkUI/entry/src/main/ets/pages/SharePopup.ets new file mode 100644 index 0000000000000000000000000000000000000000..99d5b92d050bebb55aef6162612e0e628af5659c --- /dev/null +++ b/ArkUI/entry/src/main/ets/pages/SharePopup.ets @@ -0,0 +1,115 @@ +/* +* 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. +*/ + +/* +* FAQ:如何使用自定义弹窗实现分享弹窗 +*/ + +// DocsCode 1 +import { ComponentContent } from '@kit.ArkUI'; + +let componentContent: ComponentContent | undefined = undefined; + +class Params { + applicationSharings: string[] = []; + sharings: string[] = []; + + constructor(applicationSharings: string[], sharings: string[] = []) { + this.applicationSharings = applicationSharings; + this.sharings = sharings; + } +} + +@Builder +function buildText($$: Params) { + Column() { + Text('share') + Grid() { + ForEach($$.applicationSharings, (item: string, index) => { + GridItem() { + Column() { + Image($r('app.media.app_icon')) + .height(50) + .width(50) + Text(item) + .fontSize(10) + } + } + }) + } + .height(100) + .rowsGap(20) + .columnsGap(20) + .scrollBar(BarState.Off) + .rowsTemplate('1fr') + + Grid() { + ForEach($$.sharings, (item: string, index) => { + GridItem() { + Column() { + Image($r('app.media.app_icon')) + .height(50) + .width(50) + Text(item) + .fontSize(10) + } + } + }) + } + .height(100) + .rowsGap(20) + .columnsGap(20) + .scrollBar(BarState.Off) + .rowsTemplate('1fr') + + Button('取消') + .width('100%') + .fontColor(Color.Black) + .backgroundColor(Color.White) + .onClick(() => { + this.getUIContext().getPromptAction()?.closeCustomDialog(componentContent); + }) + } + .backgroundColor('#FFF0F0F0') + .width('90%') + .height('30%') + .borderRadius(10) +} + +@Entry +@Component +struct CustomShareDialog { + @State applicationSharings: string[] = + ['share1', 'share2', 'share3', 'share4', 'share5', 'share6', 'share7', 'share8']; + @State sharings: string[] = ['share1', 'share2', 'share3', 'share4', 'share5', 'share6', 'share7', 'share8']; + + build() { + Row() { + Column() { + Button('click me') + .onClick(() => { + let contentNode = new ComponentContent(uiContext, wrapBuilder(buildText), + new Params(this.applicationSharings, this.sharings)); + componentContent = contentNode; + this.getUIContext().getPromptAction().openCustomDialog(contentNode); + }) + } + .width('100%') + .height('100%') + } + .height('100%') + } +} +// DocsCode 1 \ No newline at end of file diff --git a/ArkUI/entry/src/main/ets/pages/SideSlipEventInterception.ets b/ArkUI/entry/src/main/ets/pages/SideSlipEventInterception.ets new file mode 100644 index 0000000000000000000000000000000000000000..6f4f313ee5f36edaa767f7db7f076c14176edd8f --- /dev/null +++ b/ArkUI/entry/src/main/ets/pages/SideSlipEventInterception.ets @@ -0,0 +1,88 @@ +/* +* 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. +*/ + +/* +* FAQ:如何在Navigation页面中实现侧滑事件拦截 +*/ + +// DocsCode 1 +import { ShowDialogSuccessResponse } from '@kit.ArkUI'; + +@Entry +@Component +struct SideslipIntercept { + controller: TextAreaController = new TextAreaController(); + @State text: string = ''; + @Provide pageStackForComponentSharedPages: NavPathStack = new NavPathStack(); + + build() { + // 应用主页用NavDestination承载,用于显示Navigation的内容区 + Navigation(this.pageStackForComponentSharedPages) { + } + .onAppear(() => { + this.pageStackForComponentSharedPages.pushPathByName('MainPage', null, false); + }) + // 创建NavDestination组件,需使用此组件的onBackPressed回调拦截返回事件 + .navDestination(this.textArea) + } + + @Builder + textArea(name: string) { + NavDestination() { + Column() { + TextArea({ + text: this.text, + placeholder: 'input your word...', + controller: this.controller + }) + .onChange((value: string) => { + this.text = value; + }) + } + .justifyContent(FlexAlign.Start) + .width('100%') + .height('100%') + } + .onBackPressed(() => { + // 此处可添加拦截处理逻辑,然后return true放行 + this.getUIContext().getPromptAction().showDialog({ + message: '是否保存', + alignment: DialogAlignment.Center, + buttons: [ + { + text: '不保存', + color: '#0000FF' + }, + { + text: '保存', + color: '#0000FF' + } + ] + }).then((data: ShowDialogSuccessResponse) => { + // 操作菜单的响应结果,选中按钮在buttons数组中的索引,从0开始,第二个索引为1 + // 点击不保存按钮 + if (data.index === 0) { + console.info('不保存') + } + // 点击保存按钮 + if (data.index === 1) { + console.info('保存') + } + }) + return true ; + }) + } +} +// DocsCode 1 \ No newline at end of file diff --git a/ArkUI/entry/src/main/ets/pages/SimilarKeyFramesEffect.ets b/ArkUI/entry/src/main/ets/pages/SimilarKeyFramesEffect.ets new file mode 100644 index 0000000000000000000000000000000000000000..936c2adc4b8b647f2e31ca600df5367e0ca2961a --- /dev/null +++ b/ArkUI/entry/src/main/ets/pages/SimilarKeyFramesEffect.ets @@ -0,0 +1,64 @@ +/* +* 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. +*/ + +/* +* FAQ:如何实现类似keyframes的效果 +*/ + +// DocsCode 1 +@Entry +@Component +struct AnimateToExample { + @State widthSize: number = 250; + @State heightSize: number = 100; + @State rotateAngle: number = 0; + private flag: boolean = true; + @State opacityValue: number = 1; + + build() { + Column() { + Button('change size') + .width(this.widthSize) + .height(this.heightSize) + .margin(30) + .opacity(this.opacityValue) + .onClick(() => { + if (this.flag) { + this.getUIContext().animateTo({ + duration: 2000, + curve: Curve.EaseOut, + iterations: 1, + playMode: PlayMode.Normal, + onFinish: () => { + this.getUIContext().animateTo({ + duration: 2000, + curve: Curve.EaseOut, + iterations: 1, + playMode: PlayMode.Normal, + onFinish: () => { + } + }, () => { + this.opacityValue = 0.2; + }) + } + }, () => { + this.opacityValue = 0.5; + }) + } + }) + }.width('100%').margin({ top: 5 }) + } +} +// DocsCode 1 \ No newline at end of file diff --git a/ArkUI/entry/src/main/ets/pages/StatusbarAndPageOverlap.ets b/ArkUI/entry/src/main/ets/pages/StatusbarAndPageOverlap.ets new file mode 100644 index 0000000000000000000000000000000000000000..48230d78dbb02e9cecdc161bff5079d19e16e3e9 --- /dev/null +++ b/ArkUI/entry/src/main/ets/pages/StatusbarAndPageOverlap.ets @@ -0,0 +1,239 @@ +/* +* 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. +*/ + +/* +* FAQ:状态栏与页面内容发生重叠,如何解决 +*/ + +// DocsCode 1 +// EntryAbility.ets + +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/ImagePreview', (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.'); + + let windowClass: window.Window = windowStage.getMainWindowSync(); // 获取应用主窗口 + // 1. 设置窗口全屏 + let isLayoutFullScreen = true; + windowClass.setWindowLayoutFullScreen(isLayoutFullScreen); + // 2. 缓存window窗口对象 + AppStorage.setOrCreate('windowClass', windowClass); + }); +} +// DocsCode 1 + +// DocsCode 2 +import { window } from '@kit.ArkUI'; + +@Entry +@Component +struct ImagePreviewExample { + windowClass: window.Window = AppStorage.get('windowClass') as window.Window; + @State visible: Visibility = Visibility.None; + @State scaleValue: number = 1; + @State pinchValue: number = 1; + @State pinchX: number = 0; + @State pinchY: number = 0; + @State count: number = 0; + @State offsetX: number = 0; + @State offsetY: number = 0; + @State positionX: number = 0; + @State positionY: number = 0; + + build() { + Stack() { + Row() { + Column() { + Image($r('app.media.startIcon')) + .width(100) + .height(100) + .onClick(() => { + if (this.visible === Visibility.Visible) { + this.visible = Visibility.None; + } else { + this.visible = Visibility.Visible; + this.windowClass.setSpecificSystemBarEnabled('status', false); + } + }) + } + .width('100%') + .justifyContent(FlexAlign.Center) + .alignItems(HorizontalAlign.Center) + } + .height('100%') + + Text('') + .onClick(() => { + if (this.visible === Visibility.Visible) { + this.windowClass.setSpecificSystemBarEnabled('status', true); + this.visible = Visibility.None; + } else { + this.visible = Visibility.Visible; + } + }) + .width('100%') + .height('100%') + .opacity(0.16)// 透明度 + .backgroundColor(Color.Black) + .visibility(this.visible) + + Column() { + Image($r('app.media.startIcon')) + .width(300) + .height(300) + .draggable(false) + .visibility(this.visible) + .scale({ + x: this.scaleValue, + y: this.scaleValue, + z: 1 + }) + .translate({ + x: this.offsetX, + y: this.offsetY, + z: 0 + }) + .gesture( + GestureGroup(GestureMode.Parallel, + PinchGesture({ fingers: 2 }) + .onActionUpdate((event?: GestureEvent) => { + if (event) { + this.scaleValue = this.pinchValue * event.scale; + this.pinchX = event.pinchCenterX; + this.pinchY = event.pinchCenterY; + } + }) + .onActionEnd(() => { + this.pinchValue = this.scaleValue; + }), + PanGesture() + .onActionUpdate((event?: GestureEvent) => { + if (event) { + this.offsetX = this.positionX + event.offsetX; + this.offsetY = this.positionY + event.offsetY; + } + }) + .onActionEnd(() => { + this.positionX = this.offsetX; + this.positionY = this.offsetY; + }) + ) + ) + } + } + .backgroundColor(Color.White) + .height('100%') + .width('100%') + } +} +// DocsCode 2 + +// DocsCode 3 +// EntryAbility.ets + +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/AvoidStatusBar', (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.'); + + let windowClass: window.Window = windowStage.getMainWindowSync(); // 获取应用主窗口 + // 1. 设置窗口全屏 + let isLayoutFullScreen = true; + windowClass.setWindowLayoutFullScreen(isLayoutFullScreen); + // 2. 缓存window窗口对象 + AppStorage.setOrCreate('windowClass', windowClass); + + // 3. 获取布局避让遮挡的区域 + let type = window.AvoidAreaType.TYPE_SYSTEM; + let avoidArea = windowClass.getWindowAvoidArea(type); + let statusBar = this.getUIContext().px2vp( avoidArea.topRect.height); // 获取状态栏的高度 + AppStorage.setOrCreate('statusBar', statusBar); + }); +} +// DocsCode 3 + +// DocsCode 4 +@Entry +@Component +struct AvoidStatusBar { + statusBar: number = AppStorage.get('statusBar') as number; + + build() { + + Column() { + Row() { + Text('ROW1') + .fontSize(40) + } + .backgroundColor(Color.Orange) + .padding(20) + + Row() { + Text('ROW2') + .fontSize(40) + } + .backgroundColor(Color.Orange) + .padding(20) + + Row() { + Text('ROW3') + .fontSize(40) + } + .backgroundColor(Color.Orange) + .padding(20) + + Row() { + Text('ROW4') + .fontSize(40) + } + .backgroundColor(Color.Orange) + .padding(20) + + Row() { + Text('ROW5') + .fontSize(40) + } + .backgroundColor(Color.Orange) + .padding(20) + + Row() { + Text('ROW6') + .fontSize(40) + } + .backgroundColor(Color.Orange) + .padding(20) + } + .width('100%') + .height('100%') + .alignItems(HorizontalAlign.Center) + .justifyContent(FlexAlign.SpaceBetween) + .padding({ top: this.statusBar }) // 此处margin或padding具体数值在实际中应与状态栏区域高度保持一致 + .backgroundColor('#008000') + } +} +// DocsCode 4 \ No newline at end of file diff --git a/ArkUI/entry/src/main/ets/pages/SwipeActionToNotSlide.ets b/ArkUI/entry/src/main/ets/pages/SwipeActionToNotSlide.ets new file mode 100644 index 0000000000000000000000000000000000000000..45c79d13ec8a0c76b8d1ed47f0dca575626f8b8d --- /dev/null +++ b/ArkUI/entry/src/main/ets/pages/SwipeActionToNotSlide.ets @@ -0,0 +1,77 @@ +/* +* 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. +*/ + +/* +* FAQ:如何将ListItem的swipeAction滑动效果恢复至未滑动 +*/ + +// DocsCode 1 +@Component +export struct SwiperActionRecover { + @State arr: number[] = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]; + private scrollerForList: ListScroller = new ListScroller(); + + @Builder + itemEnd() { + Row() { + Button('Delete') + Button('Set') + .onClick(() => { + this.scrollerForList.closeAllSwipeActions(); // 重点是这行代码 + }) + } + .justifyContent(FlexAlign.SpaceEvenly) + } + + build() { + Column() { + List({ space: 5, scroller: this.scrollerForList }) { + ForEach(this.arr, (item: number) => { + ListItem() { + Text('item' + item) + .width('100%') + .height(100) + .textAlign(TextAlign.Center) + .borderRadius(10) + .backgroundColor(0xFFFFFF) + } + .transition({ + type: TransitionType.Delete, + opacity: 0 + }) + .swipeAction({ + end: { + builder: () => { + this.itemEnd(); + }, + onAction: () => { + this.getUIContext().animateTo({ duration: 1000 }, () => { + let index = this.arr.indexOf(item); + this.arr.splice(index, 1); + }); + }, + actionAreaDistance: 56 + } + }) + }, (item: string) => item) + } + } + .padding(20) + .backgroundColor(0xDCDCDC) + .width('100%') + .height('100%') + } +} +// DocsCode 1 \ No newline at end of file diff --git a/ArkUI/entry/src/main/ets/pages/TextExpansionAndCollapseFunctions.ets b/ArkUI/entry/src/main/ets/pages/TextExpansionAndCollapseFunctions.ets new file mode 100644 index 0000000000000000000000000000000000000000..da14102d8b8a0d4c5cd74b4a7f9380c0e36ffd68 --- /dev/null +++ b/ArkUI/entry/src/main/ets/pages/TextExpansionAndCollapseFunctions.ets @@ -0,0 +1,145 @@ +/* +* 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. +*/ + +/* +* FAQ:如何实现文本展开收起功能 +*/ + +// DocsCode 1 +// 文本行宽度 +const TEXT_WIDTH: number = 350; +// 收起文本显示行数 +const COLLAPSE_LINES: number = 2; +const ELLIPSIS: string = '...'; +const EXPAND_STR: string = '展开'; +const COLLAPSE_STR: string = '收起'; +const FULL_TEXT: string = + 'HarmonyOS提供了一套UI开发框架,即方舟开发框架(ArkUI框架)。方舟开发框架可为开发者提供应用UI开发' + + '所必需的能力,比如多种组件、布局计算、动画能力、UI交互、绘制等。\n' + + '方舟开发框架针对不同目的和技术背景的开发者提供了两种开发范式,分别是基于ArkTS的声明式开发范式(简称“声明式开发范式”)' + + '和兼容JS的类Web开发范式(简称“类Web开发范式”)。以下是两种开发范式的简单对比。' + +@Entry +@Component +struct TextCollapseTest { + @State title: string = FULL_TEXT; + @State suffixStr: string = ''; + private expanded: Boolean = true; + private needProcess: boolean = true + aboutToAppear(): void { + this.process(); + } + + process(): void { + if (this.expanded) { + this.collapseText(); + } else { + this.expandText(); + } + } + + //展开文本 + expandText(): void { + if (this.needProcess) { + this.suffixStr = COLLAPSE_STR; + this.expanded = true; + this.title = FULL_TEXT; + } + } + + //收起文本 + collapseText(): void { + if (!this.needProcess) { + return; + } + // 展开文本的size + let expandSize: SizeOptions = this.getUIContext().getMeasureUtils().measureTextSize({ + textContent: FULL_TEXT, + constraintWidth: TEXT_WIDTH, + fontSize: 30 + }); + + // 将要收起的文本size + let collapseSize: SizeOptions = this.getUIContext().getMeasureUtils().measureTextSize({ + textContent: FULL_TEXT, + constraintWidth: TEXT_WIDTH, + fontSize: 30, + maxLines: COLLAPSE_LINES + }); + + //收起的文本高度和展开时的文本高度相等时,不进行处理 + if ((expandSize.height as number) == (collapseSize.height as number)) { + this.needProcess = false; + return; + } + + let clipTitle: string = FULL_TEXT + this.suffixStr = EXPAND_STR; + // 使用二分法查找正好两行的长度的字符串 + let leftCursor: number = 0; + let rightCursor: number = this.title.length; + let cursor: number = Math.floor(rightCursor / 2); + let tempTitle: string = ''; + while (true) { + tempTitle = this.title.substring(0, cursor) + ELLIPSIS + EXPAND_STR; + const currentLinesTextSize: SizeOptions = this.getUIContext().getMeasureUtils().measureTextSize({ + textContent: tempTitle, + fontSize: 30, + wordBreak: WordBreak.BREAK_ALL, + constraintWidth: TEXT_WIDTH + }); + + if ((currentLinesTextSize.height as number) > (collapseSize.height as number)) { + // 当前字符已超过两行,向左继续找 + rightCursor = cursor; + cursor = leftCursor + Math.floor((cursor - leftCursor) / 2); + } else { + // 当前字符小于两行了,可能已经ok,但仍需向右查找 + leftCursor = cursor; + cursor += Math.floor((rightCursor - cursor) / 2); + } + if (Math.abs(rightCursor - leftCursor) <= 1) { + // 两次指针基本重合了,代表已找到 + break; + } + } + clipTitle = this.title.substring(0, cursor - 1); + this.title = clipTitle + ELLIPSIS; + this.expanded = false; + } + + build() { + Row() { + Column() { + Text() { + Span(this.title) + if (this.needProcess) { + Span(this.suffixStr) + .fontColor(Color.Orange) + .onClick(() => { + this.process(); + }) + } + } + .fontSize(30) + .fontWeight(FontWeight.Bold) + .width(TEXT_WIDTH) + } + .width('100%') + } + .height('100%') + } +} +// DocsCode 1 \ No newline at end of file diff --git a/ArkUI/entry/src/main/ets/pages/TextSetMaxlinesIsHideText.ets b/ArkUI/entry/src/main/ets/pages/TextSetMaxlinesIsHideText.ets new file mode 100644 index 0000000000000000000000000000000000000000..61b91326f41008ddb63f4170caeda74b63c3ac0a --- /dev/null +++ b/ArkUI/entry/src/main/ets/pages/TextSetMaxlinesIsHideText.ets @@ -0,0 +1,78 @@ +/* +* 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. +*/ + +/* +* FAQ:Text组件设置maxLines后如何确定文本是否被隐藏 +*/ + +// DocsCode 1 +@Entry +@Component +struct TextInputExample { + @State text: string = ''; + @State truncatedHint: string = "文本未截断"; + controller: TextInputController = new TextInputController(); + + build() { + Column() { + TextInput({ text: this.text, placeholder: 'input your word...', controller: this.controller }) + .placeholderColor(Color.Grey) + .placeholderFont({ size: 14, weight: 400 }) + .caretColor(Color.Blue) + .width(400) + .height(40) + .margin(20) + .fontSize(14) + .fontColor(Color.Black) + .onChange((value: string) => { + this.text = value; + let textSizeShow1: SizeOptions = this.getUIContext().getMeasureUtils().measureTextSize({ + textContent: this.text, + constraintWidth: 100, + fontSize: 14, + overflow: TextOverflow.Ellipsis, + maxLines: 2 + }) + let textSizeShow2: SizeOptions = this.getUIContext().getMeasureUtils().measureTextSize({ + textContent: this.text + " ", + constraintWidth: 100, + fontSize: 14, + overflow: TextOverflow.Ellipsis, + maxLines: 2000000 + }) + console.log("textSizeShow1.height=" + textSizeShow1.height); + console.log("textSizeShow2.height=" + textSizeShow2.height); + + if (textSizeShow2 && textSizeShow1 && textSizeShow2?.height && textSizeShow1?.height && (textSizeShow2?.height > textSizeShow1?.height)) { + console.log("文本截断"); + this.truncatedHint = "文本截断"; + } else { + console.log("文本未截断"); + this.truncatedHint = "文本未截断"; + } + }) + Text(this.text) + .maxLines(2) + .width(100) + .textOverflow({ overflow: TextOverflow.Ellipsis }) + .border({ width: 1 }) + .minFontSize(14) + .maxFontSize(24) + Text(this.truncatedHint) + + }.width('100%') + } +} +// DocsCode 1 \ No newline at end of file diff --git a/ArkUI/entry/src/main/ets/pages/TheHeaderTruncated.ets b/ArkUI/entry/src/main/ets/pages/TheHeaderTruncated.ets new file mode 100644 index 0000000000000000000000000000000000000000..449a3b344edbd5edfacc2563f9dd8b5f94217aac --- /dev/null +++ b/ArkUI/entry/src/main/ets/pages/TheHeaderTruncated.ets @@ -0,0 +1,75 @@ +/* +* 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. +*/ + +/* +* FAQ:如何解决Web页面输入框拉起键盘后,页面头部被截断的问题 +*/ + +// DocsCode 1 +// 子窗口页面布局 +import { webview } from '@kit.ArkWeb'; +import { window } from '@kit.ArkUI'; + +@Entry +@Component +export struct SubWindowPage { + @State webViewVisibility: Visibility = Visibility.Visible; + private pageWidth = 320; + private pageHeight = 500; + private controller: webview.WebviewController = new webview.WebviewController(); + @State flexAlign: FlexAlign = FlexAlign.Center; + @State screenHeight: number | string = '100%'; + + aboutToAppear() { + window.getLastWindow(getContext(this)).then(currentWindow => { + // 监视软键盘的弹出和收起 + currentWindow.on('avoidAreaChange', async data => { + let property = currentWindow.getWindowProperties(); + let avoidArea = currentWindow.getWindowAvoidArea(window.AvoidAreaType.TYPE_KEYBOARD); + this.screenHeight = this.getUIContext().px2vp(property.windowRect.height - avoidArea.bottomRect.height); + }); + }) + } + + build() { + Stack() { + Column() { + Web({ src: $rawfile('index.html'), controller: this.controller }) + .javaScriptAccess(true) + .fileAccess(false) + .zoomAccess(false) + .domStorageAccess(true) + .onlineImageAccess(true) + .horizontalScrollBarAccess(false) + .verticalScrollBarAccess(false) + .cacheMode(CacheMode.Online) + .width(this.pageWidth) + .height(this.pageHeight) + .border({ radius: 6 }) + .visibility(this.webViewVisibility) + .backgroundColor(Color.Pink) + } + .justifyContent(this.flexAlign) + .alignItems(HorizontalAlign.Center) + .width('100%') + .height('100%') + } + .width('100%') + .height(this.screenHeight) + .backgroundColor('#999955') + .alignContent(Alignment.Center) + } +} +// DocsCode 1 \ No newline at end of file diff --git a/ArkUI/entry/src/main/ets/pages/ToggleWithDelay.ets b/ArkUI/entry/src/main/ets/pages/ToggleWithDelay.ets new file mode 100644 index 0000000000000000000000000000000000000000..d64e193ac06a92414b0adb44cf7da08decca21b3 --- /dev/null +++ b/ArkUI/entry/src/main/ets/pages/ToggleWithDelay.ets @@ -0,0 +1,49 @@ +/* +* 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. +*/ + +/* +* FAQ:目前Toggle组件响应点击之后会立刻渲染且立刻回调,如何延迟改变Toggle状态且延时回调? +*/ + +// DocsCode 1 +@Entry +@Component +struct ToggleDemo { + @State isDarkMode: boolean = false; + + build() { + Column() { + Column() { + Toggle({ type: ToggleType.Switch, isOn: $$this.isDarkMode }) + .onChange((isOn: boolean) => { + console.info('Toggle.onChange:isOn' + isOn); + this.isDarkMode = isOn; + this.getUIContext().getHostContext()!.getApplicationContext().setColorMode(this.isDarkMode ? 0 : 1); + }) + } + // 设置hitTestBehavior属性为HitTestMode.Block,阻塞Toggle组件响应事件。 + .hitTestBehavior(HitTestMode.Block) + .onClick(() => { + setTimeout(() => { + this.isDarkMode = !this.isDarkMode; + }, 1500); + }) + } + .width('100%') + .height('100%') + .padding(32) + } +} +// DocsCode 1 \ No newline at end of file diff --git a/ArkUI/entry/src/main/ets/pages/WindowProperties.ets b/ArkUI/entry/src/main/ets/pages/WindowProperties.ets new file mode 100644 index 0000000000000000000000000000000000000000..d30bc6d31262549b7938530e3bdef42f64df8b16 --- /dev/null +++ b/ArkUI/entry/src/main/ets/pages/WindowProperties.ets @@ -0,0 +1,46 @@ +/* +* 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. +*/ + +/* +* FAQ:如何获取窗口的宽度 +*/ + +// DocsCode 1 +import { window } from '@kit.ArkUI'; + +@Entry +@Component +struct WindowProperties { + context = this.getUIContext(); + + build() { + Text("Scroll Area") + .width("100%") + .height("100%") + .backgroundColor(0X330000FF) + .fontSize(16) + .textAlign(TextAlign.Center) + .onClick(() => { + window.getLastWindow(this.context.getHostContext()).then((data) => { + // 获取窗口属性 + let properties = data?.getWindowProperties(); + // // 获取窗口宽高 + console.log("windowClass width: " + properties.windowRect.width); + console.log("windowClass height: " + properties.windowRect.height); + }); + }) + } +} +// DocsCode 1 \ No newline at end of file diff --git a/ArkUI/entry/src/main/module.json5 b/ArkUI/entry/src/main/module.json5 new file mode 100644 index 0000000000000000000000000000000000000000..a1cea8b6a4560cee7bda7a2db52f310c035ab6c8 --- /dev/null +++ b/ArkUI/entry/src/main/module.json5 @@ -0,0 +1,52 @@ +{ + "module": { + "name": "entry", + "type": "entry", + "description": "$string:module_desc", + "mainElement": "EntryAbility", + "deviceTypes": [ + "phone", + "tablet", + "2in1" + ], + "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/ArkUI/entry/src/main/resources/base/element/color.json b/ArkUI/entry/src/main/resources/base/element/color.json new file mode 100644 index 0000000000000000000000000000000000000000..3c712962da3c2751c2b9ddb53559afcbd2b54a02 --- /dev/null +++ b/ArkUI/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/ArkUI/entry/src/main/resources/base/element/float.json b/ArkUI/entry/src/main/resources/base/element/float.json new file mode 100644 index 0000000000000000000000000000000000000000..a0a93dd91fd48f08f3a9532c76e9b26e68d4c034 --- /dev/null +++ b/ArkUI/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/ArkUI/entry/src/main/resources/base/element/string.json b/ArkUI/entry/src/main/resources/base/element/string.json new file mode 100644 index 0000000000000000000000000000000000000000..f94595515a99e0c828807e243494f57f09251930 --- /dev/null +++ b/ArkUI/entry/src/main/resources/base/element/string.json @@ -0,0 +1,16 @@ +{ + "string": [ + { + "name": "module_desc", + "value": "module description" + }, + { + "name": "EntryAbility_desc", + "value": "description" + }, + { + "name": "EntryAbility_label", + "value": "label" + } + ] +} \ No newline at end of file diff --git a/ArkUI/entry/src/main/resources/base/media/background.png b/ArkUI/entry/src/main/resources/base/media/background.png new file mode 100644 index 0000000000000000000000000000000000000000..923f2b3f27e915d6871871deea0420eb45ce102f Binary files /dev/null and b/ArkUI/entry/src/main/resources/base/media/background.png differ diff --git a/ArkUI/entry/src/main/resources/base/media/foreground.png b/ArkUI/entry/src/main/resources/base/media/foreground.png new file mode 100644 index 0000000000000000000000000000000000000000..97014d3e10e5ff511409c378cd4255713aecd85f Binary files /dev/null and b/ArkUI/entry/src/main/resources/base/media/foreground.png differ diff --git a/ArkUI/entry/src/main/resources/base/media/layered_image.json b/ArkUI/entry/src/main/resources/base/media/layered_image.json new file mode 100644 index 0000000000000000000000000000000000000000..fb49920440fb4d246c82f9ada275e26123a2136a --- /dev/null +++ b/ArkUI/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/ArkUI/entry/src/main/resources/base/media/startIcon.png b/ArkUI/entry/src/main/resources/base/media/startIcon.png new file mode 100644 index 0000000000000000000000000000000000000000..205ad8b5a8a42e8762fbe4899b8e5e31ce822b8b Binary files /dev/null and b/ArkUI/entry/src/main/resources/base/media/startIcon.png differ diff --git a/ArkUI/entry/src/main/resources/base/profile/backup_config.json b/ArkUI/entry/src/main/resources/base/profile/backup_config.json new file mode 100644 index 0000000000000000000000000000000000000000..78f40ae7c494d71e2482278f359ec790ca73471a --- /dev/null +++ b/ArkUI/entry/src/main/resources/base/profile/backup_config.json @@ -0,0 +1,3 @@ +{ + "allowToBackupRestore": true +} \ No newline at end of file diff --git a/ArkUI/entry/src/main/resources/base/profile/main_pages.json b/ArkUI/entry/src/main/resources/base/profile/main_pages.json new file mode 100644 index 0000000000000000000000000000000000000000..d92299cfbe3a2dd279ae1322ca5c4d871743455e --- /dev/null +++ b/ArkUI/entry/src/main/resources/base/profile/main_pages.json @@ -0,0 +1,14 @@ +{ + "src": [ + "pages/Index", + "pages/TabBarAddComponent", + "pages/CustomDialogVariableToPage", + "pages/GetHorizontalAndVerticalScreenStatus", + "pages/AdaptWebForFullScreenOfPlayer", + "pages/ListenForScreenRotation", + "pages/TextExpansionAndCollapseFunctions", + "pages/GetTextWidth", + "pages/TextSetMaxlinesIsHideText", + "pages/HandleDraw9PatchReplacementRegimen" + ] +} \ No newline at end of file diff --git a/ArkUI/entry/src/main/resources/dark/element/color.json b/ArkUI/entry/src/main/resources/dark/element/color.json new file mode 100644 index 0000000000000000000000000000000000000000..79b11c2747aec33e710fd3a7b2b3c94dd9965499 --- /dev/null +++ b/ArkUI/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/ArkUI/entry/src/mock/mock-config.json5 b/ArkUI/entry/src/mock/mock-config.json5 new file mode 100644 index 0000000000000000000000000000000000000000..7a73a41bfdf76d6f793007240d80983a52f15f97 --- /dev/null +++ b/ArkUI/entry/src/mock/mock-config.json5 @@ -0,0 +1,2 @@ +{ +} \ No newline at end of file diff --git a/ArkUI/entry/src/ohosTest/ets/test/Ability.test.ets b/ArkUI/entry/src/ohosTest/ets/test/Ability.test.ets new file mode 100644 index 0000000000000000000000000000000000000000..85c78f67579d6e31b5f5aeea463e216b9b141048 --- /dev/null +++ b/ArkUI/entry/src/ohosTest/ets/test/Ability.test.ets @@ -0,0 +1,35 @@ +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/ArkUI/entry/src/ohosTest/ets/test/List.test.ets b/ArkUI/entry/src/ohosTest/ets/test/List.test.ets new file mode 100644 index 0000000000000000000000000000000000000000..794c7dc4ed66bd98fa3865e07922906e2fcef545 --- /dev/null +++ b/ArkUI/entry/src/ohosTest/ets/test/List.test.ets @@ -0,0 +1,5 @@ +import abilityTest from './Ability.test'; + +export default function testsuite() { + abilityTest(); +} \ No newline at end of file diff --git a/ArkUI/entry/src/ohosTest/module.json5 b/ArkUI/entry/src/ohosTest/module.json5 new file mode 100644 index 0000000000000000000000000000000000000000..55725a929993a8a18b3808d41ef037759440488b --- /dev/null +++ b/ArkUI/entry/src/ohosTest/module.json5 @@ -0,0 +1,13 @@ +{ + "module": { + "name": "entry_test", + "type": "feature", + "deviceTypes": [ + "phone", + "tablet", + "2in1" + ], + "deliveryWithInstall": true, + "installationFree": false + } +} diff --git a/ArkUI/entry/src/test/List.test.ets b/ArkUI/entry/src/test/List.test.ets new file mode 100644 index 0000000000000000000000000000000000000000..bb5b5c3731e283dd507c847560ee59bde477bbc7 --- /dev/null +++ b/ArkUI/entry/src/test/List.test.ets @@ -0,0 +1,5 @@ +import localUnitTest from './LocalUnit.test'; + +export default function testsuite() { + localUnitTest(); +} \ No newline at end of file diff --git a/ArkUI/entry/src/test/LocalUnit.test.ets b/ArkUI/entry/src/test/LocalUnit.test.ets new file mode 100644 index 0000000000000000000000000000000000000000..165fc1615ee8618b4cb6a622f144a9a707eee99f --- /dev/null +++ b/ArkUI/entry/src/test/LocalUnit.test.ets @@ -0,0 +1,33 @@ +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/ArkUI/hvigor/hvigor-config.json5 b/ArkUI/hvigor/hvigor-config.json5 new file mode 100644 index 0000000000000000000000000000000000000000..9c90b403dd784cdf9f08be97a5bc94c77fe8daf8 --- /dev/null +++ b/ArkUI/hvigor/hvigor-config.json5 @@ -0,0 +1,22 @@ +{ + "modelVersion": "5.0.4", + "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/ArkUI/hvigorfile.ts b/ArkUI/hvigorfile.ts new file mode 100644 index 0000000000000000000000000000000000000000..c0b1912d6817dc2a28164a25e448ebe80cf06907 --- /dev/null +++ b/ArkUI/hvigorfile.ts @@ -0,0 +1,6 @@ +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/ArkUI/oh-package-lock.json5 b/ArkUI/oh-package-lock.json5 new file mode 100644 index 0000000000000000000000000000000000000000..c6f99f5c73b06c5fdef7ec6f491b74b7befebe2e --- /dev/null +++ b/ArkUI/oh-package-lock.json5 @@ -0,0 +1,27 @@ +{ + "meta": { + "stableOrder": true + }, + "lockfileVersion": 3, + "ATTENTION": "THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY.", + "specifiers": { + "@ohos/hamock@1.0.0": "@ohos/hamock@1.0.0", + "@ohos/hypium@1.0.21": "@ohos/hypium@1.0.21" + }, + "packages": { + "@ohos/hamock@1.0.0": { + "name": "@ohos/hamock", + "version": "1.0.0", + "integrity": "sha512-K6lDPYc6VkKe6ZBNQa9aoG+ZZMiwqfcR/7yAVFSUGIuOAhPvCJAo9+t1fZnpe0dBRBPxj2bxPPbKh69VuyAtDg==", + "resolved": "https://repo.harmonyos.com/ohpm/@ohos/hamock/-/hamock-1.0.0.har", + "registryType": "ohpm" + }, + "@ohos/hypium@1.0.21": { + "name": "@ohos/hypium", + "version": "1.0.21", + "integrity": "sha512-iyKGMXxE+9PpCkqEwu0VykN/7hNpb+QOeIuHwkmZnxOpI+dFZt6yhPB7k89EgV1MiSK/ieV/hMjr5Z2mWwRfMQ==", + "resolved": "https://repo.harmonyos.com/ohpm/@ohos/hypium/-/hypium-1.0.21.har", + "registryType": "ohpm" + } + } +} \ No newline at end of file diff --git a/ArkUI/oh-package.json5 b/ArkUI/oh-package.json5 new file mode 100644 index 0000000000000000000000000000000000000000..75e4e229db0f608fc3d9471c8819d0e52fb403c5 --- /dev/null +++ b/ArkUI/oh-package.json5 @@ -0,0 +1,10 @@ +{ + "modelVersion": "5.0.4", + "description": "Please describe the basic information.", + "dependencies": { + }, + "devDependencies": { + "@ohos/hypium": "1.0.21", + "@ohos/hamock": "1.0.0" + } +}