HarmonyOS ArkUI 3.0试玩初体验!

2024-01-31 18:10

本文主要是介绍HarmonyOS ArkUI 3.0试玩初体验!,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

HarmonyOS ArkUI 3.0 正式到来,今天就给大家分享一下我的 HarmonyOS ArkUI 3.0 框架试玩初体验,以合成 1024 的开发实战,带大家感受一下 HarmonyOS ArkUI 3.0 的极简开发。

af95efca7c5d5e46521baae1d31097f3.png

效果图如下:

b13561214c7c6d73fea502205785b837.png

代码文件结构:

3d73ec24ae85bb317284de64e0ea73b0.png

创建一个空白的工程

①安装和配置 DevEco Studio

DevEco Studio 下载:

https://developer.harmonyos.com/cn/develop/deveco-studio#download

DevEco Studio 安装:

https://developer.harmonyos.com/cn/docs/documentation/doc-guides/software_install-0000001053582415
②创建一个 Empty Ability 应用

DevEco Studio 下载安装成功后,打开 DevEco Studio,点击左上角的 File,点击 New,再选择 New Project,选择 Empty Ability 选项,点击 Next 按钮。

d045c2564913d0f550cd8602bffc726d.png

将文件命名为 MyETSApplication(文件名不能出现中文或者特殊字符,否则将无法成功创建项目文件),Project Type 勾选 Application,选择保存路径。

Language 勾选 eTS,选择 API7,设备勾选 Phone,最后点击 Finish 按钮。

9b0f9d99e4be868b4557da8ff03cf27b.png

③准备工作

在 entry>src>main>config.json 文件中最下方"launchType": "standard"的后面添加以下代码,这样就可以实现去掉应用上方的标签栏了。

config.json 最下方部分代码:

"metaData": {"customizeData": [{"name": "hwc-theme","value": "androidhwext:style/Theme.Emui.Light.NoTitleBar","extra": ""}]}

实现界面布局

①保存图片

将 logo 图片保存到 entry>src>main>resources>base>media 文件中。

0bbe602504c97af719e3a321bb6dd0fe.png

②新一代的声明式 UI 开发范式

具体而言,ArkUI 3.0 中的新一代声明式 UI 开发范式,主要特征如下:

(1)基于 TypeScript 扩展的声明式 UI 描述语法,提供了类自然语言的UI描述和组合。

(2)开箱即用的多态组件。多态是指 UI 描述是统一的,UI 呈现在不同类型设备上会有所不同。比如 Button 组件在手机和手表会有不同的样式和交互方式。

(3)多维度的状态管理机制,支持灵活的数据驱动的 UI 变更。

装饰器:用来装饰类、结构体、方法以及变量,赋予其特殊的含义,如上述示例中 @Entry、@Component、@State 都是装饰器。

@Component 表示这是个自定义组件;@Entry 则表示这是个入口组件;@State 表示组件中的状态变量,这个状态变化会引起 UI 变更。

自定义组件:可复用的 UI 单元,可组合其它组件,如上述被 @Component 装饰的 struct Hello。

UI 描述:声明式的方式来描述UI的结构,如上述 build() 方法内部的代码块。

内置组件:框架中默认内置的基础和布局组件,可直接被开发者调用,比如示例中的 Column、Text、Divider、Button。

事件方法:用于添加组件对事件的响应逻辑,统一通过事件方法进行设置,如跟随在 Button 后面的 onClick()。

属性方法:用于组件属性的配置,统一通过属性方法进行设置,如 fontSize()、width()、height()、color() 等,可通过链式调用的方式设置多项属性。

③实现界面

这一次程序用到的装饰器分别有 @Entry 、@Component、@State和 @Link 。

装饰器 @Entry 装饰的自定义组件用作页面的默认入口组件,加载页面时,将首先创建并呈现 @Entry 装饰的自定义组件。

要注意的是:在单个源文件中,最多可以使用 @Entry 装饰一个自定义组件。

装饰器 @Component 装饰的 struct 表示该结构体具有组件化能力,能够成为一个独立的组件,这种类型的组件也称为自定义组件。该组件可以组合其他组件,它通过实现 build 方法来描述 UI 结构。

