鸿蒙作为一个新系统,我觉得很有发展潜力,因此想入门一下鸿蒙开发,以便于以后的个人发展。

下面是我的鸿蒙开发学习笔记。

DevEco创建项目流程

示例代码:

DevEco软件配置

基础入门

ArkTS基础

变量和类型

定义变量名的方法:

1
let 变量名:数据类型=值

变量跟界面没有关系的话,那直接写在界面代码的外部。

如何验证变量是否存进去了?用输出语句输出变量内容即可:

1
console.log(变量名)

例如:

注释用 // 符号,在DevEco中可以用 ctrl+/ 来给选中的一行或多行快速加上注释。

三种基本变量类型的定义例子如下(注意boolean类型只有truefalse两种值):

变量名不适合用中文!

数组

数组:一次性保存多个同类型数据。

定义数组的方法:

1
let 数组名:类型[]=[数据1, 数据2, ...]

数组下标跟大多数编程语言一样,都是从开始。

使用console输出数组,这里要注意一下,cosole.log的第一个参数是string类型的,因此不能直接输出数组内容,需要像下面这样:

1
2
let titles: string[] = ['1', '2', '3']
console.log('数组内容是:', titles)

对象

对象:一次性存储多个不同类型的数据。

声明对象时同样需要标注数据类型,而对象的数据类型可以由接口来定义:

1
2
3
4
5
6
7
8
let vase:数据类型 = {
title: '创意橘子花瓶',
price: 12.99
}
interface Goods {
title: string
price: number
}

对象内部各变量由属性名和属性值构成,这一对称为键值对,键值对之间用逗号隔开。

取对象中的变量:

1
2
console.log('title: ', vase.title)
console.log('price: ', vase.price)

函数

使用函数封装代码,可以提升代码的复用性。

ArkTS的函数返回值不需要声明数据类型,以return的值为准:

1
2
3
4
5
function calc(r: number) {
return 2 * 3.1415926 * r
}
let c1: number = calc(2)
console.log("周长是:", c1)

函数声明时的参数是形参,调用时的参数是实参。

箭头函数

使用箭头函数封装代码,可以提高代码复用性。

1
2
3
let sum = (num1: number, num2: number) => {
return num1 + num2
}

跟function函数的使用一样。

ArkUI基础

组件的基础语法

ArkUI(方舟开发框架):构建鸿蒙应用界面的框架。

组件:界面构建与显示的最小单位。

鸿蒙APP所能看到的界面内容都是一个个的组件。

组件包括容器组件内容组件

1
2
3
4
Column() {} //控制里面的内容可以换行排
Row() {} //控制里面的内容可以横着排

Text('内容') //文本组件

编写时,先写容器组件做布局,再写内容组件做内容。

  • Column的效果:

可以看见文本内容有换行。

  • Row的效果:

可以看见文本内容是横着排的。

**注意,build函数中只能有一个组件(并且必须是容器组件),如果放入多个组件会报错!!!**因此需要放入多个组件时,可以设置一个Column根组件:

通用属性

使用属性美化组件。

上图展现的属性为通用属性,所有组件都包含。

尝试用这些属性,来看看效果:

色值还能用十六进制色值,如下:

1
.backgroundColor('#ff6600')

在鸿蒙系统中,满屏尺寸是360vp,这个尺寸会适配不同的设备。也可以用100%来表示满屏尺寸

文本属性

使用文本属性美化文字外观样式。

尝试使用这些属性,效果如下:

注意,字体大小默认是16fp,字体粗细默认大小是400。

练习题 · 练练手

我的答案:

图像组件

使用图像组件为界面添加图像资源。

图像组件的写法:

1
Image(图像资源路径)

图像资源路径分为本地图和网络图。

本地图:在项目的resource文件夹下找到base文件夹,base文件夹下有一个media文件夹,假设media文件夹下有一个background.png图片,那么找到图片的写法:

1
$r('app.media.background')

