-
在开发HarmonyOS应用的过程中,从初始测试到最终上架,每一步都需要精心规划与实施。本文将按照实际开发流程,详细介绍从生成签名证书文件到完成小规模真机内测直至最终应用上架的各个步骤。官方交互式资料体验中心:AppGallery Connect交互式资料体验中心一、生成签名证书文件在开发阶段结束并准备进行真机测试或上架之前,首先需要生成签名证书文件。这是确保应用安全性的重要步骤之一。步骤如下:1. 生成密钥和证书请求文件(CSR)使用DevEco Studio中的“生成密钥和CSR”功能,输入相关信息以生成密钥文件和CSR文件。注意,填写信息时应避免使用中文字符,以免引起后续问题。参考:文档中心2. 上传CSR文件生成证书登录AppGallery Connect平台,上传之前生成的CSR文件,以生成相应的证书文件(.cer)。参考: 文档中心3. 生成P7B文件再次登录AppGallery Connect,进入“Profile”页面,使用之前生成的.cer文件生成.p7b文件。参考:文档中心4. 配置签名信息在DevEco Studio中配置签名信息:依次选择File > Project Structure > Signing Configs,在此处指定之前生成的密钥文件及其密码。二、小规模真机内测方案完成签名证书文件的准备工作之后,下一步是进行小规模的真机内测。这有助于在正式发布前发现并解决潜在的问题。方案包括但不限于:1. 开放式测试• 打包方式:使用发布证书打包成.app格式的安装包。• 上传流程:登录AppGallery Connect上传安装包。• 用户安装:用户收到邀请后,可以在真机上安装并使用该应用。• 前置条件:打包时需要使用发布证书,打.app格式;软件著作权、备案并填写相关信息,因为上传测试包也需要提交审核资质。参考:文档中心2. 发布企业内部应用• 打包方式:使用企业证书打包成.hap格式的安装包。• 上传流程:登录AppGallery Connect上传安装包。• 用户安装:用户收到邀请后,可以在真机上安装并使用该应用。• 前置条件:打包时需要使用企业证书,打.hap格式;需要额外准备一个账号,并填写申请信息,包括企业全称、应用信息、申请原因、使用人数等。不支持元服务也不支持个人申请。参考:文档中心3. DevEco Testing命令安装• 打包方式:使用调试证书打包成.hap格式的安装包。• 上传流程:通过DevEco Testing命令app install -r <路径>\xx.hap安装。• 用户安装:用户通过命令直接安装测试包。• 前置条件:打包时需要使用调试证书,打.hap格式;安装DevEco Testing软件,手机开启开发者模式。参考:下载中心 | 华为开发者联盟-HarmonyOS开发者官网,共建鸿蒙生态三、应用上架完成内测并确认应用无误后,接下来就是正式上架的步骤。流程如下:1. 构建并打包APP• 通过DevEco Studio的“Build > Build Hap(s)/APP(s) > Build APP(s)”菜单构建APP。构建完成后,在项目的相应目录下找到.app格式的正式签名安装包,用于上传至应用商店。2. 上传至AppGallery Connect参考:AppGallery Connect• 登录AppGallery Connect,上传之前构建好的.app格式安装包。• 按照提示填写应用的相关信息,如应用名称、描述、截图等。3. 提交审核• 提交应用后,等待华为团队的审核。审核期间,保持通讯畅通以便及时回应可能出现的问题。4. 完成上架• 审核通过后,应用正式上架,用户可以在AppGallery中搜索并下载使用。四、所需资料在整个流程中,还需要准备一些必要的资料:1. APP备案根据华为官方指南,APP备案需通过华为云、阿里云或腾讯云等接入服务商完成。填写备案信息时,重点关注包名、公钥、签名信息(证书MD5指纹)等。参考:文档中心2. 电子版软件著作权准备好《软件版权申请信息采集表.doc》、《源代码.doc》、《xxxapp 操作手册.doc》等相关文档,以供申请电子版软件著作权。转载自https://www.cnblogs.com/zhongcx/articles/18444615
-
随着HarmonyOS的发展,API版本的更新带来了许多新的特性和限制。在API 11及以后的版本中,直接赋值对象的语法不再被支持,这要求开发者们采用新的方式来处理对象的创建和属性的访问。同时,HarmonyOS支持ETS(Enhanced TypeScript)文件,这是一种扩展了TypeScript的文件格式,用于更好地支持HarmonyOS的特性。然而,ETS文件并不支持所有的TypeScript语法特性,这就需要开发者灵活运用不同的文件格式来实现所需的功能。【完整示例】src/main/ets/common/FactoryUtil.ts123export function createInstance<T>(constructor: new () => T): T { return new constructor();} src/main/ets/pages/Index.ets123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100import { createInstance } from '../common/FactoryUtil.ts'; class Person { name: string = '张三';} class Person2 { name: string = '李四';} function sum(a: number, b: number) { console.info(`${a} + ${b} = ${a + b}`);} function subtract(a: number, b: number) { console.info(`${a} - ${b} = ${a - b}`);} function printString(str: string) { console.info(str);} class BirthInfo { birthDate: string = "2020-02-03";} class UserInfo { userName: string = ''; birthInfo?: BirthInfo = new BirthInfo(); calculateAge = (): number | string => { if (!this.birthInfo) { return '数据异常'; } const today = new Date(); const birthDate = new Date(this.birthInfo.birthDate); const age = today.getFullYear() - birthDate.getFullYear(); return age; };} class Action { description: string; action: Function; constructor(description: string, action: Function) { this.description = description; this.action = action; }} @Entry@Componentstruct MainPage { @State actions: Action[] = [ new Action('加法计算', sum), new Action('减法计算', subtract), new Action('打印字符串', printString), ]; build() { Column({ space: 10 }) { Button('创建对象并获取属性').onClick(() => { const person: object = Object({ name: '张三', age: 30 }); console.info(`person['name']:${person['name']}`); console.info(`person['age']:${person['age']}`); }); Button('执行动作').onClick(() => { this.actions.forEach(action => { if (action.description.includes('加法')) { action.action(1, 2); } else if (action.description.includes('减法')) { action.action(1, 2); } else if (action.description.includes('打印')) { action.action('Hello World'); } }); }); Button('从TS文件创建实例').onClick(() => { const person1 = createInstance(Person); console.info('person1.name', person1.name); const person2 = createInstance(Person2); console.info('person2.name', person2.name); }); Button('获取用户信息').onClick(() => { const userInfo = new UserInfo(); Object.keys(userInfo).forEach(key => { console.info(`key: ${key}`); }); console.info(`年龄: ${userInfo.calculateAge()}`); }); } .width('100%') .height('100%'); }} 打印1234567891011121314person['name']:张三person['age']:30 1 + 2 = 31 - 2 = -1Hello World person1.name 张三person2.name 李四 key: userNamekey: birthInfokey: calculateAge年龄: 4 技术要点解析1. 创建对象并获取属性使用Object()创建对象并使用索引访问属性,以确保兼容性与正确性。123const person:object = Object({ name: '张三', age: 30 });console.info(`person['name']:${person['name']}`);console.info(`person['age']:${person['age']}`); 2. 执行动作将方法定义为对象属性,并通过动态方式调用它们。123456this.actions.forEach(action => { if (action.description.includes('加法')) { action.action(1, 2); } // 其他条件分支...}); 3. 从TS文件创建实例在某些情况下,ETS文件不支持特定的TypeScript语法特性,如new () => T语法。这时可以将这部分逻辑移到TS文件中,并在ETS文件中导入使用。例如,创建一个通用的工厂函数来实例化类:12const person1 = createInstance(Person);console.info('person1.name', person1.name); 4. 遍历对象的属性可以使用Object.keys()遍历对象的属性,并利用面向对象的思想通过实例方法计算年龄。123456const userInfo = new UserInfo();Object.keys(userInfo).forEach(key => { console.info(`key: ${key}`);}); console.info(`年龄: ${userInfo.calculateAge()}`); 结论本文介绍了HarmonyOS应用开发中的几个关键技巧,包括使用Object()创建对象、动态调用方法、使用TS文件中的工厂函数创建实例,以及遍历对象属性。通过遵循良好的命名规范和代码组织结构,可以使代码更加清晰易懂,便于后期维护。掌握了这些技巧后,开发者能够更加高效地开发出高质量的HarmonyOS应用程序。转载自https://www.cnblogs.com/zhongcx/articles/18445830
-
/** * 根据比例混合两个十六进制颜色值。 * @param colorA 第一个颜色的十六进制值,例如红色 '#ff0000'。 * @param colorB 第二个颜色的十六进制值,例如黑色 '#000000'。 * @param ratio 混合比例,0 表示仅返回 colorA,1 表示仅返回 colorB,介于 0 和 1 之间的值会混合两个颜色。 * @returns 混合后的颜色的十六进制值。 */ function mixColors(colorA: string, colorB: string, ratio: number): string { let mix = (a: number, b: number, ratio: number) => Math.round(a + (b - a) * ratio).toString(16).padStart(2, '0'); let a = parseInt(colorA.slice(1), 16); let b = parseInt(colorB.slice(1), 16); let red = mix((a >> 16) & 255, (b >> 16) & 255, ratio); let green = mix((a >> 8) & 255, (b >> 8) & 255, ratio); let blue = mix(a & 255, b & 255, ratio); return `#${red}${green}${blue}`; } function convertDecimalColorToHex(decimalColorValue: number): string { if (decimalColorValue < 0 || decimalColorValue > 0xFFFFFFFF) { throw new Error('Color value must be within the range of 0 to 0xFFFFFFFF.'); } const paddedHexColor = ('00000000' + decimalColorValue.toString(16).toUpperCase()).slice(-8); return '#' + paddedHexColor.slice(-6); } @Entry @Component struct Index { @State resourceColor: Resource | undefined = undefined @State convertedColorHex: string = "" @State displayText: string = "测试测试" aboutToAppear(): void { this.resourceColor = $r(`app.color.start_window_background`); const colorFromResourceManager = getContext(this).resourceManager.getColorByNameSync('start_window_background'); console.info('从ResourceManager获取的颜色(十进制):', colorFromResourceManager); this.convertedColorHex = convertDecimalColorToHex(colorFromResourceManager); console.info('转换后的十六进制颜色:', this.convertedColorHex); } build() { Column() { Text('测试1').backgroundColor('rgba(0, 0, 0, 0.5)') Text('测试2').backgroundColor('#80000000') Text(mixColors('#ff0000', '#000000', 0)) .fontColor(Color.White) .backgroundColor(mixColors('#ff0000', '#000000', 0)) Text(mixColors('#ff0000', '#000000', 1)) .fontColor(Color.White) .backgroundColor(mixColors('#ff0000', '#000000', 1)) Text(mixColors('#ff0000', '#000000', 0.5)) .fontColor(Color.White) .backgroundColor(mixColors('#ff0000', '#000000', 0.5)) Text(mixColors('#ff0000', '#000000', 0.8)) .fontColor(Color.White) .backgroundColor(mixColors('#ff0000', '#000000', 0.8)) Text(this.displayText) .backgroundColor($r(`app.color.start_window_background`)) .fontSize(50) .fontWeight(FontWeight.Bold) Text(this.displayText) .backgroundColor(this.resourceColor) .fontSize(50) .fontWeight(FontWeight.Bold) Text(this.displayText) .backgroundColor(this.convertedColorHex) .fontSize(50) .fontWeight(FontWeight.Bold) } .height('100%') .width('100%') .backgroundColor(Color.Orange) } }在HarmonyOS应用开发中,颜色设置是一项基本但重要的功能。本文将介绍在ArkTS中如何设置颜色的透明度,并探讨如何在两种颜色之间进行混合以得到新的颜色值。一、设置颜色透明度在HarmonyOS的ArkTS框架中,可以通过多种方式来设置颜色的透明度。以下是两种常见的方法:1. 使用RGBA格式:通过直接指定RGBA值来设置颜色的透明度。1Text('测试1').backgroundColor('rgba(0, 0, 0, 0.5)')2. 使用十六进制颜色值:通过在颜色值前加上表示透明度的十六进制数来设置透明度。1Text('测试2').backgroundColor('#80000000')在此示例中,80表示半透明,00表示不透明,ff表示完全透明。二、颜色混合方案在一些应用场景中,需要实现两种颜色之间的混合效果。下面是一个示例,演示如何根据给定的比例混合两种颜色:/** * 根据比例混合两个十六进制颜色值。 * @param colorA 第一个颜色的十六进制值,例如红色 '#ff0000'。 * @param colorB 第二个颜色的十六进制值,例如黑色 '#000000'。 * @param ratio 混合比例,0 表示仅返回 colorA,1 表示仅返回 colorB,介于 0 和 1 之间的值会混合两个颜色。 * @returns 混合后的颜色的十六进制值。 */ mixColors(colorA: string, colorB: string, ratio: number): string { let mix = (a: number, b: number, ratio: number) => Math.round(a + (b - a) * ratio).toString(16).padStart(2, '0'); let a = parseInt(colorA.slice(1), 16); let b = parseInt(colorB.slice(1), 16); let red = mix((a >> 16) & 255, (b >> 16) & 255, ratio); let green = mix((a >> 8) & 255, (b >> 8) & 255, ratio); let blue = mix(a & 255, b & 255, ratio); return `#${red}${green}${blue}`; }三、解决预览器颜色显示问题在使用resourceManager获取颜色值时,可能会遇到在预览器中无法正确显示颜色的问题。为了避免这类问题,建议直接定义颜色常量:如果只是简单的颜色值,建议直接定义字符串类颜色值,如"#000000",这样预览器也能正确显示颜色转载自https://www.cnblogs.com/zhongcx/articles/18447243
-
引言在特殊情况下,如国难日或其他重要事件期间,应用程序可能需要将界面转换为灰度显示以示尊重或表达特定的情感。比如android环境下的代码为12345Paint paint = new Paint();ColorMatrix cm = new ColorMatrix();cm.setSaturation( 0);//0:表示灰度显示,1:表示彩色显示paint.setColorFilter(new ColorMatrixColorFilter(cm));view.setLayerType(View.LAYER_TYPE_HARDWARE, paint); 方案一:使用 saturate 属性通过设置页面根容器的饱和度为0来实现灰度效果:123456789101112131415@Entry@Componentstruct Index { build() { Column() { Image($r("app.media.app_icon")) .autoResize(true) .width(100) .height(100) } .width('100%') .height('100%') .saturate(0) }} 方案二:使用 grayscale 属性通过设置页面根容器的灰度效果为1来实现灰度效果:123456789101112131415@Entry@Componentstruct Index { build() { Column() { Image($r("app.media.app_icon")) .autoResize(true) .width(100) .height(100) } .width('100%') .height('100%') .grayscale(1) }}转载自https://www.cnblogs.com/zhongcx/articles/18447277
-
@Entry @Component struct Page11 { @State message: string = 'Hello World'; build() { Column() { Row(){ Text("呵呵").flexGrow(1).backgroundColor(Color.Red) Text("呵呵").flexGrow(1).backgroundColor(Color.Blue) } Flex(){ Text("呵呵").layoutWeight(1).backgroundColor(Color.Red) Text("呵呵").flexGrow(1).backgroundColor(Color.Blue) } Flex(){ Text("呵呵").flexGrow(1).backgroundColor(Color.Red) Text("呵呵呵呵呵呵呵呵呵呵").flexGrow(1).backgroundColor(Color.Blue) }.width('100%') Flex(){ Text("呵呵").layoutWeight(1).backgroundColor(Color.Red) Text("呵呵呵呵呵呵呵呵呵呵").layoutWeight(1).backgroundColor(Color.Blue) }.width('100%') } .height('100%') .width('100%') } }引言在HarmonyOS的应用开发过程中,我们需要对不同类型的布局属性有所了解,以便更好地组织和管理我们的界面。本文将探讨两种重要的布局属性:flexGrow 和 .layoutWeight,并分析它们之间的区别以及各自的适用场景。1. 使用场景flexGrow 是一种Flex容器特有的布局属性,它决定了子元素如何根据剩余空间进行扩展。.layoutWeight 则可以在 Flex、Row 和 Column 等多种容器中使用,更加灵活。2. 混合使用如果在非 Flex 容器中同时使用 flexGrow 和 .layoutWeight,则只有 .layoutWeight 起作用。这是因为 flexGrow 只在 Flex 容器中有意义,而 .layoutWeight 的兼容性更强。3. 分配方式flexGrow 根据每个子元素的权重分配剩余空间,但会优先保留子元素自身的宽度。例如,在有两个子元素的 Flex 容器中,如果两者都设置了 flexGrow: 1,那么它们将平均分配剩余空间。然而,如果其中某个子元素的内容较长,则实际宽度可能会大于另一个。相比之下,.layoutWeight 根据每个子元素的权重分配整个组件的宽度。这意味着具有相同权重的子元素将获得相同的宽度,无论其内容长度如何。4. 推荐使用由于 .layoutWeight 具有简单直观的宽度分配方式,因此在需要均匀分配空间的情况下,推荐使用此属性。转载自https://www.cnblogs.com/zhongcx/articles/18447321
-
import { systemDateTime } from '@kit.BasicServicesKit'; @Entry @Component struct Index { @State formattedTimeNow: string = ""; @State formattedTimeAgo: string = ""; @State timestampSecs: string = ""; @State timestampSecsAlt: string = ""; @State fullDateTime: string = ""; @State nanosecondsTimestamp: string = ""; @State timezoneOffsetHours: string = ""; @State currentDate: string = ""; @State formattedSpecifiedDateTime: string = ""; formatTimeAgo(dateTime: Date): string { const now = new Date(); const diff = now.getTime() - dateTime.getTime(); const SECONDS = 1000; const MINUTES = SECONDS * 60; const HOURS = MINUTES * 60; const DAYS = HOURS * 24; if (diff < SECONDS) { return '刚刚'; } else if (diff < MINUTES) { return '不到一分钟'; } else if (diff < HOURS) { return Math.round(diff / MINUTES) + '分钟前'; } else if (diff < DAYS) { return Math.round(diff / HOURS) + '小时前'; } else if (diff < DAYS * 2) { return '昨天'; } else if (diff < DAYS * 3) { return '前天'; } else { return this.formatDate(dateTime); } } formatDate(dateTime: Date): string { const year = dateTime.getFullYear(); const month = String(dateTime.getMonth() + 1).padStart(2, '0'); const day = String(dateTime.getDate()).padStart(2, '0'); return `${year}年${month}月${day}日`; } getFullDateTime(): string { const formatter = new Intl.DateTimeFormat('zh-CN', { year: 'numeric', month: '2-digit', day: '2-digit', hour: '2-digit', minute: '2-digit', second: '2-digit' }); return formatter.format(new Date()); } formatCustomDateTime(dateTime: Date): string { const formatter = new Intl.DateTimeFormat('zh-CN', { year: 'numeric', month: '2-digit', day: '2-digit' }); const parts = formatter.formatToParts(dateTime); let formattedDate = ''; for (const part of parts) { switch (part.type) { case 'month': formattedDate += `${part.value}月`; break; case 'day': formattedDate += `${part.value}日`; break; case 'year': formattedDate = `${part.value}年${formattedDate}`; break; default: break; } } return formattedDate; } getFormattedSpecifiedDateTime(dateTime: Date): string { return this.formatCustomDateTime(dateTime); } getNanosecondsTimestamp(): void { const time = systemDateTime.getTime(true); this.nanosecondsTimestamp = time.toString(); } getTimezoneOffsetHours(): void { try { const now = new Date(); const offsetMinutes = now.getTimezoneOffset(); const offsetHours = Math.floor(-offsetMinutes / 60); this.timezoneOffsetHours = offsetHours.toString(); } catch (error) { console.error('获取时区偏移量失败:', error); this.timezoneOffsetHours = '未知'; } } getCurrentYearMonthDay(): string { const date = new Date(); const year = date.getFullYear(); const month = String(date.getMonth() + 1).padStart(2, '0'); const day = String(date.getDate()).padStart(2, '0'); return `${year}年${month}月${day}日`; } build() { Column({ space: 10 }) { Button('获取当前时间戳(秒)').onClick(() => { this.timestampSecs = Math.floor(Date.now() / 1000).toString() this.timestampSecsAlt = Math.floor(new Date().getTime() / 1000).toString() }) Text(`当前时间戳(秒):${this.timestampSecs}`) Text(`当前时间戳(秒):${this.timestampSecsAlt}`) Button('获取当前时间戳(纳秒)').onClick(() => { this.getNanosecondsTimestamp(); }) Text(`当前时间戳(纳秒):${this.nanosecondsTimestamp}`) Button('获取时间间隔显示').onClick(() => { this.formattedTimeNow = this.formatTimeAgo(new Date()); this.formattedTimeAgo = this.formatTimeAgo(new Date('2023-04-01T12:00:00')); }) Text(`当前时间间隔显示:${this.formattedTimeNow}`) Text(`指定时间间隔显示:${this.formattedTimeAgo}`) Button('获取当前时区偏移量').onClick(() => { this.getTimezoneOffsetHours(); }) Text(`当前时区偏移量:${this.timezoneOffsetHours}小时`) Button('获取当前年-月-日').onClick(() => { this.currentDate = this.getCurrentYearMonthDay(); }) Text(`当前年-月-日:${this.currentDate}`) Button('获取当前完整时间').onClick(() => { this.fullDateTime = this.getFullDateTime(); }) Text(`当前完整时间:${this.fullDateTime}`) Button('获取指定日期时间').onClick(() => { this.formattedSpecifiedDateTime = this.getFormattedSpecifiedDateTime(new Date('2024-10-02T09:30:00')); }) Text(`指定日期时间:${this.formattedSpecifiedDateTime}`) } .width('100%') .height('100%') } }转载自https://www.cnblogs.com/zhongcx/articles/18447576
-
在鸿蒙系统中,为了给用户带来更加生动的视觉体验,我们可以使用不同的技术手段来实现图像和文字的镂空效果。本文将通过三个具体的示例来展示如何在鸿蒙系统中实现实心矩形镂空、实心圆镂空以及文字镂空的效果。示例代码// 定义一个名为Index的应用入口组件 @Entry @Component struct Index { // 初始化绘图上下文所需的设置 private settings: RenderingContextSettings = new RenderingContextSettings(true); // 创建两个用于绘制不同图案的Canvas绘图上下文 private contextForRectangle: CanvasRenderingContext2D = new CanvasRenderingContext2D(this.settings); private contextForCircle: CanvasRenderingContext2D = new CanvasRenderingContext2D(this.settings); // 构建UI build() { // 使用Column布局,设置每个子元素之间的间隔为5 Column({ space: 5 }) { // 第一个示例:实心矩形镂空 Text('1. 实心矩形镂空') Stack() { // 在Stack中放置一个图像作为背景 Image($r('app.media.startIcon')).width(200).height(200).enableAnalyzer(true) // 创建一个Canvas,并在准备就绪后执行绘图逻辑 Canvas(this.contextForRectangle).width(80).height(80).backgroundColor(undefined).onReady(async () => { // 设置填充色 this.contextForRectangle.fillStyle = 'rgba(0, 255, 255, 1)'; // 绘制一个覆盖整个Canvas的矩形 this.contextForRectangle.fillRect(0, 0, 80, 80); // 在矩形中心位置创建一个镂空矩形 this.contextForRectangle.clearRect(10, 20, 50, 40); }); }.width(300) // 第二个示例:实心圆镂空 Text('2. 实心圆镂空') Stack() { Image($r('app.media.startIcon')).width(200).height(200).enableAnalyzer(true) // 创建一个Canvas,并在准备就绪后执行绘图逻辑 Canvas(this.contextForCircle).width(80).height(80).backgroundColor(undefined).onReady(async () => { // 清除背景 this.contextForCircle.clearRect(0, 0, 80, 80); // 设置填充色 this.contextForCircle.fillStyle = 'rgba(0, 255, 255, 1)'; // 绘制一个覆盖整个Canvas的矩形 this.contextForCircle.fillRect(0, 0, 80, 80); // 画一个圆形镂空 this.contextForCircle.beginPath(); this.contextForCircle.arc(40, 40, 30, 0, Math.PI * 2); // 圆心坐标为(40, 40),半径为30 this.contextForCircle.globalCompositeOperation = 'destination-out'; this.contextForCircle.fill(); }); } // 第三个示例:文字镂空 Text('3. 文字镂空') Stack() { // 背景图像 Image($r('app.media.startIcon')).width(200).height(200).enableAnalyzer(true) Stack() { // 在内部Stack中绘制镂空文字 Text('鸿蒙') .fontSize(30) .fontWeight(FontWeight.Bold) .blendMode(BlendMode.XOR, BlendApplyType.OFFSCREEN) }.blendMode(BlendMode.SRC_OVER, BlendApplyType.OFFSCREEN) .backgroundColor('rgba(0, 255, 255, 1)') .width(80).height(80) }.width(200).height(200) }.width('100%') } }案例解析1. 实心矩形镂空在这个例子中,我们首先创建了一个Canvas实例,并在准备好后绘制了一个完全覆盖Canvas的矩形。接着,我们在该矩形的中央清除了一块矩形区域,从而实现了矩形镂空的效果。2. 实心圆镂空对于圆形镂空,我们同样先绘制一个覆盖整个Canvas的矩形,然后在一个新路径中绘制圆形并设置 globalCompositeOperation 为 'destination-out',这样就会在矩形中挖出一个圆形的镂空。3. 文字镂空最后,在文字镂空的例子中,我们先绘制了一个背景图像,然后在图像上绘制了“鸿蒙”这两个字。通过设置 blendMode 为 'XOR' 和 'SRC_OVER',使得文字呈现镂空效果。转载自https://www.cnblogs.com/zhongcx/articles/18448377
-
在设计应用界面时,我们常常需要对某些重要的文本进行高亮显示,以引起用户的注意。同时,在一些场景中,我们需要确保长文本能够自动换行,以适应不同的屏幕尺寸和布局需求。本文将通过两个示例,分别展示如何在HarmonyOS应用中实现这些功能。【示例一】文本高亮显示@Entry @Component struct Page01 { @State originalText: string = '混沌未分天地乱,茫茫渺渺无人见。自从盘古破鸿蒙,开辟从兹清浊辨。'; @State highlightKeyword: string = '鸿蒙'; // 需要高亮显示的关键字 @State highlightedSegments: string[] = []; // 分割原始文本并保留关键字 private splitAndHighlight(text: string, keyword: string): string[] { let segments: string[] = []; let lastMatchEnd: number = 0; while (true) { const matchIndex = text.indexOf(keyword, lastMatchEnd); if (matchIndex === -1) { segments.push(text.slice(lastMatchEnd)); break; } else { segments.push(text.slice(lastMatchEnd, matchIndex)); segments.push(text.slice(matchIndex, matchIndex + keyword.length)); lastMatchEnd = matchIndex + keyword.length; } } return segments; } // 页面即将出现时进行文本分割 aboutToAppear() { this.highlightedSegments = this.splitAndHighlight(this.originalText, this.highlightKeyword); console.info(`分割后的文本段落:${JSON.stringify(this.highlightedSegments)}`); } build() { Column({ space: 20 }) { Text() { ForEach(this.highlightedSegments, (segment: string, index: number) => { ContainerSpan() { ImageSpan($r('app.media.app_icon')).width(0).height(1); Span(segment).fontSize(30) .fontColor(segment === this.highlightKeyword ? Color.White : Color.Black) .onClick(() => { console.info(`高亮文本被点击:${segment}`); console.info(`点击索引:${index}`); }); }.textBackgroundStyle({ color: segment === this.highlightKeyword ? Color.Red : Color.Transparent }); }); } }.width('100%').height('100%'); } }在这个示例中,我们首先定义了一个字符串originalText作为原始文本,并指定了需要高亮显示的关键字highlightKeyword。然后,我们定义了一个splitAndHighlight函数来分割原始文本,并将包含关键字的部分与其他部分分开。在页面加载时,我们调用这个函数来获得分割后的文本段落,并使用Span组件来显示文本。需要注意的是,由于Span组件本身不支持直接设置背景颜色(即Span不支持.backgroundColor(Color.Orange)),因此设置背景色需要在Span外部嵌套ContainerSpan组件,并使用textBackgroundStyle属性来实现。对于需要高亮显示的关键字部分,我们通过ContainerSpan组件的textBackgroundStyle属性来改变其背景颜色,同时保持字体颜色为白色,以确保高亮效果明显。【示例二】文本自动换行接下来,我们来看一个文本自动换行的示例。在这个例子中,我们需要将多行文本按照一定的规则自动换行。@Entry @Component struct Page02 { @State poemLines: string[] = [ '混沌未分天地乱,', '茫茫渺渺无人见。', '自从盘古破鸿蒙,', '开辟从兹清浊辨。', ]; build() { Column({ space: 10 }) { Text('Text + Span,文本无法自动换行').backgroundColor(Color.Orange); Text() { ForEach(this.poemLines, (line: string) => { Span(line); }); } .fontSize(20); Text('Flex + Span,可以实现文本换行').backgroundColor(Color.Orange); Flex({ wrap: FlexWrap.Wrap }) { ForEach(this.poemLines, (line: string) => { Text(line).fontSize(20); }); } } .width('100%').height('100%'); } }在这个示例中,我们定义了一个字符串数组poemLines,其中包含了多行诗句。我们展示了两种不同的方式来显示这些诗句:一种是使用Text和Span组件直接显示,这种方式默认不会自动换行;另一种是使用Flex容器,并设置wrap属性为FlexWrap.Wrap,这样可以使得子元素在超出容器宽度时自动换行。【技术要点总结】1. 文本高亮:• 使用splitAndHighlight函数分割文本,并标记关键字。• 使用ContainerSpan和Span组件组合实现背景高亮。• 注意Span不支持直接设置背景颜色,需通过ContainerSpan的textBackgroundStyle属性实现。2. 文本换行:• 使用Flex容器并设置wrap属性为FlexWrap.Wrap,实现自动换行。• 多行文本可以通过ForEach循环动态生成。
-
在鸿蒙系统(HarmonyOS)的应用开发中,有时需要提供退出应用的功能。鸿蒙系统提供了多种方法来实现这一目标,包括 terminateSelf()、killAllProcesses() 和 clearUpApplicationData()。本文将详细介绍这些方法及其适用场景,并提供一种较为优雅的退出应用的方式,以提升用户体验。退出应用的方法方案一:terminateSelf()描述terminateSelf() 方法用于停止当前 Ability 自身。这是一种较为常见的退出方式,适用于那些只有一个 Activity 或者 Ability 的应用。用法在 EntryAbility 中使用:this.context.terminateSelf();在 Pages 页面中使用:import { common } from '@kit.AbilityKit'; (getContext(this) as common.UIAbilityContext)?.terminateSelf();优点• 退出时有动画过渡,用户体验较好。• 适合单 Activity 或 Ability 应用。缺点• 仅能终止当前 Ability,对于多 Ability 应用可能不够用。方案二:killAllProcesses()描述killAllProcesses() 方法用于杀死应用所在的整个进程。这是一种更为激进的退出方式,会立即结束应用的所有活动。用法getContext(this).getApplicationContext().killAllProcesses();优点• 可以彻底结束应用的所有活动,适用于需要完全清理资源的场景。缺点• 无动画过渡,用户体验较差。• 可能会导致一些未保存的数据丢失。方案三:clearUpApplicationData()描述clearUpApplicationData() 方法用于清理应用本身的数据,并撤销应用向用户申请的权限。这是一种更为极端的退出方式,不仅终止了应用,还清除了所有应用数据。用法 getContext(this).getApplicationContext().clearUpApplicationData(); 优点• 清理了所有应用数据,适用于需要完全重置应用的状态。缺点• 退出时可能会有短暂的卡顿现象(大约 1-2 秒),用户体验不佳。• 清除数据的过程可能会导致一些副作用,如未保存的数据丢失。推荐方案推荐使用 terminateSelf() 方法来退出应用,因为它提供了动画过渡,用户体验较好。而对于需要清除应用数据并退出的情况,可以使用 clearUpApplicationData(),但在调用之前增加一个加载提示,以提高用户体验。示例代码 @Entry @Component struct Page03 { @State isExit: boolean = false build() { Stack() { Column({ space: 10 }) { Button('清除应用数据并退出APP').margin({ bottom: 200 }).onClick(() => { this.isExit = true setTimeout(() => { getContext(this).getApplicationContext().clearUpApplicationData() }, 500) }) } .width('100%') .height('100%') .justifyContent(FlexAlign.Center) Text('处理中...') .textAlign(TextAlign.Center) .visibility(this.isExit ? Visibility.Visible : Visibility.None) .width('200lpx') .fontColor("#ffffff") .height('200lpx') .backgroundColor("#80000000") .borderRadius(20) }.width('100%').height('100%') } }总结在鸿蒙系统中,根据应用的具体需求选择合适的退出方法非常重要。对于多数情况,推荐使用 terminateSelf() 来提供优雅的退出体验。而对于需要清除应用数据的情况,可以使用 clearUpApplicationData(),并在调用前加入加载提示,以避免用户感到困惑或不满。通过合理选择和设计,可以显著提升应用的整体用户体验。转载自https://www.cnblogs.com/zhongcx/articles/18442826
-
随着鸿蒙系统的不断更新迭代,新版DevEco Studio的预览器会有上下白色间距问题我们可以通过调用鸿蒙的API来修复这个问题。以下是如何手动调整界面以消除这些空白区域的方法:this.windowClass.setWindowLayoutFullScreen(true)这段代码会在页面加载时获取最后一个窗口并将其设为全屏模式,从而消除上下白色间距。实现全屏(沉浸式)页面与非全屏(非沉浸式)页面之间的跳转与切换为了实现全屏(沉浸式)页面与非全屏(非沉浸式)页面之间的无缝切换,我们可以使用鸿蒙的 ArkUI 库。以下是一个示例,展示了如何在两个页面之间进行切换,并保持全屏状态:全屏页面示例(Page01.ets)import { router, window } from '@kit.ArkUI'; @Entry @Component struct Page01 { windowClass?: window.Window async setFullScreen(flag: boolean) { if (!this.windowClass) { this.windowClass = await window.getLastWindow(getContext(this)) } this.windowClass.setWindowLayoutFullScreen(flag) } onPageShow(): void { this.setFullScreen(true) } onPageHide(): void { this.setFullScreen(false) } build() { Column() { Text('当前页全屏(沉浸式)').fontSize(30) Button('跳转到下一页').onClick(() => { router.pushUrl({ url: 'pages/Page02' }) }) } .height('100%') .width('100%') .justifyContent(FlexAlign.Center) .backgroundColor(Color.Orange) } }非全屏页面示例(Page02.ets)import { router } from '@kit.ArkUI' @Entry @Component struct Page65 { build() { Column() { Text('当前页非全屏(非沉浸式)').fontSize(30) Button('返回上一页').onClick(() => { router.back() }) } .height('100%') .width('100%') .justifyContent(FlexAlign.Center) .backgroundColor(Color.Blue) } }在这个例子中,我们定义了两个页面:一个是全屏页面(Page01),另一个是非全屏页面(Page02)。当用户点击“跳转到下一页”按钮时,页面会从全屏页面跳转到非全屏页面;而点击“返回上一页”按钮时,页面又会回到全屏页面。这样实现了全屏与非全屏页面之间的自由切换。注意,在全屏页面中,我们使用了 setFullScreen(true) 方法来开启全屏模式,而在非全屏页面中并没有设置全屏模式。这样就可以实现页面间的正常切换。结论通过上述方法,您可以轻松地解决DevEco预览器中的上下白色间距问题,并实现全屏沉浸式页面与非全屏页面之间的切换。鸿蒙系统提供了丰富的工具和库供开发者使用,帮助他们更好地控制应用程序的外观和行为。希望这篇文章能对您的鸿蒙系统开发工作有所帮助!转载自https://www.cnblogs.com/zhongcx/articles/18442825
-
在鸿蒙应用开发中,实现购物车功能并进行屏幕适配是一个常见的需求。通过侧滑删除、侧滑收藏和价格计算等功能,可以为用户提供便捷的购物体验。下面将介绍一个购物车示例的实现方法,并结合屏幕适配技术进行详细说明。示例代码解析以上代码实现了一个购物车功能的示例,包括商品展示、侧滑收藏、侧滑删除和价格计算等功能。通过定义BeanItem类和使用List和ListItem组件展示商品信息,同时通过swipeAction实现了侧滑收藏和侧滑删除的功能。在价格计算部分,通过遍历商品列表并计算总价,实现了价格的动态更新。屏幕适配技术应用在示例中,使用了lpx单位来设置字体大小、宽高等属性,以实现屏幕适配。通过合理设置单位和布局,可以在不同设备上实现一致的视觉效果和用户体验。同时,针对不同设备类型的展示效果,可以通过响应式布局和自适应布局进行调整,以适配不同屏幕尺寸和分辨率的设备。结语通过以上示例代码和屏幕适配技术的应用,可以为开发者提供一个实践的范例,帮助他们更好地理解和掌握鸿蒙应用的开发技巧。购物车功能作为一个常见的应用场景,结合屏幕适配技术的应用,可以为用户提供更加友好和一致的购物体验。通过合理使用不同单位和布局技术,可以有效地解决鸿蒙应用在不同设备上的屏幕适配问题,提供一致且优秀的用户体验。希望这篇文章能够帮助开发者更好地理解和掌握鸿蒙应用的屏幕适配技巧。以上是关于鸿蒙应用示例的相关介绍,希望对开发者在实际开发中有所帮助。import { promptAction } from '@kit.ArkUI' class BeanItem { name: string = "" price: number = 0 count: number = 0 img: string = '' constructor(name: string, price: number, count: number, img: string) { this.name = name this.price = price this.count = count this.img = img } } @Entry @Component struct test { @State dataArr: Array<BeanItem> = [ new BeanItem('苹果', 100, 0, 'https://s.boohee.cn/house/upload_food/2022/1/24/small_photo_url_83bdb4eb0c7f4ab9580d9ccff0bcdced.jpg'), new BeanItem('嘎啦果', 150, 0, 'https://s.boohee.cn/house/upload_food/2020/12/3/small_photo_url_f6a4dd01310addcf7e3e411915690b7a.jpg'), new BeanItem('苹果梨', 200, 0, 'https://s.boohee.cn/house/new_food/small/920d4a8b9c6149289cd9dc378830f551.jpg'), new BeanItem('苹果蕉', 50, 0, 'https://s.boohee.cn/house/upload_food/2021/7/7/small_photo_url_3bd7f3e283d2c6190c88dc6a84f2a17c.jpg'), new BeanItem('伏苹果', 48, 0, 'https://s.boohee.cn/house/new_food/small/aed4c667f79643e6ba3b756086124878.jpg'), new BeanItem('蒸苹果', 35, 0, 'https://s.boohee.cn/house/upload_food/2020/6/12/small_photo_url_90e4b6ab647f45029c52609296c1a7ac.jpg'), new BeanItem('旱苹果', 34, 0, 'https://s.boohee.cn/house/new_food/small/b255df59ed0149908bcf493a5f973c00.jpg'), new BeanItem('煮苹果', 70, 0, 'https://s.boohee.cn/house/upload_food/2021/7/23/small_photo_url_03.png'), new BeanItem('苹果酥', 157, 0, 'https://s.boohee.cn/house/upload_food/2021/7/23/small_photo_url_05.png'), new BeanItem('苹果糊', 53, 0, 'https://s.boohee.cn/house/upload_food/2019/7/19/small_photo_url_0329d3f0d77e104ebbf0c51d6e28b86c.jpg') ] @State priceCount: number = 0; getPriceCount() { let count = 0; for (let i = 0; i < this.dataArr.length; i++) { count += this.dataArr[i].count * this.dataArr[i].price } this.priceCount = count } @Builder itemStart(index: number) { Row() { Text('收藏').fontColor("#ffffff").fontSize('40lpx') .textAlign(TextAlign.Center) .width('180lpx') } .height('100%') .backgroundColor("#FFC107") .justifyContent(FlexAlign.SpaceEvenly) .borderRadius({ topLeft: 10, bottomLeft: 10 }) .onClick(() => { promptAction.showToast({ message: '【' + this.dataArr[index].name + '】收藏成功', duration: 2000, bottom: '400lpx' }); }) } @Builder itemEnd(index: number) { Row() { Text('删除').fontColor("#ffffff").fontSize('40lpx') .textAlign(TextAlign.Center) .width('180lpx') } .height('100%') .backgroundColor("#FF3D00") .justifyContent(FlexAlign.SpaceEvenly) .borderRadius({ topRight: 10, bottomRight: 10 }) .onClick(() => { promptAction.showToast({ message: '【' + this.dataArr[index].name + '】已删除', duration: 2000, bottom: '400lpx' }); this.dataArr.splice(index, 1) this.getPriceCount(); }) } build() { Column() { Text('购物车') .width('100%') .height('88lpx') .fontSize('38lpx') .backgroundColor("#ffffff") .textAlign(TextAlign.Center) List({ space: '44lpx' }) { ForEach(this.dataArr, (item: BeanItem, index: number) => { ListItem() { Row() { Image(item.img) .width('193lpx') .height('193lpx') .alt(item.img) .borderRadius(10) .padding('14lpx') Column() { Text(item.name) .fontSize('30lpx') .fontColor("#222B45") Text(item.price.toString() + '元') .fontSize("30lpx") .fontColor("#65DACC") Blank() Counter() { Text(item.count.toString()) .fontColor("#000000") .fontSize('26lpx') }.backgroundColor("#0F000000") .onInc(() => { item.count++ this.dataArr[index] = new BeanItem(item.name, item.price, item.count, item.img) this.getPriceCount() }) .onDec(() => { if (item.count == 0) { return; } item.count-- this.dataArr[index] = new BeanItem(item.name, item.price, item.count, item.img) this.getPriceCount() }) }.margin({ left: '56lpx' }) .height('167lpx') .alignItems(HorizontalAlign.Start) }.backgroundColor("#ffffff") .borderRadius(10) .width('100%') }.width('100%').margin({ top: index == 0 ? 20 : 0, bottom: index == this.dataArr.length - 1 ? 20 : 0 }) .swipeAction({ start: this.itemStart(index), end: this.itemEnd(index) }) }) } .width('648lpx') .layoutWeight(1) Row() { Column() { Text('合计').fontSize('26lpx').fontColor("#515C6F") Text(this.priceCount + '元').fontSize('38lpx').fontColor("#222B45") Text('免费送货') }.margin({ left: '50lpx' }) .justifyContent(FlexAlign.Start) .alignItems(HorizontalAlign.Start) .width('300lpx') Row() { Text('结账').fontColor("#FFFFFF").fontSize('28lpx') } .onClick(() => { promptAction.showToast({ message: '结算成功', duration: 2000, bottom: '400lpx' }); }) .width('316lpx') .height('88lpx') .backgroundColor("#65DACC") .borderRadius(10) .justifyContent(FlexAlign.Center) }.width('100%').height('192lpx').backgroundColor("#ffffff") } .backgroundColor("#F8FAFB") .width('100%') .height('100%') } }转载自https://www.cnblogs.com/zhongcx/articles/18441745
-
新年新技能,云学堂开发者认证学习等你来挑战。丰富的云实验带你快速体验华为云服务,轻松完成云上实践!涵盖了AI、鸿蒙、欧拉、GaussDB、云技术精髓等各项技术领域的课程、实战和认证一体化学习,帮助大家从入门到进阶,考证还可赢取专属奖励,云学堂助你成为更好的开发者!立即报名:cid:link_0福利一:分享有礼,邀请好友报名领取100-500元云资源券福利二:完成任意云实验抽好礼(云宝盲盒、定制帆布包、水杯)福利三:考证有礼,考取任意微认证和开发者认证可领取专属礼品,实物奖品、云资源代金券任你选择
-
2024年8月3日,全国高校计算机类课程能力提升高级研修班第六期在华为上海研究所举行。来自西安交通大学的谢涛老师作了题为“基于OpenHarmony的Web编程技术及应用开发基础”的课程改革经验分享。谢涛老师分别从OpenHarmony概述及开发环境部署、两个OpenHarmony应用开发案例(查查词典、辞艺)等方面阐述了基于OpenHarmony的Web编程技术及应用开发的课程改革情况及实践效果,最后带领全体老师一起体验了AppGallery Connect 云数据库的连接实例。
-
HarmonyOS 项目 API 使用注意事项总结1.手动导包的重要性:* 自动导包(Alt + 回车)并不总是有效,某些包需要手动输入。例如:import fs from '@ohos.file.fs'; // 需手动输入2.使用 @Kit:* 从 API 12 开始,使用 @Kit 替代 @ohos。许多论坛资料仍使用 @ohos,可能导致功能不显示。例如:要把import hilog from '@ohos.hilog'; import deviceInfo from '@ohos.deviceInfo';改为import { hilog } from '@kit.PerformanceAnalysisKit'; import { deviceInfo } from '@kit.BasicServicesKit'; * 新建 API 12 项目时,查找资料时遇到 @ohos,请参考官方文档确认对应的 @Kit 版本。3.注意手机版本:* Beta 1 和 Beta 3 之间差异显著,尽管代码在 API 12 下不报错,但在真机上可能会出现错误。确保真机版本升级到 Beta 3 以上,官方文档可能未提供相关提示。常用 API 导入示例// 日志系统import { hilog } from '@kit.PerformanceAnalysisKit';// Web 控制能力import { webview } from '@kit.ArkWeb';// 图片处理import { image } from '@kit.ImageKit';// 相册管理import { photoAccessHelper } from '@kit.MediaLibraryKit';// 呼叫管理import { call } from '@kit.TelephonyKit';// 资源管理import { resourceManager } from '@kit.LocalizationKit';// 分享功能import { systemShare } from '@kit.ShareKit';// 用户首选项import { preferences } from '@kit.ArkData';// 事件处理import { emitter } from '@kit.BasicServicesKit';// 文件操作import { fileIo as fs } from '@kit.CoreFileKit';// 网络连接管理import { connection } from '@kit.NetworkKit';// 扫码功能import { scanBarcode } from '@kit.ScanKit';// 设备信息import { deviceInfo } from '@kit.BasicServicesKit';// 剪贴板管理import { pasteboard } from '@kit.BasicServicesKit';// 窗口管理import { window } from '@kit.ArkUI';// 动画插值曲线import { curves } from '@kit.ArkUI';// 组件内容封装import { ComponentContent } from '@kit.ArkUI';// 提示框import { promptAction } from '@kit.ArkUI';// 路由管理import { router } from '@kit.ArkUI';// 页签型标题栏import { TabTitleBar } from '@kit.ArkUI';示例代码// @ohos全面替换 @kit //hilog日志系统,使应用/服务可以按照指定级别、标识和格式字符串输出日志内容,帮助开发者了解应用/服务的运行状态,更好地调试程序。import { hilog } from '@kit.PerformanceAnalysisKit';//@ohos.web.webview提供web控制能力,Web组件提供网页显示的能力。访问在线网页时需添加网络权限:ohos.permission.INTERNET,具体申请方式请参考声明权限。import { webview } from '@kit.ArkWeb';//本模块提供图片处理效果,包括通过属性创建PixelMap、读取图像像素数据、读取区域内的图片数据等。import { image } from '@kit.ImageKit';//该模块提供相册管理模块能力,包括创建相册以及访问、修改相册中的媒体数据信息等。import { photoAccessHelper } from '@kit.MediaLibraryKit';//该模块提供呼叫管理功能,包括拨打电话、跳转到拨号界面、获取通话状态、格式化电话号码等。import { call } from '@kit.TelephonyKit';//资源管理模块,根据当前configuration:语言、区域、横竖屏、Mcc(移动国家码)和Mnc(移动网络码)、Device capability(设备类型)、Density(分辨率)提供获取应用资源信息读取接口。import { resourceManager } from '@kit.LocalizationKit'//本模块提供分享数据创建及分享面板拉起的功能,提供多种系统标准分享服务,例如分享数据给其他应用、复制、打印等。//// 分享接入应用需要配置、呈现和关闭分享面板。// 分享面板的配置包括数据对象、呈现视图的方式、预览方式等。import { systemShare } from '@kit.ShareKit';//本模块对标准化数据类型进行了抽象定义与描述。import { uniformTypeDescriptor as utd } from '@kit.ArkData';//@ohos.data.preferences (用户首选项)用户首选项为应用提供Key-Value键值型的数据处理能力,支持应用持久化轻量级数据,并对其修改和查询。//// 数据存储形式为键值对,键的类型为字符串型,值的存储数据类型包括数字型、字符型、布尔型以及这3种类型的数组类型。import { preferences } from '@kit.ArkData';//错误信息打印import { BusinessError } from '@kit.BasicServicesKit';//开发者可以通过该模块引用Ability公共模块类。import { common } from '@kit.AbilityKit';//需要校验的权限名称,合法的权限名取值可在应用权限列表中查询。import { Permissions } from '@kit.AbilityKit';//UIAbility是包含UI界面的应用组件,继承自Ability,提供组件创建、销毁、前后台切换等生命周期回调,同时也具备组件协同的能力,组件协同主要提供如下常用功能:import { UIAbility } from '@kit.AbilityKit';//本模块提供应用信息查询能力,支持BundleInfo、ApplicationInfo、AbilityInfo、ExtensionAbilityInfo等信息的查询。import { bundleManager } from '@kit.AbilityKit';//Want是对象间信息传递的载体, 可以用于应用组件间的信息传递。 Want的使用场景之一是作为startAbility的参数, 其包含了指定的启动目标, 以及启动时需携带的相关数据, 如bundleName和abilityName字段分别指明目标Ability所在应用的Bundle名称以及对应包内的Ability名称。当Ability A需要启动Ability B并传入一些数据时, 可使用Want作为载体将这些数据传递给Ability B。import { Want } from '@kit.AbilityKit';//本模块提供HTTP数据请求能力。应用可以通过HTTP发起一个数据请求,支持常见的GET、POST、OPTIONS、HEAD、PUT、DELETE、TRACE、CONNECT方法。import { http } from '@kit.NetworkKit';//网络连接管理提供管理网络一些基础能力,包括获取默认激活的数据网络、获取所有激活数据网络列表、开启关闭飞行模式、获取网络能力信息等功能。import { connection } from '@kit.NetworkKit';//本模块提供默认界面扫码能力。import { scanBarcode } from '@kit.ScanKit'//本模块提供扫码公共信息。import { scanCore } from '@kit.ScanKit'//本模块提供终端设备信息查询,开发者不可配置。其中deviceInfo.marketNames可以获取设备名称,比如mate60import { deviceInfo } from '@kit.BasicServicesKit';//本模块提供了在同一进程不同线程间,或同一进程同一线程内,发送和处理事件的能力,包括持续订阅事件、单次订阅事件、取消订阅事件,以及发送事件到事件队列的能力。import { emitter } from '@kit.BasicServicesKit';//本模块主要提供管理系统剪贴板的能力,为系统复制、粘贴功能提供支持。系统剪贴板支持对文本、HTML、URI、Want、PixelMap等内容的操作。import { pasteboard } from '@kit.BasicServicesKit';//该模块为基础文件操作API,提供基础文件操作能力,包括文件基本管理、文件目录管理、文件信息统计、文件流式读写等常用功能。import { fileIo as fs } from '@kit.CoreFileKit';//该模块提供空间查询相关的常用功能:包括对内外卡的空间查询,对应用分类数据统计的查询,对应用数据的查询等。import { storageStatistics } from '@kit.CoreFileKit';//选择器(Picker)是一个封装PhotoViewPicker、DocumentViewPicker、AudioViewPicker等API模块,具有选择与保存的能力。应用可以自行选择使用哪种API实现文件选择和文件保存的功能。该类接口,需要应用在界面UIAbility中调用,否则无法拉起photoPicker应用或FilePicker应用。import { picker } from '@kit.CoreFileKit';//本模块提供设置动画插值曲线功能,用于构造阶梯曲线对象、构造三阶贝塞尔曲线对象和构造弹簧曲线对象。import { curves } from '@kit.ArkUI';//ComponentContent表示组件内容的实体封装,其对象支持在非UI组件中创建与传递,便于开发者对弹窗类组件进行解耦封装。ComponentContent底层使用了BuilderNode,相关使用规格参考BuilderNode。import { ComponentContent } from '@kit.ArkUI';//用于设置长度属性,当长度单位为PERCENT时,值为1表示100%。import { LengthMetrics } from '@kit.ArkUI';//创建并显示文本提示框、对话框和操作菜单。import { promptAction } from '@kit.ArkUI';//窗口提供管理窗口的一些基础能力,包括对当前窗口的创建、销毁、各属性设置,以及对各窗口间的管理调度。//// 该模块提供以下窗口相关的常用功能://// Window:当前窗口实例,窗口管理器管理的基本单元。// WindowStage:窗口管理器。管理各个基本窗口单元。import { window } from '@kit.ArkUI';//一种普通标题栏,支持设置标题、头像(可选)和副标题(可选),可用于一级页面、二级及其以上界面配置返回键。import { ComposeTitleBar } from '@kit.ArkUI';//本模块提供通过不同的url访问不同的页面,包括跳转到应用内的指定页面、同应用内的某个页面替换当前页面、返回上一页面或指定的页面等。//// 推荐使用Navigation组件作为应用路由框架。import { router } from '@kit.ArkUI';//页签型标题栏,用于页面之间的切换。仅一级页面适用。import { TabTitleBar } from '@kit.ArkUI'; class MyUIAbility extends UIAbility {} @Builderfunction buildText(params: object) { Column() { }.backgroundColor('#FFF0F0F0')} @Entry@Componentstruct Page14 { controller: webview.WebviewController = new webview.WebviewController(); test() { router.pushUrl({ url: 'pages/routerpage2' }) let config: window.Configuration = { name: "test", windowType: window.WindowType.TYPE_DIALOG, ctx: getContext() }; let promise = window.createWindow(config); try { promptAction.showToast({ message: 'Hello World', duration: 2000 }); } catch (error) { let message = (error as BusinessError).message let code = (error as BusinessError).code console.error(`showToast args error code is ${code}, message is ${message}`); } ; } aboutToAppear(): void { LengthMetrics.vp(3) let uiContext = this.getUIContext(); let promptAction = uiContext.getPromptAction(); let contentNode = new ComponentContent(uiContext, wrapBuilder(buildText), Object); curves.initCurve(Curve.EaseIn) // 创建一个默认先慢后快插值曲线 let documentPicker = new picker.DocumentViewPicker(getContext()); storageStatistics.getCurrentBundleStats().then((BundleStats: storageStatistics.BundleStats) => { console.info("getCurrentBundleStats successfully:" + JSON.stringify(BundleStats)); }).catch((err: BusinessError) => { console.error("getCurrentBundleStats failed with error:" + JSON.stringify(err)); }); let filePath = "pathDir/test.txt"; fs.stat(filePath).then((stat: fs.Stat) => { console.info("get file info succeed, the size of file is " + stat.size); }).catch((err: BusinessError) => { console.error("get file info failed with error message: " + err.message + ", error code: " + err.code); }); let dataXml = new ArrayBuffer(256); let pasteData: pasteboard.PasteData = pasteboard.createData('app/xml', dataXml); let innerEvent: emitter.InnerEvent = { eventId: 1 }; console.info(`marketName:${deviceInfo.marketName}`) let netConnection = connection.createNetConnection(); http.RequestMethod.POST hilog.isLoggable(0x0001, "testTag", hilog.LogLevel.INFO); const color: ArrayBuffer = new ArrayBuffer(96); // 96为需要创建的像素buffer大小,取值为:height * width *4 let opts: image.InitializationOptions = { editable: true, pixelFormat: 3, size: { height: 4, width: 6 } } image.createPixelMap(color, opts).then((pixelMap: image.PixelMap) => { console.info('Succeeded in creating pixelmap.'); }).catch((error: BusinessError) => { console.error(`Failed to create pixelmap. code is ${error.code}, message is ${error.message}`); }) //此处获取的phAccessHelper实例为全局对象,后续使用到phAccessHelper的地方默认为使用此处获取的对象,如未添加此段代码报phAccessHelper未定义的错误请自行添加 let context = getContext(this); let phAccessHelper = photoAccessHelper.getPhotoAccessHelper(context); call.makeCall("138xxxxxxxx", (err: BusinessError) => { if (err) { console.error(`makeCall fail, err->${JSON.stringify(err)}`); } else { console.log(`makeCall success`); } }); let systemResourceManager = resourceManager.getSystemResourceManager(); let data: systemShare.SharedData = new systemShare.SharedData({ utd: utd.UniformDataType.PLAIN_TEXT, content: 'Hello HarmonyOS' }); preferences.getPreferencesSync(getContext(), { name: 'myStore' }) let uiAbilityContext: common.UIAbilityContext; let permissionName: Permissions = 'ohos.permission.GRANT_SENSITIVE_PERMISSIONS'; let bundleFlags = bundleManager.BundleFlag.GET_BUNDLE_INFO_WITH_APPLICATION | bundleManager.BundleFlag.GET_BUNDLE_INFO_WITH_METADATA; let want: Want = { deviceId: '', // deviceId为空表示本设备 bundleName: 'com.example.myapplication', abilityName: 'EntryAbility', moduleName: 'entry' // moduleName非必选 }; // 定义扫码参数options let options: scanBarcode.ScanOptions = { scanTypes: [scanCore.ScanType.ALL], enableMultiMode: true, enableAlbum: true }; // 可调用getContext接口获取当前页面关联的UIAbilityContext scanBarcode.startScanForResult(context, options, (error: BusinessError, result: scanBarcode.ScanResult) => { }) } build() { Column() { ComposeTitleBar({ title: "标题", subtitle: "副标题", }) TabTitleBar({ // swiperContent: this.componentBuilder, // tabItems: this.tabItems, // menuItems: this.menuItems, }) } .height('100%') .width('100%') }}转载自https://www.cnblogs.com/zhongcx/articles/18440601
-
在项目中使用的系统组件和属性总结如下:使用的系统组件:1.Column:纵向布局容器,用于垂直排列子组件。2.Row:横向布局容器,用于水平排列子组件。3.Stack:层叠布局容器,用于将子组件层叠显示。4.Flex:弹性布局容器,用于创建灵活的布局。5.Scroll:滚动布局容器,用于实现滚动效果。6.Image:图片组件,用于显示图片内容。7.Text:文本组件,用于显示文本内容。8.LoadingProgress:加载指示器组件,用于展示加载过程中的指示器。9.SaveButton:保存按钮组件,用于保存图片到相册。10.Swiper:轮播图组件,用于创建轮播图效果。11.TextInput:输入框组件,用于接收用户输入。12.Search:搜索条组件,用于实现搜索功能。13.Web:网页加载组件,用于加载网页内容。使用的属性记录:* width:设置容器或组件的宽度。* height:设置容器或组件的高度。* backgroundColor:设置容器或组件的背景色。* padding:设置容器或组件的内边距。* margin:设置容器或组件的外边距。* visibility:根据属性值控制容器或组件的显示或隐藏。* onClick:设置点击事件处理器。* onAreaChange:监听容器尺寸变化。* linearGradient:设置容器或组件的背景为线性渐变色。* shadow:设置容器的阴影效果。* align:设置内部组件的位置显示方式。* constraintSize:设置容器或组件的最大宽度或高度。* transition:为容器或组件添加过渡动画效果。* maxLines:设置文本组件最多显示的行数。* onChange:监听输入内容的变化。* indicator:设置是否显示轮播指示点。* loop:设置是否开启轮播图的循环播放。* src:设置网页加载组件的源地址。* javaScriptProxy:注册JS Bridge,用于与H5页面进行数据通信。* onLoadIntercept:拦截内部跳转、重定向等链接。以上是项目中使用的系统组件和属性记录,可以作为学习和开发项目时的参考。【代码示例】import { LengthMetrics } from '@kit.ArkUI'import web_webview from '@ohos.web.webview'; @Entry@Componentexport struct Page13 { controller: web_webview.WebviewController = new web_webview.WebviewController(); @State inviteQrCodeID: string = "inviteQrCodeID" @State isShow: boolean = true @State searchValue: string = "" scripts: Array<ScriptItem> = [ // { script: this.localStorage, scriptRules: ["*"] } ]; build() { Column() { Column({ space: 10 }) { // 纵向布局容器 // ForEach() 可配合使用以动态渲染子组件 } .width('90%') // 设置容器宽度为父容器的90% .height('100%') // 设置容器高度为父容器的100% .backgroundColor("#ffffff") // 设置容器背景色为白色 .layoutWeight(1) // 占据父容器的剩余空间 .alignItems(HorizontalAlign.Center) // 水平居中对齐 .justifyContent(FlexAlign.Center) // 垂直居中对齐 .align(Alignment.TopStart) // 内容对齐方式为顶部左端 .borderWidth({ bottom: 1 }) // 设置底部边框宽度为1 .borderColor("#E3E3E3") // 设置边框颜色 .padding({ left: '20lpx', right: '20lpx' }) // 设置左右内边距为20逻辑像素 .margin({ top: '44lpx' }) // 设置顶部外边距为44逻辑像素 .visibility(this.isShow ? Visibility.Visible : Visibility.None) // 根据isShow属性控制容器的显示或隐藏 .id(this.inviteQrCodeID) // 设置组件ID,方便后续截图保存到相册 .flexGrow(1) // 当父布局为Flex时,占据父容器的剩余空间 .gesture(LongPressGesture({ repeat: false })) // 长按手势监听,设置repeat为false表示长按时不会重复触发 .onClick(() => { // 点击事件处理器 // 处理点击逻辑 }) Row() { // 横向布局容器 // ForEach() 可用于动态渲染子组件列表 } .width('100%') // 设置容器宽度为父容器的100% .height('192lpx') // 设置容器高度为192逻辑像素 .justifyContent(FlexAlign.End) // 子元素在主轴方向上靠右对齐 .backgroundColor(Color.White) // 设置容器背景色为白色 .padding({ left: '28lpx', right: '28lpx' }) // 设置左右内边距为28逻辑像素 .margin({ top: '39lpx' }) // 设置顶部外边距为39逻辑像素 .transition(TransitionEffect.OPACITY.animation({ duration: 200 })) // 添加透明度过渡动画,持续时间为200毫秒 .visibility(this.isShow ? Visibility.None : Visibility.Visible) // 根据 `this.isShow` 属性来决定是否显示该容器 .onClick(() => { // 点击事件处理器 // 执行点击操作的逻辑 }) .onAreaChange((previousArea: Area, currentArea: Area) => { // 监听容器尺寸变化 // 在容器尺寸发生变化时执行相关逻辑 }) Stack({ alignContent: Alignment.Bottom }) { // 创建一个层叠布局容器,并设置内容对其方式为底部对齐 } .width(180) // 设置容器宽度为180逻辑像素 .height(180) // 设置容器高度为180逻辑像素 .backgroundColor(0x88000000) // 设置容器背景色为半透明黑色(RGB: #000000,Alpha: 0.53) .borderRadius(10) // 设置容器的圆角半径为10逻辑像素 .margin({ left: '25lpx', top: '6lpx', right: '25lpx' }) // 设置容器的左、顶和右外边距分别为25和6逻辑像素 .align(Alignment.Top) // 设置内部组件的位置显示方式为顶部对齐 .visibility(this.isShow ? Visibility.Visible : Visibility.None) // 根据 `this.isShow` 属性值来控制容器的显示或隐藏 .onClick(() => { }) // 定义点击事件处理函数 .linearGradient({ // 设置容器背景色为线性渐变色,注意与 `.backgroundColor` 互斥 angle: 90, // 渐变角度为90度 colors: [// 渐变颜色配置 [0xFF0000, 0.0], // 红色,位置0% [0xFFFF00, 0.2], // 黄色,位置20% [0x00FF00, 0.4], // 绿色,位置40% [0x00FFFF, 0.6], // 青绿色,位置60% [0x0000FF, 0.8], // 蓝色,位置80% [0xFF00FF, 1.0]// 紫色,位置100% ] }) .shadow({ // 设置容器的阴影效果 radius: 20, // 阴影模糊半径为20逻辑像素 offsetY: 25, // 阴影垂直偏移量为25逻辑像素 offsetX: 0, // 阴影水平偏移量为0逻辑像素 color: "#bfbfbf" // 阴影颜色为浅灰色 }) Flex({ wrap: FlexWrap.Wrap }) { // 创建一个允许换行的弹性布局容器 // ForEach 通常用于内部动态渲染子组件列表 } .width('100%') // 设置容器宽度为父容器的100% .height('88lpx') // 设置容器高度为88逻辑像素 .margin({ top: '20lpx', bottom: '30lpx' }) // 设置容器的顶部和底部外边距分别为20和30逻辑像素 .borderWidth({ top: 1 }) // 设置容器顶部边框宽度为1逻辑像素 .borderColor("#cccccc") // 设置容器边框颜色为浅灰色 .visibility(this.isShow ? Visibility.Visible : Visibility.None) // 根据 `this.isShow` 属性值来控制容器的显示或隐藏 Scroll() { // 创建一个滚动布局容器 // 通常内部配合 Row() 或 Column() 使用以实现滚动效果 } .width('100%') // 设置容器宽度为父容器的100% .layoutWeight(1) // 占据父容器的剩余空间 .scrollable(ScrollDirection.Horizontal) // 设置滚动方向为水平 .scrollBar(BarState.Off) // 关闭滚动条显示 .borderWidth({ bottom: 1 }) // 设置底部边框宽度为1逻辑像素 .borderColor("#e3e3e3") // 设置边框颜色 .align(Alignment.Start) // 设置内部组件的位置显示方式为起始位置对齐 .visibility(this.isShow ? Visibility.Visible : Visibility.None) // 根据 `this.isShow` 属性值来控制容器的显示或隐藏 Image($r('app.media.app_icon'))// 图片组件 .width('120lpx')// 设置图片宽度为120逻辑像素 .height('120lpx')// 设置图片高度为120逻辑像素 .padding('10lpx')// 设置图片的内边距为10逻辑像素 .margin({ top: '25lpx' })// 设置图片的顶部外边距为25逻辑像素 .draggable(false)// 设置图片不可拖动,默认情况下不设置时可能会受外层长按手势影响 .objectFit(ImageFit.Fill)// 设置图片显示方式为填充,可能会导致图片变形 .visibility(this.isShow ? Visibility.Visible : Visibility.Hidden)// 根据 `this.isShow` 属性值来控制图片的显示或隐藏 .alt($r('app.media.app_icon'))// 设置图片加载失败时的占位图 .expandSafeArea([SafeAreaType.SYSTEM], [SafeAreaEdge.TOP, SafeAreaEdge.BOTTOM])// 使图片在系统安全区域内扩展,避免被状态栏遮挡 .onClick(() => { // 点击事件处理器 // 处理点击逻辑 }) Text() { // 文本组件,可结合 ForEach 和 Span 使用 ForEach(["a", "b"], (item: string, index: number) => { // 使用 ForEach 循环遍历数组 ["a", "b"] Span(item)// 创建一个 Span 子组件,并传入当前项作为文本内容 .fontColor("#FF1919")// 设置 Span 组件的文字颜色为红色 .fontSize('24lpx')// 设置 Span 组件的字体大小为24逻辑像素 .onClick(() => { }) // 设置 Span 组件的点击事件处理器 }) } .width('100%') // 设置 Text 组件的宽度为100%,即填充其父容器的宽度 .height('120lpx') // 设置 Text 组件的高度为120逻辑像素 .textAlign(TextAlign.Center) // 设置 Text 组件内的文本水平居中对齐 .fontColor("#2E2E2E") // 设置 Text 组件内的文本颜色为深灰色 .fontSize('36lpx') // 设置 Text 组件内的字体大小为36逻辑像素 .backgroundColor("#F9F9F9") // 设置 Text 组件的背景色为浅灰色 .padding(20) // 设置 Text 组件的内边距为20逻辑像素 .margin({ bottom: '44lpx' }) // 设置 Text 组件的底部外边距为44逻辑像素 .lineHeight('60lpx') // 设置 Text 组件内文本的行间距(行高)为60逻辑像素 .lineSpacing(LengthMetrics.lpx(15)) // 设置 Text 组件内文本行与行之间的实际空白距离为15逻辑像素 .borderRadius(8) // 设置 Text 组件的圆角半径为8逻辑像素 .borderWidth('1lpx') // 设置 Text 组件的边框宽度为1逻辑像素 .borderColor("#bbbbbb") // 设置 Text 组件的边框颜色为浅灰色 .borderStyle(BorderStyle.Solid) // 设置 Text 组件的边框样式为实线 .visibility(this.isShow ? Visibility.Visible : Visibility.None) // 根据 `this.isShow` 的值来决定 Text 组件是否可见 .constraintSize({ maxWidth: '80%' }) // 设置 Text 组件的最大宽度为其父容器宽度的80% .layoutWeight(1) // 设置 Text 组件在弹性布局中的权重为1,意味着它会占据剩余的空间 .transition(TransitionEffect.OPACITY.animation({ duration: 200 })) // 为 Text 组件添加一个持续200毫秒的透明度过渡动画 .maxLines(2) // 设置 Text 组件最多显示两行文本 .onClick(() => { // 设置 Text 组件的点击事件处理器 // 在此处添加点击事件的具体逻辑 }) .onAreaChange((previousArea: Area, currentArea: Area) => { // 监听 Text 组件的尺寸变化 // 在此处添加尺寸变化时的具体逻辑 }) .linearGradient({ // 设置 Text 组件的背景为线性渐变色,注意与 `.backgroundColor` 不能同时使用 angle: 90, // 设置渐变的角度为90度,从左到右 colors: [// 设置渐变的颜色配置数组 [0xFF0000, 0.0], // 红色,位于渐变起始点(0%) [0xFFFF00, 0.2], // 黄色,位于渐变的20%位置 [0x00FF00, 0.4], // 绿色,位于渐变的40%位置 [0x00FFFF, 0.6], // 青绿色,位于渐变的60%位置 [0x0000FF, 0.8], // 蓝色,位于渐变的80%位置 [0xFF00FF, 1.0]// 紫色,位于渐变终点(100%) ] }) LoadingProgress()// 创建一个加载指示器组件,通常用于页面加载过程中展示 .color(Color.White)// 设置加载指示器的颜色为白色 .width(100)// 设置加载指示器的宽度为100单位 .height(100) // 设置加载指示器的高度为100单位 SaveButton()// 用户点击此按钮可保存图片到相册 .onClick(() => { }) // 设置点击事件处理器 Swiper() { // 创建一个轮播图组件,通常内部结合 ForEach 使用 } .indicator(false) // 设置是否显示轮播指示点 .loop(false) // 设置是否开启轮播图的循环播放 TextInput({ placeholder: '请输入邀请码' })// 创建一个输入框,带有提示信息 .width('540lpx')// 设置输入框宽度为540逻辑像素 .height('76lpx')// 设置输入框高度为76逻辑像素 .placeholderColor("#CBCBCB")// 设置提示信息文字颜色为浅灰色 .maxLength(6)// 设置输入框最多可输入的字符长度为6 .fontColor("#2E2E2E")// 设置输入内容的颜色为深灰色 .fontSize('36lpx')// 设置输入框内字体大小为36逻辑像素 .padding({ left: 0 })// 设置输入框左侧内边距为0逻辑像素 .margin({ left: '105lpx', top: '28lpx' })// 设置输入框左侧和顶部的外边距分别为105和28逻辑像素 .borderRadius(0)// 设置输入框圆角为0,即直角 .backgroundColor("#ffffff")// 设置输入框背景色为白色 .inputFilter('^[0-9a-zA-Z]*$')// 设置输入过滤规则,仅允许数字和字母输入 .borderWidth({ bottom: 1 })// 设置输入框底部边框宽度为1逻辑像素 .borderColor("#CBCBCB")// 设置输入框边框颜色为浅灰色 .type(InputType.PhoneNumber)// 设置输入类型为电话号码 .caretColor('#FF1919')// 设置输入框光标颜色为红色 .onChange((value: string) => { }) // 监听输入内容的变化 Search({ value: $$this.searchValue, placeholder: '搜索当前列表显示的单位' })// 创建一个搜索条组件,并设置初始值和提示信息 .layoutWeight(1)// 在弹性布局中占据剩余空间 .backgroundColor(Color.Transparent)// 设置搜索条背景为透明 .fontColor("#2E2E2E")// 设置搜索内容的颜色为深灰色 .placeholderColor("#CBCBCB")// 设置提示信息文字颜色为浅灰色 .borderRadius('32lpx')// 设置搜索条的圆角半径为32逻辑像素 .textFont({ size: '28lpx' })// 设置搜索条内字体大小为28逻辑像素 .onChange((value: string) => { }) // 监听输入内容的变化 Web({ src: "https://xxx", controller: this.controller })// 创建一个加载网页的组件,并设置源地址和控制器 .width('100%')// 设置组件宽度为100%,即填充其父容器宽度 .height('100%')// 设置组件高度为100%,即填充其父容器高度 .domStorageAccess(true)// 开启DOM Storage API权限,允许本地存储功能 .javaScriptAccess(true)// 允许执行JavaScript脚本,默认允许执行 .databaseAccess(true)// 开启数据库存储API权限,默认不开启 .mixedMode(MixedMode.All)// 允许HTTP和HTTPS混合模式 .fileAccess(true)// 开启应用文件系统的访问权限,默认已开启 .imageAccess(true)// 允许自动加载图片资源,默认允许 .geolocationAccess(true)// 开启地理位置权限,默认开启 .onlineImageAccess(true)// 允许从网络加载图片资源,默认允许 .mediaPlayGestureAccess(true)// 允许有声视频播放无需用户手动点击,默认需要用户点击 .backgroundColor('#ffffff')// 设置组件背景色为白色 .javaScriptOnDocumentStart(this.scripts)// 在文档开始加载前注入JavaScript脚本 .javaScriptProxy({ // 注册JS Bridge,用于与H5页面进行数据通信 name: "xx", // 注册名称,注意避免使用关键字 object: Object(), methodList: Object(), controller: this.controller, }) .onLoadIntercept((event) => { return true })// 拦截内部跳转、重定向等链接 .onControllerAttached(() => { })// 在网页加载前设置自定义UA .onPageEnd((e) => { })// 页面加载完成后,可以设置隐藏loading布局 .onShowFileSelector((event) => { return true })// 网页请求拉起相机时,由系统调用返回用户选择的图片 .onVisibleAreaChange([0.0, 1.0], () => { }) // 监听网页显示区域的变化 } .height('100%') .width('100%') }}转载自https://www.cnblogs.com/zhongcx/articles/18440599
推荐直播
-
GaussDB管理平台TPOPS,DBA高效运维的一站式解决方案
2024/12/24 周二 16:30-18:00
Leo 华为云数据库DTSE技术布道师
数据库的复杂运维,是否让你感到头疼不已?今天,华为云GaussDB管理平台将彻底来改观!本期直播,我们将深入探索GaussDB管理平台的TPOPS功能,带你感受一键式部署安装的便捷,和智能化运维管理的高效,让复杂的运维、管理变得简单,让简单变得可靠。
回顾中 -
DTT年度收官盛典:华为开发者空间大咖汇,共探云端开发创新
2025/01/08 周三 16:30-18:00
Yawei 华为云开发工具和效率首席专家 Edwin 华为开发者空间产品总监
数字化转型进程持续加速,驱动着技术革新发展,华为开发者空间如何巧妙整合鸿蒙、昇腾、鲲鹏等核心资源,打破平台间的壁垒,实现跨平台协同?在科技迅猛发展的今天,开发者们如何迅速把握机遇,实现高效、创新的技术突破?DTT 年度收官盛典,将与大家共同探索华为开发者空间的创新奥秘。
回顾中
热门标签