组件生命周期包括:

  • aboutToAppear:函数在创建自定义组件的新实例后,在执行其build函数之前执行。允许在 aboutToAppear 函数中改变状态变量,这些更改将在后续执行build函数中生效。

  • aboutToDisappear:函数在自定义组件析构消耗之前执行。不允许在 aboutToDisappear 函数中改变状态变量,特别是 @Link 变量的修改可能会导致应用程序行为不稳定。

  • onPageShow:当此页面显示时触发一次。包括路由过程、应用进入前后台等场景,仅 @Entry 修饰的自定义组件生效。

  • onPageHide:当此页面消失时触发一次。包括路由过程、应用进入前后台等场景,仅 @Entry 修饰的自定义组件生效。

  • onBackPress:当用户点击返回按钮时触发,,仅 @Entry 修饰的自定义组件生效。

装饰器 @State 装饰的变量是组件内部的状态数据,当这些状态数据被修改时,将会调用所在组件的 build 方法进行 UI 刷新。

要注意的是,标记为 @State 的属性不能直接在组件外部修改,必须为所有 @State 变量分配初始值。

装饰器 @Link 装饰的变量可以和父组件的 @State 变量建立双向数据绑定。要注意的是,@Link 变量不能在组件内部进行初始化,在创建组件的新实例时,必须使用命名参数初始化所有 @Link 变量。

@Link 变量可以使用 @State 变量或 @Link 变量的引用进行初始化。@State 变量可以通过’$'操作符创建引用。

index.ets:先定义一个方格的背景颜色字典 colors,用以绘制不同数字的背景颜色,和一个全局变量 number,用以 ForEach 的键值生成。

var number = 1
const colors={"0": "#CDC1B4","2": "#EEE4DA","4": "#ECE0C6","8": "#F2B179","16": "#F59563","32": "#F67C5F","64": "#F65E3B","128": "#EDCF72","256": "#EDCC61","512": "#99CC00","1024": "#83AF9B","2048": "#0099CC","4096": "#0099CC","8192": "#0099CC"
}

对于 4x4 的方格,如果要一个一个绘制,那么就需要重复绘制 16 个 Text 组件,而且这些 Text 组件除了文本之外,其他属性值都是一样的,这样极其繁琐且没有必要,体现不了 HarmonyOS ArkUI 3.0 的极简开发。

我们可以把 4x4 的方格以每一行定义成一个组件,每一行每一行地绘制,这样能够极大的减少代码量。

对于每一行组件,传统的方式是重复绘制 4 个 Text 组件,而且这些 Text 组件除了文本之外,其他属性值都是一样的,同样极其繁琐且没有必要。

我们可以采用 ForEach 循环渲染来绘制:

第一个参数必须是数组:允许空数组,空数组场景下不会创建子组件。同时允许设置返回值为数组类型的函数。

例如 arr.slice(1, 3),设置的函数不得改变包括数组本身在内的任何状态变量,如 Array.splice、Array.sort 或 Array.reverse 这些原地修改数组的函数。

第二个参数用于生成子组件的 lambda 函数。它为给定数组项生成一个或多个子组件。单个组件和子组件列表必须括在大括号“{…}”中。

可选的第三个参数是用于键值生成的匿名函数。它为给定数组项生成唯一且稳定的键值。

当子项在数组中的位置更改时,子项的键值不得更改,当数组中的子项被新项替换时,被替换项的键值和新项的键值必须不同。

键值生成器的功能是可选的。但是,出于性能原因,强烈建议提供,这使开发框架能够更好地识别数组更改。

如单击进行数组反向时,如果没有提供键值生成器,则 ForEach 中的所有节点都将重建。

使用装饰器 @Component,自定义一个每一行的组件,用装饰器 @Link 定义一个数组 grids。

在 build() 里面添加弹性布局 Flex,使用循环渲染 ForEach 来绘制组件 Text。

对于每一个 Text 组件,文本判断是否为 0,如果值为 0,则不显示,背景颜色采用刚才定义好的背景颜色字典 colors 对应的背景颜色。

文本颜色判断其值是否为 2 或 4,如果为 2 或 4,则采用颜色 #645B52,否则采用背景颜色白色。

@Component
struct setText {@Link grids: number[]build() {Flex({ justifyContent: FlexAlign.Center, alignItems: ItemAlign.Center, direction: FlexDirection.Row }) {ForEach(this.grids,(item: number) => Text(item == 0 ? '' : item.toString()).width(70).height(70).textAlign(TextAlign.Center).fontSize(30).margin({ left: 5, top: 5, right: 5, bottom: 5 }).backgroundColor(colors[item.toString()]).fontColor((item == 2 || item == 4) ? '#645B52' : '#FFFFFF'),(item: number) => (number++) + item.toString())}}
}

同理,使用装饰器 @Component,自定义一个按钮 Button 组件,用以绘制上下左右四个按钮。

@Component
struct setButton {private dirtext: stringprivate dir: string@Link Grids: number[][]@Link grid1: number[]@Link grid2: number[]@Link grid3: number[]@Link grid4: number[]build() {Button(this.dirtext).width(60).height(60).fontSize(30).fontWeight(FontWeight.Bold).align(Alignment.Center).backgroundColor('#974B31').fontColor('#FFFFFF').margin({ left: 5, top: 3, right: 5, bottom: 3 })}
}

在装饰器 @Entry 装饰的结构体的 build() 中,将原来的代码全部删掉。

使用装饰器 @State 定义一个二维数组和四个一维数组,添加垂直布局 Column,宽和高都为 100%,背景颜色为白色。

在其中添加 Image 组件,引用刚才保存好的 logo 图片,再添加一个宽和高都是 320,背景颜色为 #BBADA0 的垂直布局 Column,在其添加四个刚才定义好的行组件 setText。

在外围的垂直布局 Column 中再添加四个刚才定义好的按钮组件 setButton,其中中间两个按钮组件位于弹性布局 Flex 中,最后添加一个 Button 组件,文本内容为“重新开始”。

@Entry
@Component
struct Index {@State grids: number[][] = [[0, 0, 0, 0],[0, 2, 0, 0],[0, 0, 2, 0],[0, 0, 0, 0]]@State grid1: number[] = [this.grids[0][0], this.grids[0][1], this.grids[0][2], this.grids[0][3]]@State grid2: number[] = [this.grids[1][0], this.grids[1][1], this.grids[1][2], this.grids[1][3]]@State grid3: number[] = [this.grids[2][0], this.grids[2][1], this.grids[2][2], this.grids[2][3]]@State grid4: number[] = [this.grids[3][0], this.grids[3][1], this.grids[3][2], this.grids[3][3]]build() {Column() {Image($r('app.media.logo1024')).width('100%').height(140).align(Alignment.Center)Column() {setText({ grids: $grid1 })setText({ grids: $grid2 })setText({ grids: $grid3 })setText({ grids: $grid4 })}.width(320).height(320).backgroundColor("#BBADA0")setButton({dirtext: '↑', dir: 'up', Grids: $grids, grid1: $grid1, grid2: $grid2, grid3: $grid3, grid4: $grid4})Flex({ justifyContent: FlexAlign.Center, alignItems: ItemAlign.Center, direction: FlexDirection.Row }) {setButton({dirtext: '←', dir: 'left', Grids: $grids, grid1: $grid1, grid2: $grid2, grid3: $grid3, grid4: $grid4})setButton({dirtext: '→', dir: 'right', Grids: $grids, grid1: $grid1, grid2: $grid2, grid3: $grid3, grid4: $grid4})}setButton({dirtext: '↓', dir: 'down', Grids: $grids, grid1: $grid1, grid2: $grid2, grid3: $grid3, grid4: $grid4})Button('重新开始').width(180).height(50).fontSize(30).align(Alignment.Center).backgroundColor('#974B31').fontColor('#FFFFFF').margin({ left: 5, top: 3, right: 5, bottom: 3 })}.width('100%').height('100%').backgroundColor("#FFFFFF").alignItems(HorizontalAlign.Center)}
}

编写逻辑代码

index.ets:在结构体 setButton 中添加四个函数。

  • addTwoOrFourToGrids():用以随机生成一个新的方格数字,数字为2或4。

  • swipeGrids(direction):用以实现方格的重新生成。

  • changeGrids(direction):用以实现方格的上下左右移动。

  • changeString():用以将二维数组分成四个一维数组。

最后在 Button 组件的属性里添加一个点击事件,依次调用函数 swipeGrids(direction)、addTwoOrFourToGrids() 和 changeString()。

@Component
struct setButton {private dirtext: stringprivate dir: string@Link Grids: number[][]@Link grid1: number[]@Link grid2: number[]@Link grid3: number[]@Link grid4: number[]addTwoOrFourToGrids() {let array = [];for (let row = 0; row < 4; row++)for (let column = 0;column < 4; column++)if (this.Grids[row][column] == 0)array.push([row, column]);let randomIndes = Math.floor(Math.random() * array.length);let row = array[randomIndes][0];let column = array[randomIndes][1];if (Math.random() < 0.8) {this.Grids[row][column] = 2;} else {this.Grids[row][column] = 4;}}swipeGrids(direction) {let newGrids = this.changeGrids(direction);if (newGrids.toString() != this.Grids.toString()) {this.Grids = newGrids;}}changeGrids(direction) {let newGrids = [[0, 0, 0, 0],[0, 0, 0, 0],[0, 0, 0, 0],[0, 0, 0, 0]];if (direction == 'left' || direction == 'right') {let step = 1;if (direction == 'right') {step = -1;//step作为循环时数组下标改变的方向}for (let row = 0; row < 4; row++) {//每一层let array = [];let column = 0;//如果为left则从0开始right从3开始,if (direction == 'right') {column = 3;}for (let i = 0; i < 4; i++) {if (this.Grids[row][column] != 0) {//把所有非零元依次放入数组中array.push(this.Grids[row][column]);}column += step;//当direction为left时则从0向3递增,为right时则从3向0递减}for (let i = 0; i < array.length - 1; i++) {//访问当前元素及他的下一个元素,所有循环次数为length-1if (array[i] == array[i + 1]) {//判断是否可合并,array[i] += array[i + 1];//合并,array[i + 1] = 0;//合并后参与合并的第二个元素消失i++;}}column = 0;if (direction == 'right') {column = 3;}for (const elem of array) {if (elem != 0) {//跳过array里的空元素newGrids[row][column] = elem;//把合并后的状态赋给新数组grids,column += step;}}}} else if (direction == 'up' || direction == 'down') {//同理let step = 1;if (direction == 'down') {step = -1;}for (let column = 0; column < 4; column++) {let array = [];let row = 0;if (direction == 'down') {row = 3;}for (let i = 0; i < 4; i++) {if (this.Grids[row][column] != 0) {array.push(this.Grids[row][column]);}row += step;}for (let i = 0; i < array.length - 1; i++) {if (array[i] == array[i + 1]) {array[i] += array[i + 1];array[i + 1] = 0;i++;}}row = 0;if (direction == 'down') {row = 3;}for (const elem of array) {if (elem != 0) {newGrids[row][column] = elem;row += step;}}}}return newGrids;}changeString() {this.grid1 = [this.Grids[0][0], this.Grids[0][1], this.Grids[0][2], this.Grids[0][3]]this.grid2 = [this.Grids[1][0], this.Grids[1][1], this.Grids[1][2], this.Grids[1][3]]this.grid3 = [this.Grids[2][0], this.Grids[2][1], this.Grids[2][2], this.Grids[2][3]]this.grid4 = [this.Grids[3][0], this.Grids[3][1], this.Grids[3][2], this.Grids[3][3]]}build() {Button(this.dirtext).width(60).height(60).fontSize(30).fontWeight(FontWeight.Bold).align(Alignment.Center).backgroundColor('#974B31').fontColor('#FFFFFF').margin({ left: 5, top: 3, right: 5, bottom: 3 }).onClick((event: ClickEvent) => {this.swipeGrids(this.dir)this.addTwoOrFourToGrids()this.changeString()})}
}

在结构体 index 中文本内容为“重新开始”的按钮添加一个点击事件,用以重新初始化数据。

@Entry
@Component
struct Index {@State grids: number[][] = [[0, 0, 0, 0],[0, 2, 0, 0],[0, 0, 2, 0],[0, 0, 0, 0]]@State grid1: number[] = [this.grids[0][0], this.grids[0][1], this.grids[0][2], this.grids[0][3]]@State grid2: number[] = [this.grids[1][0], this.grids[1][1], this.grids[1][2], this.grids[1][3]]@State grid3: number[] = [this.grids[2][0], this.grids[2][1], this.grids[2][2], this.grids[2][3]]@State grid4: number[] = [this.grids[3][0], this.grids[3][1], this.grids[3][2], this.grids[3][3]]build() {Column() {Image($r('app.media.logo1024')).width('100%').height(140).align(Alignment.Center)Column() {setText({ grids: $grid1 })setText({ grids: $grid2 })setText({ grids: $grid3 })setText({ grids: $grid4 })}.width(320).height(320).backgroundColor("#BBADA0")setButton({dirtext: '↑', dir: 'up', Grids: $grids, grid1: $grid1, grid2: $grid2, grid3: $grid3, grid4: $grid4})Flex({ justifyContent: FlexAlign.Center, alignItems: ItemAlign.Center, direction: FlexDirection.Row }) {setButton({dirtext: '←', dir: 'left', Grids: $grids, grid1: $grid1, grid2: $grid2, grid3: $grid3, grid4: $grid4})setButton({dirtext: '→', dir: 'right', Grids: $grids, grid1: $grid1, grid2: $grid2, grid3: $grid3, grid4: $grid4})}setButton({dirtext: '↓', dir: 'down', Grids: $grids, grid1: $grid1, grid2: $grid2, grid3: $grid3, grid4: $grid4})Button('重新开始').width(180).height(50).fontSize(30).align(Alignment.Center).backgroundColor('#974B31').fontColor('#FFFFFF').margin({ left: 5, top: 3, right: 5, bottom: 3 }).onClick((event: ClickEvent)=>{this.grids = [[0, 0, 0, 0],[0, 2, 0, 0],[0, 0, 2, 0],[0, 0, 0, 0]]this.grid1 = [this.grids[0][0], this.grids[0][1], this.grids[0][2], this.grids[0][3]]this.grid2 = [this.grids[1][0], this.grids[1][1], this.grids[1][2], this.grids[1][3]]this.grid3 = [this.grids[2][0], this.grids[2][1], this.grids[2][2], this.grids[2][3]]this.grid4 = [this.grids[3][0], this.grids[3][1], this.grids[3][2], this.grids[3][3]]})}.width('100%').height('100%').backgroundColor("#FFFFFF").alignItems(HorizontalAlign.Center)}
}

写在最后

HarmonyOS ArkUI 3.0 框架还有很多内容在本次程序中没有涉及到,例如页面跳转、数据管理、分布式数据库、分布式流转、分布式协同等等,我会在以后的文章中陆陆续续分享我的实战操作,希望能与各位一起学习相互交流!

更多资料请关注我们的项目 Awesome-Harmony_木棉花:

https://gitee.com/hiharmonica/awesome-harmony-os-kapok

1. 回复“m”可以查看历史记录;

2. 回复“h”或者“帮助”,查看帮助;

   开发者已开通多个技术群交流学习,请加若飞微信:1321113940  (暗号k)进开发群学习交流

  说明:我们都是开发者。视频或文章来源于网络,如涉及版权或有误,请您与若飞(1321113940)联系,将在第一时间删除或者修改,谢谢!

009cb1f268fb9bab88338d86bab647e9.png

开 发 者 : KaiFaX

面向全栈工程师的开发者
专注于前端、Java/Python/Go/PHP的技术社区

这篇关于HarmonyOS ArkUI 3.0试玩初体验!的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/664626

相关文章

HarmonyOS学习(七)——UI(五)常用布局总结

自适应布局 1.1、线性布局(LinearLayout) 通过线性容器Row和Column实现线性布局。Column容器内的子组件按照垂直方向排列,Row组件中的子组件按照水平方向排列。 属性说明space通过space参数设置主轴上子组件的间距,达到各子组件在排列上的等间距效果alignItems设置子组件在交叉轴上的对齐方式,且在各类尺寸屏幕上表现一致,其中交叉轴为垂直时,取值为Vert

4B参数秒杀GPT-3.5:MiniCPM 3.0惊艳登场!

​ 面壁智能 在 AI 的世界里,总有那么几个时刻让人惊叹不已。面壁智能推出的 MiniCPM 3.0,这个仅有4B参数的"小钢炮",正在以惊人的实力挑战着 GPT-3.5 这个曾经的AI巨人。 MiniCPM 3.0 MiniCPM 3.0 MiniCPM 3.0 目前的主要功能有: 长上下文功能:原生支持 32k 上下文长度,性能完美。我们引入了

【HarmonyOS】-TaskPool和Worker的对比实践

ArkTS提供了TaskPool与Worker两种多线程并发方案,下面我们将从其工作原理、使用效果对比两种方案的差异,进而选择适用于ArkTS图片编辑场景的并发方案。 TaskPool与Worker工作原理 TaskPool与Worker两种多线程并发能力均是基于 Actor并发模型实现的。Worker主、子线程通过收发消息进行通信;TaskPool基于Worker做了更多场景化的功能封装,例

Cmake之3.0版本重要特性及用法实例(十三)

简介: CSDN博客专家、《Android系统多媒体进阶实战》一书作者 新书发布:《Android系统多媒体进阶实战》🚀 优质专栏: Audio工程师进阶系列【原创干货持续更新中……】🚀 优质专栏: 多媒体系统工程师系列【原创干货持续更新中……】🚀 优质视频课程:AAOS车载系统+AOSP14系统攻城狮入门视频实战课 🚀 人生格言: 人生从来没有捷径,只有行动才是治疗恐惧

【鸿蒙HarmonyOS NEXT】页面之间相互传递参数

【鸿蒙HarmonyOS NEXT】页面之间相互传递参数 一、环境说明二、页面之间相互传参 一、环境说明 DevEco Studio 版本: API版本:以12为主 二、页面之间相互传参 说明: 页面间的导航可以通过页面路由router模块来实现。页面路由模块根据页面url找到目标页面,从而实现跳转。通过页面路由模块,可以使用不同的url访问不同的页面,包括跳转到U

HarmonyOS】ArkTS学习之基于TextTimer的简易计时器的elapsedTime最小时间单位问题

本文旨在纪录自己对TextTimer使用过程的疑惑问题 我在查看教程时候,发现很多博客在onTimer(event: (utc: number, elapsedTime: number) => void) 这里提到elapsedTime:计时器经过的时间,单位为毫秒。我不清楚是否为版本问题。 在我查看version11和version10的api时候,说的都是设置格式的最小单位。 经过个人检验的

【C-实践】文件服务器(3.0)

文件服务器1.0文件服务器2.0文件服务器4.0 概述 使用了 tcp + epoll + 线程池 + 生产者消费者模型,实现文件服务器 有两个进程,主进程负责接收退出信号用来退出整个程序;子进程负责管理线程池、客户端连接以及线程池的退出 子进程中的主线程生产任务,其他子线程消费任务 功能 主要功能:客户端连接服务器,然后自动下载文件 注意 实际传输速度

鸿蒙开发入门day06-ArkUI简介

(创作不易,感谢有你,你的支持,就是我前行的最大动力,如果看完对你有帮助,还请三连支持一波哇ヾ(@^∇^@)ノ) 目录 ArkUI简介 基本概念 两种开发范式 不同应用类型支持的开发范式 UI开发(ArkTS声明式开发范式)概述 特点 整体架构 开发布局 布局结构 布局元素的组成 布局位置 对子元素的约束 ArkUI简介 ArkUI(方舟UI框架)为应用

HarmonyOS应用开发环境搭建

本文主要讲述的是HarmonyOS应用开发环境的搭建,HUAWEI DevEco Studio是基于IntelliJ IDEA Community开源版本打造,为运行在HarmonyOS系统上的应用和服务提供一站式的开发平台。具体下载链接DevEco Studio 一、下载 DevEco Studio 只需要下载对应的版本,选择安装路径,这里根据大家自己的喜好选择路径安装即可 接着下一步,

Node.js初体验 Kali安装Node.js

背景:偶然看到node.js开发微信公众号的视频,有些好奇,想要接触下。然后花了两个小时在实验楼网站上在线学习了JavaScript的基础知识,以及Node.js的基础 接着本着从实践出发的原则 先去本地kali下安装个Node.js玩玩 下载地址:https://nodejs.org/en/download/ 网页最下面有提示:Note: Python 2.6 or 2.7 is requ