网络图:直接粘贴网络图的网址就行了(https://….)。

总结:resouces/base/media/目录下保存图像资源,使用$r('app.media.xx')查找。网络图片直接以字符串形式粘贴网址即可。

内外边距

使用内、外边距调整组件以及内容的位置。

内容跟组件边缘的距离用内边距padding设定,两个组件之间有距离通过外边距margin设定。

若四个方向间距相同,则:

若四个方向间距不同,则:

总结一下:

border属性

使用border属性为组件添加边框效果。

例如下面的代码展示的效果:

案例-歌曲列表

使用组件以及属性方法布局歌曲列表。

遵循一个小套路:先整体,再局部。先布局,再内容,后美化。

用一个Column作为根组件,再用黑色填充整个界面,但是上下会留下一条横着的白线,因为鸿蒙默认这两个区域是留给系统的,因此可以给根Column加上以下代码:

1
.expandSafeArea([SafeAreaType.SYSTEM], [SafeAreaEdge.TOP, SafeAreaEdge.BOTTOM])  //扩充组件安全区域代码

这样就能让.width.height的100%参数填满整个屏幕。

歌曲列表,屏幕不一定能全部装下,因此需要一个鸿蒙系统提供的支持滚动的组件:List(),在内部使用ListItem(),有说少项就用多少ListItem()

1
2
3
4
5
6
7
8
List() {
ListItem() {
Row() {}
.width('100%')
.height(80)
.backgroundColor(Color.Pink)
}
}

List()默认情况下在右侧会有滑条,可以用以下代码来取消滑条:

1
2
List() {}
.scrollBar(BarState.Off)

歌曲列表实现代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
@Entry
@Component
struct Index {
build() {
Column() {
Text('猜你喜欢')
.fontColor(Color.White)
.width('100%')
.margin({bottom:10})
List() {
ListItem() {
Row() {
// 图
Image($r('app.media.background'))
.width(80)
.border({radius:10})
.margin({right:10})
// 文字
Column() {
Text('直到世界的尽头')
.fontColor('#F3F3F3')
.width('100%')
.fontWeight(700)
.margin({bottom:15})
Row() {
Text('VIP')
.fontColor('#9A8E28')
.border({width: 1, color: '#9A8E28', radius: 12})
.padding({left: 5, right: 5, top: 3, bottom: 3})
.margin({right:10})
Text('WANDS')
.fontColor('#696969')
}
.width('100%')
}
.layoutWeight(1)
// 更多
Image($r('app.media.ic_public_more_list'))
.width(24)
.fillColor('#FEFEFE')
}
.width('100%')
.height(80)
.margin({bottom: 10})
}

}
.scrollBar(BarState.Off)
}
.width('100%')
.height('100%')
.backgroundColor('#131313')
.padding({left:10, right:10})
.expandSafeArea([SafeAreaType.SYSTEM], [SafeAreaEdge.TOP, SafeAreaEdge.BOTTOM])
}
}

效果:

ArkTS核心

if分支语句

根据逻辑条件结果,执行不同的语句。

1
2
3
4
5
if (逻辑条件) {
条件成立执行的代码
} else {
条件成立不执行的代码
}

if-else的语法跟C语言里的几乎一样。

条件表达式

根据逻辑条件结果,执行不同的表达式,得到不同的结果。

写法:

1
条件 ? 条件成立的表达式 : 条件不成立的表达式

跟C语言几乎一样。

条件渲染

根据逻辑条件结果,渲染不同的UI内容。

=====都能用于判断。=== 更严格(既判断值又判断类型)。

根据不同的条件来确定渲染哪个组件。

循环渲染

根据数组数据重复渲染UI内容。

代码如下:

1
2
3
4
5
let names: string[] = ['111', '222', '333']
ForEach(names, (item: string, index: number) => {
// item为names里的每一项,idex为对应项的下标
console.log(item + index) //字符串之间的'+'表示拼接
})

状态管理和事件

注意,默认的装饰器是@Component,如图,我们要改成@ComponentV2装饰器。装饰器在V2变为了@Local

  • 状态变量必须设置数据类型;
  • 状态必须设置初始值。

界面当中使用状态是用this.<状态变量>,相当于是找到当前组件对应变量的状态。

.onClick()作用是点击一下组件触发对应动作,可以用箭头函数作为参数。

@Builder 自定义构建函数

使用@Builder装饰函数,封装的UI元素,提升复用性。

@Builder装饰的函数也称为“自定义构建函数”。

可以写在struct里面。

例如:

1
2
3
4
5
6
7
8
9
10
11
@Entry
@Component
struct Index {
@Builder
musicBuilder() { }
build() {
Column() {
this.musicBuilder()
}
}
}

案例-歌单交互效果

要将歌曲数据通过对象数组渲染到界面上。

存储歌曲数据的接口:

1
2
3
4
5
interface SongItemType {
img: string // 图像路径
name: string // 名称
author: string // 作者
}

歌单配套数据:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
songs: SongItemType[] = [
{
img: 'http://yjy-teach-oss.oss-cn-beijing.aliyuncs.com/HeimaCloudMusic/0.jpg',
name: '直到世界的尽头',
author: 'WANDS',
},
{
img: 'http://yjy-teach-oss.oss-cn-beijing.aliyuncs.com/HeimaCloudMusic/1.jpg',
name: '画',
author: '赵磊',
},
{
img: 'http://yjy-teach-oss.oss-cn-beijing.aliyuncs.com/HeimaCloudMusic/2.jpg',
name: 'Sweet Dreams',
author: 'TPaul Sax / Eurythmics',
},
{
img: 'http://yjy-teach-oss.oss-cn-beijing.aliyuncs.com/HeimaCloudMusic/3.jpg',
name: '奢香夫人',
author: '凤凰传奇',
},
{
img: 'http://yjy-teach-oss.oss-cn-beijing.aliyuncs.com/HeimaCloudMusic/4.jpg',
name: '空心',
author: '光泽',
},
{
img: 'http://yjy-teach-oss.oss-cn-beijing.aliyuncs.com/HeimaCloudMusic/5.jpg',
name: '反转地球',
author: '潘玮柏',
},
{
img: 'http://yjy-teach-oss.oss-cn-beijing.aliyuncs.com/HeimaCloudMusic/6.jpg',
name: 'No.9',
author: 'T-ara',
},
{
img: 'http://yjy-teach-oss.oss-cn-beijing.aliyuncs.com/HeimaCloudMusic/7.jpg',
name: '孤独',
author: 'G.E.M.邓紫棋',
},

{
img: 'http://yjy-teach-oss.oss-cn-beijing.aliyuncs.com/HeimaCloudMusic/8.jpg',
name: 'Lose Control',
author: 'Hedley',
},
{
img: 'http://yjy-teach-oss.oss-cn-beijing.aliyuncs.com/HeimaCloudMusic/9.jpg',
name: '倩女幽魂',
author: '张国荣',
},
{
img: 'http://yjy-teach-oss.oss-cn-beijing.aliyuncs.com/HeimaCloudMusic/10.jpg',
name: '北京北京',
author: '汪峰',
},
{
img: 'http://yjy-teach-oss.oss-cn-beijing.aliyuncs.com/HeimaCloudMusic/11.jpg',
name: '苦笑',
author: '汪苏泷',
},
{
img: 'http://yjy-teach-oss.oss-cn-beijing.aliyuncs.com/HeimaCloudMusic/12.jpg',
name: '一生所爱',
author: '卢冠廷 / 莫文蔚',
},
{
img: 'http://yjy-teach-oss.oss-cn-beijing.aliyuncs.com/HeimaCloudMusic/13.jpg',
name: '月半小夜曲',
author: '李克勤',
},
{
img: 'http://yjy-teach-oss.oss-cn-beijing.aliyuncs.com/HeimaCloudMusic/14.jpg',
name: 'Rolling in the Deep',
author: 'Adele',
},
{
img: 'http://yjy-teach-oss.oss-cn-beijing.aliyuncs.com/HeimaCloudMusic/15.jpg',
name: '海阔天空',
author: 'Beyond',
}
]

每首歌的组件重复出现多次,因此可以用ForEach实现。

但是还要实现点击歌曲后显示播放动画的效果。

需要用到一个新的组件——层叠组件Stack,在歌曲图像上显示播放状态。

在Image组件上加上层叠组件Stack:

1
2
3
4
5
6
7
8
9
Stack() {
Image(song.img)
.width(80)
.border({radius:10})
.margin({right:10})
Image($r('app.media.ic_public_play_norm'))
.width(24)
.fillColor(Color.White)
}

这么直接加上去会导致所有歌曲都有播放状态,因此可以用一个状态变量作为下标来表明当前是哪首歌曲正在播放:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
...
@Local playIndex: number = -1
...
Stack() {
Image(song.img)
.width(80)
.border({radius:10})
.margin({right:10})
if (this.playIndex === index) {
Image($r('app.media.ic_public_play_norm'))
.width(24)
.fillColor(Color.White)
}
}
...

然后要实现点击某歌曲就显示播放图标的功能。

给实现歌曲的Row()组件添加.onClick()

这样点击对应歌曲,this.playIndex的值会立刻更新,因此播放图标的显示位置也会更新。从而实现了我们想要的效果。

总结: