HarmonyOS 开发学习笔记
- 一、开发准备
- 1.1、了解ArkTs语言
- 1.2、TypeScript语法
- 1.2.1、变量声明
- 1.2.2、条件控制
- 1.2.3、函数
- 1.2.4、类和接口
- 1.2.5、模块开发
- 1.3、快速入门
- 二、ArkUI组件
- 2.1、Image组件
- 2.2、Text文本显示组件
- 2.3、TextInput文本输入框组件
- 2.4、Button按钮组件
- 2.5、Slider滑动条组件
- 2.6、Column和Row
- 2.7、循环控制
- 2.8、List
- 2.9、自定义组件
- 三、状态管理
- 3.1、@State装饰器
- 3.2、任务统计案例
- 3.3、@Prop、@Link、@Provide和@Consume
- 3.4、@Observe和@ObjectLink
- 四、页面路由
- 五、动画
- 5.1、属性动画
- 5.2、显式动画
- 5.3、组件转场动画
- 5.4、实现摇杆功能
- 六、Stage模型
- 6.1、Stage模型概述
- 6.2、Stage应用配置文件
- 6.3、UIAbility生命周期
- 6.4、页面及组件生命周期
- 6.5、UIAbility的启动模式
- 七、网络连接
- 7.1、Http数据请求
- 7.2、第三方库axios
- 八、数据持久化
- 8.1、用户首选项
- 8.2、关系型数据库
- 九、通知
- 9.1、基础通知
- 9.2、进度条通知
- 9.3、通知行为意图
一、开发准备
1.1、了解ArkTs语言
ArkTs的优势
- 声明式UI
- 状态管理
- …
特点:
- 开发效率高、开发体验好
- 性能优越
- 有多系统适配,接入功能
1.2、TypeScript语法
1.2.1、变量声明
TypeScript在JavaScript的基础上加入了静态类型检查功能,因此每一个变量都有固定的数据类型。
// string : 字符串,可以用引号或双引号
let msg: string = 'hello world!'
// number: 数值,整数、浮点数都可以
let age: number = 21
// boolean:布尔
let finished: boolean = true
// any: 不确定类型,可以是任意类型
let a:any = 'jack'
a = 21
// union: 联合类型,可以是多个指定类型中的一种
let u: string|number|boolean = 'rose'
u = 18
// Object:对象
let p = {name:'jack',age:21}
console.log(p.name)
console.log(p['name'])
//Array:数组,元素可以是任意其它类型
let names: Array<string> = ['Jack','Rose']
let ages: number[] = [21,18]
console.log(names[0])
1.2.2、条件控制
TypeScript与大多数开发语言类似,支持基于if-else和switch的条件控制。
let num:number = 21
//判断是否是偶数
if(num%2===0){
console.log(num + "是偶数")
}else{
console.log(num + "是奇数")
}
//判断是否是正数
if(num>0){
console.log(num + "是正数")
}else if(num<0){
console.log(num + "是负数")
}else{
console.log(num +"是0")
}
注意:在TypeScript中,空字符串、数字0、null、undefined都被认为是false,其它值则为true
let grade: string = "A"
switch (grade) {
case 'A':{
console.log('优秀')
break
}
case 'B' : {
console.log('合格')
break
}
case 'c':{
console.log('不合格')
break
}
default: {
console.log('非法输入')
break
}
}
TypeScript支持for和while循环,并且为一些内置类型如Array等提供了快捷迭代语法。
//普通for
for(let i = 1; i <= 10; i++){
console.log('点赞'+i+'次')
}
//while
let i = 1;
while(i <= 10){
console.log('点赞'+i+'次')
i++;
}
// 定义数组
let names: string[] = ['Jack','Rose']
// for in 送代器,遍历得到数组角标
for (const i in names) {
console.log(i+':'+names[i])
}
// for of 送代器,直接得到元素
for (const name of names) {
console.log(name)
}
1.2.3、函数
TypeScript通常利用function关键字声明函数,并且支持可选参数、默认参数、箭头函数等特殊语法。
//无返回值函数
function sayHello(name:string):void{
console.log('您好,'+name+'!');
}
sayHello("jack")
//有返回值函数
function sum(x:number,y:number):number{
return x+y;
}
let result = sum(21,18)
//箭头函数
let sayHi =(name:string )=>{
console.log('您好'+name+'!')
}
sayHi("zhangsan")
函数-可选参数
// 可选参数,在参数名后加 ?,表示该参数是可选的
function sayHello(name?: string){
// 判断name是否有值,如果无值则给一个默认值
name = name ? name :"陌生人"
console.log('你好,' + name +'!')
}
sayHello('Jack')
sayHello()
函数-默认参数
// 参数默认值,在参数后面赋值,表示参数默认值
//如果调用者没有传参,则使用默认值
function sayHello(name: string ='陌生人'){
console.log('你好,' +'name'+"!")
}
sayHello('Jack')
sayHello()
1.2.4、类和接口
TypeScript具备面向对象编程的基本语法,例如interface、class、enum等。也具备封装、继承、多态等面向对象基本特征。
类、接口、枚举
//定义枚举
enum Msg{
HI ='Hi'
HELLO Hello
}
//定义接口,抽象方法接收举参数
interface A{
say(msg: Msg):void
}
//实现接口
class B implements A {
say(msg: Msg): void {
console.log(msg+',I am B')
}
}
// 初始化对象
let a:A = new B()
//调用方法,传递放举参数
a.say(Msg.HI)
继承
class Rectangle [
//成员变量
private width: number
private length: number
// 构造函数
constructor(width: number, length: number) [
this.width = width
this.length = length
}
//成员方法
public area(): number{
return this.width * this.length
}
}
//定义正方形
class Square extends Rectangle{
constructor(side: number) {
//调用类构造
super(side,side)
}
}
let s = new Square(10)
console.log('正方形面积为:'+s.area())
1.2.5、模块开发
应用复杂时,我们可以把通用功能抽取到单独的ts文件中,每个文件都是一个模块 (module)模块可以相互加载,提高代码复用性。
rectangle.ts
// 定义矩形类,并通过export导出
export class Rectangle {
//成员变量
public width: number
public length: number
//构造函数
constructor(width: number, length: number) {
this.width = width
this.length = length
}
}
//定义工具方法,求矩形面积,并通过export导出
export function area(rec: Rectangle): number{
return rec.width * rec.length
}
//通过import语法导入,from后面写文件的地址
import {Rectangle, area} from '../rectangle'
// 创建Rectangle对象
let r = new Rectangle(10, 20)
//调用area万法
console.log('面积为:' + area(r))
1.3、快速入门
-
装饰器
@Component
:标记自定义组件@Entry
:标记当前组件是入口组件- @State:标记该变量是状态变量,值变化时会触发UI刷新
-
自定义组件
struct Index{ }
- 可复用的UI单元
-
UI描述
build(){ }
- 其内部以声明式万式描述UI结构
-
内置组件:ArkUI提供的组件
Row(){ Column(){ Text(this.message) } }
- 容器组件: 用来完成页面布局,例如 Row、Column
- 基础组件:自带样式和功能的页面元素,例如 Text
-
属性方法
.fontSize(50) .fontWeight(FontWeight.Bold) .width('100%') .height('100%')
- 设置组件的UI样式
-
事件方法
.onClick(()=>{ //...处理事件 })
- 设置组件的UI样式
二、ArkUI组件
2.1、Image组件
Image:图片显示组件
- 声明Image组件并设置图片源:
Image(src: string|PixelMap|Resource)
- string格式,通常用来加载网络图片,需要申请网络访问权限:
ohos.permission.INTERNET
Image('https://xxx .png')
- PixelMap格式,可以加载像素图,常用在图片编辑中
Image(pixelMapobject)
- Resource格式,加载本地图片,推荐使用
Image($r('app.media.mate60'))
对应在目录中的media目录下的图片
Image($rawfile('mate60.png'))
对应在目录中rawfile目录下的图片
- string格式,通常用来加载网络图片,需要申请网络访问权限:
- 添加图片属性
Image($r('app.media.icon')) .width(100)宽度 .height(120) //高度 .borderRadius(10) //边框圆角 .interpolation(ImageInterpolation.High) //图片插值
2.2、Text文本显示组件
- 声明Text组件并设置文本内容
Text(content?: string|Resource)
- string格式,直接填写文本内容
Text('图片宽度')
- Resource格式,读取本地资源文件
Text($r('app.string.width_label'))
- string格式,直接填写文本内容
- 添加文本属性
Text('注册账号')
.lineHeight(32) // 行高
.fontSize(20) // 字体大小
.fontColor('#ff1876f8') // 字体颜色
.fontweight(FontWeight.Medium) //字体粗细
2.3、TextInput文本输入框组件
-
声明TextInput组件
TextInput( {placeholder?: ResourceStr, text?: ResourceStr])
- placeHoder:输入框无输入时的提示文本
TextInput([placeholder:'请输入账号或手机号'})
- text:输入框当前的文本内容
TextInput({text:'itcast'})
- placeHoder:输入框无输入时的提示文本
-
添加属性和事件
TextInput({text:'当前输入文本'})
.width(150) // 宽
.height(30) // 高
.backgroundColor('#FFF') // 背景色
.type(InputType.Password) // 输入框类型
名称 | 描述 |
---|---|
Normal | 基本输入模式。支持输入数字、字母、下划线、空格、特殊字符 |
Password | 密码输入模式。支持输入数字、字母、下划线、空格、特殊字符 |
邮箱地址输入模式。支持数字,字母,下划线,以及@字符. | |
Number | 纯数字输入模式 |
PhoneNumber | 电话号输入模式,支持输入数字、+、-、*、#、长度不限 |
2.4、Button按钮组件
- 声明Button组件,label是按钮文字
Button(label?: ResourceStr)
- 文字型按钮
Button('点我')
- 自定义按钮,在Button内嵌套其它组件
Button(){Image($r('app.media.search')).width(20).margin(10)}
- 文字型按钮
- 添加属性和事件
Button('点我') .width(100) .height(30) .type(ButtonType.Normal) // 按钮类型 .onClick(() => { //处理点击事件 }
名称 | 描述 |
---|---|
Capsule | 胶囊型按钮 (圆角默认为高度的一半) |
Circle | 圆形按钮 |
Normal | 普通按钮 (默认不带圆角) |
2.5、Slider滑动条组件
Silder(options?: SliderOptions )
slider({
min: 0,// 最小值
max: 100,// 最大值
value: 30 ,// 当前值
step: 1,// 滑动步长
style: SliderStyle.OutSet,// InSet
direction: Axis.Horizontal,// Vertical
reverse: false //是否反向滑动
)}
属性与事件
.width('90%')
.showTips(true)//是否展示value 百分比提示
.blockColor('#36d')
.onChange(value => {
//value就是当前滑块值
})
2.6、Column和Row
属性方法名 | 说明 | 参数 |
---|---|---|
justifyContent | 设置子元素在主轴方向的对齐格式 | FlexAlign枚举 |
alignItems | 设置子元素的交叉轴方向的对齐方式 | Row容器使用VerticalAlign枚举,Column容器使用HorizontalAlign枚举 |
@Entry
@Component
struct Index {
build() {
Column({space: 20}){
Text('item1')
Text('item2')
Text('item3')
Text('item4')
}
.width('100%')
.height('100%')
.margin({top:10})
.padding({top:20})
justifyContent(FlexAlign.Center)
alignItems(HorizontalAlign.Center)
}
}
2.7、循环控制
class Item{
name:string
image:ResourceStr
price:number
discount:number
constructor(name: string,image:ResourceStr,price:number,discount:number=0) {
this.name = name
this.image = image
this.price = price
this.discount = discount
}
}
@Entry
@Component
struct ItemPage {
private items :Array<Item> = [
new Item('荣耀',$r('app.media.honor30'),3999),
new Item('oppo',$r('app.media.oppoR17'),2999),
new Item('iPhone',$r('app.media.iPhoneX'),8999,1899),
]
build() {
Column({space:8}) {
Row(){
Text('商品列表')
.fontWeight(FontWeight.Bold)
.fontSize(30)
}
.width('100%')
.margin({bottom:20})
ForEach(
this.items,
item=>{
Row({space:10}){
Image(item.image)
.width(100)
Column(){
Text(item.name)
.fontSize(20)
.fontWeight(FontWeight.Bold)
if (item.discount) {
Text('原价:¥'+item.price)
.decoration({type:TextDecorationType.LineThrough,color:Color.Black})
Text('现价:¥'+(item.price-item.discount))
.fontSize(18)
.fontColor('#F36')
Text('折扣:¥'+item.discount)
.fontSize(18)
.fontColor('#F36')
}else {
Text('原价:¥'+item.price)
.fontSize(18)
.fontColor('#F36')
}
}
}
.width('80%')
.justifyContent(FlexAlign.Start)
}
)
}
.width('100%')
.height('100%')
}
}
2.8、List
列表(List)是一种复杂容器,具备下列特点
- 列表项(ListItem)数量过多超出屏幕后,会自动提供滚动功能
- 列表项 (ListItem)既可以纵向排列,也可以横向排列
2.9、自定义组件
-
自定义组件\
@Component struct MyComponent { private title: string build(){ //组UI描述 Text(this.title) } }
@Entry @Component struct XxxPage{ build(){ //引用组件 MyComonent({title:'订单列表'}) } }
-
自定义构建函数,可以定义在全局或组件内
//全局自定义构建函数 @Builder function XxxBuilder(){ //UI描达 }
@Component struct XxxComponent { //组件内自定义构建函数 @Builder YyyBuilder(){ //UI描达 } build(){ XxxBuilder() this.YyyBuilder() } }
-
@Styles装饰器,仅可封装组件通用属性
//全局公共样式
@Styles function fillScreen(){
.width('100%')
.height('100%')
}
@Entry
@Component
struct XxxPage [
//组件内公共样式
@Styles normalBackground(){
.backgroundColor('#EFEFEF')
.padding(14)
}
build(){
Row() {/*...*/}
.filiScreen()
.normalBackground()
}
}
- @Extend装饰器,仅可定义在全局,可以设置组件特有属性
@Extend(Text) function priceText(){
.fontSize(18)
.fontColor('#F36')
}
三、状态管理
3.1、@State装饰器
在声明式UI中,是以状态驱动视图更新:
- 状态(State):指驱动视图更新的数据(被装饰器标记的变量)
- 视图(View):基于UI描述渲染得到用户界面
注意
- @State装饰器标记的变量必须初始化,不能为空值
- @State支持Object、class、string、number、boolean、enum类型以及这些类型的数组
- 嵌套类型以及数组中的对象属性无法触发视图更新
3.2、任务统计案例
//任务类
class Task {
static id: number = 1
//任务名称
name: string = `任务${Task.id++}`
//任务状态
finished: boolean = false
}
@Styles function card() {
.width('95%')
.padding(20)
.backgroundColor(Color.White)
.borderRadius(15)
.shadow({ radius: 6, color: '#1f000000', offsetX: 2, offsetY: 4 })
}
//任务完成样式
@Extend(Text) function finishedTask() {
.decoration({ type: TextDecorationType.LineThrough })
.fontColor('#B1B2B1')
}
@Entry
@Component
struct propPage {
//总任务数量
@State totalTask: number = 0
//已完成任务数量
@State finishTask: number = 0
//任务数量
@State tasks: Task[] = []
handleTaskChange() {
//1.更新任务数量
this.totalTask = this.tasks.length
//通过过滤得出已完成的数量
this.finishTask = this.tasks.filter(item => item.finished).length
}
build() {
Column({ space: 10 }) {
//1. 任务进度
Row() {
//文本
Text('任务进度')
.fontSize(30)
.fontWeight(FontWeight.Bold)
//栈排列方式,两个容器相覆盖
Stack() {
Progress({
value: this.finishTask,
total: this.totalTask,
type: ProgressType.Ring
})
.width(100)
Row() {
Text(this.finishTask.toString())
.fontSize(24)
.fontColor('#36D')
Text('/' + this.totalTask.toString())
.fontSize(24)
}
}
}
.card()
.margin({ top: 10, bottom: 20 })
.justifyContent(FlexAlign.SpaceEvenly)
//2.新增任务按钮
Button('新增任务')
.width(200)
.onClick(() => {
//1.新增任务数据
this.tasks.push(new Task)
//2.更新任务数量
this.handleTaskChange()
})
//3. 任务列表
List({ space: 10 }) {
ForEach(
this.tasks,
(item: Task, index) => {
ListItem() {
Row() {
Text(item.name)
.fontSize(20)
Checkbox()
.select(item.finished)
.onChange(val => {
item.finished = val
//通过过滤得出已完成的数量
this.handleTaskChange()
})
}
.card()
.justifyContent(FlexAlign.SpaceBetween)
}
//增加后面的滑动功能
.swipeAction({end: this.DeleteButton(index)})
}
)
}
.width('100%')
.layoutWeight(1)
.alignListItem(ListItemAlign.Center)
}
.width('100%')
.height('100%')
.backgroundColor('#f1f2f3')
}
//构建函数 删除按钮
@Builder DeleteButton(index){
Button()
.width(40)
.height(40)
.type(ButtonType.Circle)
.backgroundColor(Color.Red)
.margin(5)
//点击事件,当点击当前按钮时,会删除该任务
.onClick(()=>{
this.tasks.splice(index,1)
//更新数量
this.handleTaskChange()
})
}
}
3.3、@Prop、@Link、@Provide和@Consume
当父子组件之间需要数据同步时,可以使用@Prop和@Link装饰器
@Prop | @Link | |
---|---|---|
同步类型 | 单向同步 | 双向同步 |
允许装饰的变量类型 | @Prop只支持string、number、boolean、enum类型;父组件对象类型,子组件是对象属性;不可以是数组、any | 父子类型一致: string、number、boolean、enum、object、class,以及他们的数组;数组中元素增、删、替换会引起刷新嵌套类型以及数组中的对象属性无法触发视图更新 |
初始化方式 | 不允许子组件初始化 | 父组件传递,禁止子组件初始化 |
修改后的代码
//任务类
class Task {
static id: number = 1
//任务名称
name: string = `任务${Task.id++}`
//任务状态
finished: boolean = false
}
@Styles function card() {
.width('95%')
.padding(20)
.backgroundColor(Color.White)
.borderRadius(15)
.shadow({ radius: 6, color: '#1f000000', offsetX: 2, offsetY: 4 })
}
//任务完成样式
@Extend(Text) function finishedTask() {
.decoration({ type: TextDecorationType.LineThrough })
.fontColor('#B1B2B1')
}
class TaskNum {
//总任务数量
totalTask: number = 0
//已完成任务数量
finishTask: number = 0
}
@Entry
@Component
struct propPage {
//总任务数量
@State tasknum: TaskNum = new TaskNum()
build() {
Column({ space: 10 }) {
//1. 任务进度
TaskStatus({totalTask:this.tasknum.totalTask,finishTask:this.tasknum.finishTask})
//2.新增任务按钮
//3. 任务列表
TaskList({tasknum: $tasknum})
}
.width('100%')
.height('100%')
.backgroundColor('#f1f2f3')
}
}
@Component
struct TaskStatus {
//总任务数量
@Prop totalTask: number
//已完成任务数量
@Prop finishTask: number
build() {
Row() {
//文本
Text('任务进度')
.fontSize(30)
.fontWeight(FontWeight.Bold)
//栈排列方式,两个容器相覆盖
Stack() {
Progress({
value: this.finishTask,
total: this.totalTask,
type: ProgressType.Ring
})
.width(100)
Row() {
Text(this.finishTask.toString())
.fontSize(24)
.fontColor('#36D')
Text('/' + this.totalTask.toString())
.fontSize(24)
}
}
}
.card()
.margin({ top: 10, bottom: 20 })
.justifyContent(FlexAlign.SpaceEvenly)
}
}
@Component
struct TaskList {
//总任务数量
@Link tasknum: TaskNum
//任务数量
@State tasks: Task[] = []
handleTaskChange() {
//1.更新任务数量
this.tasknum.totalTask = this.tasks.length
//通过过滤得出已完成的数量
this.tasknum.finishTask = this.tasks.filter(item => item.finished).length
}
build() {
Column(){
//2.新增任务按钮
Button('新增任务')
.width(200)
.margin({bottom:10})
.onClick(() => {
//1.新增任务数据
this.tasks.push(new Task)
//2.更新任务数量
this.handleTaskChange()
})
//3. 任务列表
List({ space: 10 }) {
ForEach(
this.tasks,
(item: Task, index) => {
ListItem() {
Row() {
Text(item.name)
.fontSize(20)
Checkbox()
.select(item.finished)
.onChange(val => {
item.finished = val
//通过过滤得出已完成的数量
this.handleTaskChange()
})
}
.card()
.justifyContent(FlexAlign.SpaceBetween)
}
//增加后面的滑动功能
.swipeAction({end: this.DeleteButton(index)})
}
)
}
.width('100%')
.layoutWeight(1)
.alignListItem(ListItemAlign.Center)
}
}
//构建函数 删除按钮
@Builder DeleteButton(index){
Button()
.width(40)
.height(40)
.type(ButtonType.Circle)
.backgroundColor(Color.Red)
.margin(5)
//点击事件,当点击当前按钮时,会删除该任务
.onClick(()=>{
this.tasks.splice(index,1)
//更新数量
this.handleTaskChange()
})
}
}
修改后的代码
//任务类
class Task {
static id: number = 1
//任务名称
name: string = `任务${Task.id++}`
//任务状态
finished: boolean = false
}
@Styles function card() {
.width('95%')
.padding(20)
.backgroundColor(Color.White)
.borderRadius(15)
.shadow({ radius: 6, color: '#1f000000', offsetX: 2, offsetY: 4 })
}
//任务完成样式
@Extend(Text) function finishedTask() {
.decoration({ type: TextDecorationType.LineThrough })
.fontColor('#B1B2B1')
}
class TaskNum {
//总任务数量
totalTask: number = 0
//已完成任务数量
finishTask: number = 0
}
@Entry
@Component
struct propPage {
//统计信息
@Provide tasknum: TaskNum = new TaskNum()
build() {
Column({ space: 10 }) {
//1. 任务进度
TaskStatus()
//2.新增任务按钮
//3. 任务列表
TaskList()
}
.width('100%')
.height('100%')
.backgroundColor('#f1f2f3')
}
}
@Component
struct TaskStatus {
//总任务数量
@Consume tasknum: TaskNum
build() {
Row() {
//文本
Text('任务进度')
.fontSize(30)
.fontWeight(FontWeight.Bold)
//栈排列方式,两个容器相覆盖
Stack() {
Progress({
value: this.tasknum.finishTask,
total: this.tasknum.totalTask,
type: ProgressType.Ring
})
.width(100)
Row() {
Text(this.tasknum.finishTask.toString())
.fontSize(24)
.fontColor('#36D')
Text('/' + this.tasknum.totalTask.toString())
.fontSize(24)
}
}
}
.card()
.margin({ top: 10, bottom: 20 })
.justifyContent(FlexAlign.SpaceEvenly)
}
}
@Component
struct TaskList {
//总任务数量
@Consume tasknum: TaskNum
//任务数量
@State tasks: Task[] = []
handleTaskChange() {
//1.更新任务数量
this.tasknum.totalTask = this.tasks.length
//通过过滤得出已完成的数量
this.tasknum.finishTask = this.tasks.filter(item => item.finished).length
}
build() {
Column(){
//2.新增任务按钮
Button('新增任务')
.width(200)
.margin({bottom:10})
.onClick(() => {
//1.新增任务数据
this.tasks.push(new Task)
//2.更新任务数量
this.handleTaskChange()
})
//3. 任务列表
List({ space: 10 }) {
ForEach(
this.tasks,
(item: Task, index) => {
ListItem() {
Row() {
Text(item.name)
.fontSize(20)
Checkbox()
.select(item.finished)
.onChange(val => {
item.finished = val
//通过过滤得出已完成的数量
this.handleTaskChange()
})
}
.card()
.justifyContent(FlexAlign.SpaceBetween)
}
//增加后面的滑动功能
.swipeAction({end: this.DeleteButton(index)})
}
)
}
.width('100%')
.layoutWeight(1)
.alignListItem(ListItemAlign.Center)
}
}
//构建函数 删除按钮
@Builder DeleteButton(index){
Button()
.width(40)
.height(40)
.type(ButtonType.Circle)
.backgroundColor(Color.Red)
.margin(5)
//点击事件,当点击当前按钮时,会删除该任务
.onClick(()=>{
this.tasks.splice(index,1)
//更新数量
this.handleTaskChange()
})
}
}
3.4、@Observe和@ObjectLink
@obiectLink和@Observed装饰器用于在涉及嵌套对象或数组元素为对象的场景中进行双向数据同步
@Observed
class Person {
name: string
age: number
gf: Person
constructor(name: string, age: number,gf?: Person) {
this.name = name
this.age = age
this.gf = gf
}
}
@Component
struct Child {
@ObjectLink p: Person
build() {
Column() {
Text(`s[this.p.name] : s[this.p.age]`)
}
}
}
@Entry
@Component
struct Parent {
@State p: Person = new Person('Jack', 21, new Person( ' Rose',18))
@State gfs: Person[] = [new Person('萝丝',18),new Person('露西',19),]
build() {
Column() {
Child([p: this.p.gf}).onClick(() => this.p.gf.age++)
Text('====== 女友列表 ======!')
ForEach(
this.gfs,
p=>{
Child([p: p}).onClick(() => p.age++)
}
}
}
}
}
最终修改代码
//任务类
@Observed
class Task {
static id: number = 1
//任务名称
name: string = `任务${Task.id++}`
//任务状态
finished: boolean = false
}
@Styles function card() {
.width('95%')
.padding(20)
.backgroundColor(Color.White)
.borderRadius(15)
.shadow({ radius: 6, color: '#1f000000', offsetX: 2, offsetY: 4 })
}
//任务完成样式
@Extend(Text) function finishedTask() {
.decoration({ type: TextDecorationType.LineThrough })
.fontColor('#B1B2B1')
}
class TaskNum {
//总任务数量
totalTask: number = 0
//已完成任务数量
finishTask: number = 0
}
@Entry
@Component
struct propPage {
//统计信息
@Provide tasknum: TaskNum = new TaskNum()
build() {
Column({ space: 10 }) {
//1. 任务进度
TaskStatus()
//2.新增任务按钮
//3. 任务列表
TaskList()
}
.width('100%')
.height('100%')
.backgroundColor('#f1f2f3')
}
}
@Component
struct TaskStatus {
//总任务数量
@Consume tasknum: TaskNum
build() {
Row() {
//文本
Text('任务进度')
.fontSize(30)
.fontWeight(FontWeight.Bold)
//栈排列方式,两个容器相覆盖
Stack() {
Progress({
value: this.tasknum.finishTask,
total: this.tasknum.totalTask,
type: ProgressType.Ring
})
.width(100)
Row() {
Text(this.tasknum.finishTask.toString())
.fontSize(24)
.fontColor('#36D')
Text('/' + this.tasknum.totalTask.toString())
.fontSize(24)
}
}
}
.card()
.margin({ top: 10, bottom: 20 })
.justifyContent(FlexAlign.SpaceEvenly)
}
}
@Component
struct TaskList {
//总任务数量
@Consume tasknum: TaskNum
//任务数量
@State tasks: Task[] = []
handleTaskChange() {
//1.更新任务数量
this.tasknum.totalTask = this.tasks.length
//通过过滤得出已完成的数量
this.tasknum.finishTask = this.tasks.filter(item => item.finished).length
}
build() {
Column(){
//2.新增任务按钮
Button('新增任务')
.width(200)
.margin({bottom:10})
.onClick(() => {
//1.新增任务数据
this.tasks.push(new Task)
//2.更新任务数量
this.handleTaskChange()
})
//3. 任务列表
List({ space: 10 }) {
ForEach(
this.tasks,
(item: Task, index) => {
ListItem() {
TaskItem({item:item,onTaskChange:this.handleTaskChange.bind(this)})
}
//增加后面的滑动功能
.swipeAction({end: this.DeleteButton(index)})
}
)
}
.width('100%')
.layoutWeight(1)
.alignListItem(ListItemAlign.Center)
}
}
//构建函数 删除按钮
@Builder DeleteButton(index){
Button()
.width(40)
.height(40)
.type(ButtonType.Circle)
.backgroundColor(Color.Red)
.margin(5)
//点击事件,当点击当前按钮时,会删除该任务
.onClick(()=>{
this.tasks.splice(index,1)
//更新数量
this.handleTaskChange()
})
}
}
@Component
struct TaskItem {
@ObjectLink item:Task
onTaskChange :()=>void
build() {
Row() {
if(this.item.finished){
Text(this.item.name)
.finishedTask()
.fontSize(20)
}else {
Text(this.item.name)
.fontSize(20)
}
Checkbox()
.select(this.item.finished)
.onChange(val => {
this.item.finished = val
//通过过滤得出已完成的数量
this.onTaskChange
})
}
.card()
.justifyContent(FlexAlign.SpaceBetween)
}
}
- 子组件调用父组件时可能会出现this丢失
- 在传递函数到子组件时,绑定
.bind(this)
- 在传递函数到子组件时,绑定
四、页面路由
页面路由是指在应用程序中实现不同页面之间的跳转和数据传递
- 页面栈的最大容量上限为32个页面使用
router.clear()
方法可以清空页面栈,释放内存 - Router有两种页面跳转模式,分别是:
router.pushUrl()
: 目标页不会替换当前页,而是压入页面栈,因此可以用router.back()
返回当前页router.replaceUrl()
: 目标页替换当前页,当前页会被销毁并释放资源,无法返回当前页
- Router有两种页面实例模式,分别是:
Standard
:标准实例模式,每次跳转都会新建一个目标页并压入栈顶。默认就是这种模式Single
:单实例模式,如果目标页已经在栈中,则离栈顶最近的同Ur亿页面会被移动到栈顶并重新加载
使用:
- 首先要导入HarmonyOS提供的Router模块
import router from '@ohos .router';
- 然后利用router实现跳转、返回等操作
// 跳转到指定路径,并传递参数
router.pushUrl({
/*
RouterOptions
- url:目标页面路径
- params:传递的参数(可选)
*/
url:'pages/ImagePage'
params: {id: 1}
},
//页面模式:RouterMode枚举
router.RouterMode.Single
err =>{
/*
异常响应回调函数,错误码:
- 100001:内部错误,可能是染失败
- 100002:路由地址错误
- 100003:路由栈中页面超过32
*/
if(err){
console.log('路由失败。')
}
})
//获取传递过来的参数
params: any = router.getParams()
// 返回上一页
router.back()
//返回到指定页,并携带参数
router.back({
url: 'pages/Index',
params: {id: 10}
})
五、动画
5.1、属性动画
属性动画是通过设置组件的animation属性来给组件添加动画,当组件的width、height、Opacity、backgroundColor、scale、rotate、translate等属性变更时,可以实现渐变过渡效果。
Text('^_^')
.position({
x: 10,// x轴坐标
y:0 // y轴坐标
})
.rotate({
angle: 0,// 旋转角度
centerX:'50%',//旋转中心横坐标
centerY:'50%',//旋转中心纵坐标
})
.animation({
duration: 1000,
curve: Curve.EaseInOut
})
名称 | 参数类型 | 必填 | 描述 |
---|---|---|---|
duration | number | 否 | 设置动画时长;默认值: 1000;单位:毫秒。 |
tempo | number | 否 | 动画播放速度。;数值越大,速度越快;默认值:1。 |
curve | string | Curve | 否 | 设置动画曲线。;默认值: Curve.EaselnOut,平滑开始和结束。 |
delay | number | 否 | 设置动画延迟执行的时长;默认值:0,单位:毫秒。 |
iterations | number | 否 | 设置播放次数。;默认值: 1,取值范围:[-1,+∞);说明:设置为-1时表示无限次播放。 |
playMode | PlayMode | 否 | 设置动画播放模式,默认播放完成后重头开始播放;默认值: PlayMode.Normal。 |
onFinish | ()=> void | 否 | 状态回调,动画播放完成时触发。 |
5.2、显式动画
显式动画是通过全局animateTo函数来修改组件属性,实现属性变化时的渐变过渡效果。
Text('^_^')
.position({
x: 10,// x轴坐标
y:0 // y轴坐标
})
.rotate({
angle: 0,// 旋转角度
centerX:'50%',//旋转中心横坐标
centerY:'50%',//旋转中心纵坐标
})
//显调用animateTo函数触发动四
animateTo(
{duration: 1000},//动画参数
()=>{
//修改组件属性关联的状态交品
})
名称 | 参数类型 | 必填 | 描述 |
---|---|---|---|
duration | number | 否 | 设置动画时长;默认值: 1000;单位:毫秒。 |
tempo | number | 否 | 动画播放速度。;数值越大,速度越快;默认值:1。 |
curve | string | Curve | 否 | 设置动画曲线。;默认值: Curve.EaselnOut,平滑开始和结束。 |
delay | number | 否 | 设置动画延迟执行的时长;默认值:0,单位:毫秒。 |
iterations | number | 否 | 设置播放次数。;默认值: 1,取值范围:[-1,+∞);说明:设置为-1时表示无限次播放。 |
playMode | PlayMode | 否 | 设置动画播放模式,默认播放完成后重头开始播放;默认值: PlayMode.Normal。 |
onFinish | ()=> void | 否 | 状态回调,动画播放完成时触发。 |
5.3、组件转场动画
组件转场动画是在组件插入或移除时的过渡动画通过组件的transition属性来配置
if(this.isShow){
Text('^_^')
.transition({//转场动画参数
opcity:0,
rotate: {angle: -360],
scale:{x:0,y: 0}
})
}
//显式调用animateTo函数触发动画
animateTo(
{duration: 1000},// 动画参数
()=>{
this.isShow = false
}
}
参数名称 | 参数类型 | 必填 | 参数描述 |
---|---|---|---|
type | TransitionType | 否 | 类型,默认包括组件新增和删除。默认是ALL |
opacity | number | 否 | 不透明度,为插入时起点和删除时终点的值。默认值:1,取值范围:[0,1] |
translate | {x? : number|string,y? : number| string,z? : number| string} | 否 | 平移效果,为插入时起点和删除时终点的值。-X:横向的平移距离。-y: 纵向的平移距离。-z: 竖向的平移距离。 |
scale | {x? :number,y? : number,z? : number,centerX? : number|string},centerY? : number|string} | 否 | 缩放效果,为插入时起点和删除时终点的值。-x:横向放大倍数(或缩小比例)。-y:纵向放大倍数(或缩小比例)。-z:当前为二维显示,该参数无效。-centerX、centerY指缩放中心点,centerX和 centerY默认值是"50%"。-中心点为0时,默认的是组件的左上角。 |
rotate | {x?: number,y?: number,z?: number,angle: number|string,centerX?: number|string,centerY?: number| string} | 否 | 旋转效果:angle是旋转角度,其它参数与scale类似 |
5.4、实现摇杆功能
注意点
onTouch()
函数
.onTouch(this.handleTouchEvent.bind(this))
//自定义onTouch函数
handleTouch(event:TouchEvent){
}
获取手指位置坐标
//手指x坐标
let x = event.touches[0].x
//手指y坐标
let y = event.touches[0].x
计算手指与中心点连线和x轴正半轴的夹角,单位是弧度
let angle = Math.atan2(x,y)
//sin
sin = Math.sin(angle)
//cos
cos = Math.sin(angle)
使遥感连续的动画
animateTo(
{curve:curves.responsiveSpringMotion()},
()=>{
//要执行动画的函数
}
)
switch
屏幕事件
switch(event.type){
case TouchType.Up:
case TouchType.Down:
case TouchType.Move:
}
修改指定事务的角度
if(Math.abs(angle *2)<Math.PI){
this.src = $r('app.media.fish')
}else{
this.src = $r('app.media.fish_rev')
angle = angle <0?angle + Math.PI:angle - Math.PI
}
this.angle = angle*180/Math.PI
六、Stage模型
6.1、Stage模型概述
6.2、Stage应用配置文件
app.json5主要包含以下内容:
- 应用的全局配置信息,包含应用的包名、开发厂商、版本号等基本信息。
- 特定设备类型的配置信息。
module.json5主要包含以下内容:
- Module的基本配置信息,例如Module名称、类型、描述、支持的设备类型等基本信息。
- 应用组件信息,包含UIAbility组件和ExtensionAbility组件的描述信息。
- 应用运行过程中所需的权限信息。
6.3、UIAbility生命周期
6.4、页面及组件生命周期
@Entry
@Component
struct PageA {
@State show: boolean = true
build(){
Column(){
Button('show')
.onClick(() => {
this,show = !this .show
})
if(this.show){
ComponentA()
}
}
}
}
@Component
struct ComponentA {
build(){
Row(){
Text(' component A')
}
}
}
6.5、UIAbility的启动模式
- singLeton启动模式
每一个UIAbility只存在唯一实例。是默认启动模式任务列表中只会存在一个相同的UIAbility - standard启动模式
每次启动UIAbitity都会创建一个新的实例。在任务列表中可能存在一个或多个相同的UIAbility - specified启动模式
每个UIAbility实例可以设置Kev标示例直接被拉起,不存在则创建新实例启动UIAbiTity时,需要指定key,存在key相同实
// 1当前UIAbility调用startAbility方法拉起目标UIAbility
// 1.1.获取上下文
context = getContext(this) as common.UIAbilityContext
// 1.2指定要跳转到的UIAbility的信息
let want = {
deviceId:'',// deviceId为空表示本设备
bundleName: 'com.example .myapplication',
abilityName: 'DocumentAbility',
moduleName: 'entry',// moduleName非必选
parameters: {
//getInstanceKey: 自定义方法,生成目标UIAbility实例的key
instanceKey: this.getInstancekey()
}
}
//1.3.尝试拉起目标UIAbility实例
this.context.startAbility(want)
//2.在Abilitystage的生命周期回调中为目标UIAbility实例生成key
export default class MyAbilityStage extends AbilityStage
onAcceptWant(want: Want): string {
//判断当前要拉取的是否是DocumentAbility
if(want.abilityName === 'DocumentAbility'){
// 根据参数中的instanceKey参数拼接生成一个key值并返回
return `DocAbility_${want.parameters.instanceKey}`
}
return'';
}
}
//3在module.json5配置文件中,通过srcEntry参数指定AbilityStage路径
{
"module":{
"name": "entry"
"type": "entry"
"srcEntry": "./ets/myabilitystage/MyAbilityStage.ts"
...
}
}
七、网络连接
7.1、Http数据请求
-
导入http模块
import http from '@ohos .net.http'
-
使用http模块发送请求,处理响应
// 2.1.创建一个http的请求对象,不可复用 let httpRequest = http.createHttp() // 2.2.发起网络请求 httpRequest.request( 'http://localhost:3000/users', { method: http.RequestMethod.GET, extraData: {'param1':'valuel' } // k1=v1&k2=v2 } ) // 2.3.处理响应结果 then( resp =>{ if(resp.responseCode === 200){ //请求成功 } }) .catch( err =>{ // 请求失败 });
HttpRequestOptions
名称 | 描述 | 类型 |
---|---|---|
method | RequestMethod | 请求方式,GET、POST、PUT、DELETE等 |
extraData | String|Object | 请求参数 |
header | Object | 请求头字段 |
connectTimeout | number | 连接超时时间,单位毫秒,默认是60000ms |
readTimeout | number | 读取超时间,同上 |
HttpResponse
名称 | 描述 | 类型 |
---|---|---|
responseCode | ResponseCode | 响应状态码 |
header | Object | 响应头 |
cookies | string | 响应返回的cookies |
result | string|object | 响应体,默认是JSON字符串 |
resultType | HttpDataType | 返回值类型。 |
7.2、第三方库axios
-
下载和安装ohpm、
- 下载ohpm工具包
- 解压工具包,执行初始化命令
# windows环境 init.bat #Linux和Mac环境 ./init.sh
- 将ohpm配置到环境变量
# windows环境,直接在我的电脑配置即可 #Linux和Mac环境,其中ohpm的路径替换为ohpm的安装路径 export OHPM_HOME=/xx/ohpm export PATH=${OHPM_HOME}/bin:${PATH}
-
下载和安装axios
- 下载axios
# 进入项目目录,然后输入下面命令 ohpm install @ohos/axios
- 开放网络权限
# 在模块的module.json5文件中配置网路权限 { "module":{ "requestPermissions": [ { "name":"ohos.permission.INTERNET" } ] } }
- 下载axios
-
使用axios
- 导入axios
# 导入axios模块 import axios from '@ohos/axios'
- 发送请求并处理响应
axios.get(//请求方式 'url',//请求路径 { params:{ 'param1': 'valuel' },//请求选项 data: { 'paraml': 'valuel' } } ) .then( response => { if(response.status !== 200){ console.log('查询失败') } console.log('查询成功') }) .catch(error => { console.log('查询失败',JSON.stringify(error)) }) }
- 导入axios
名称 | 类型 | 描述 |
---|---|---|
status | number | 响应状态码 |
headers | Object | 响应头 |
data | any | 服务端返回的响应体 |
八、数据持久化
8.1、用户首选项
用户首选项(Preference)为应用提供Key-Value键值型的数据处理能力,支持应用持久化轻量级数据
-
导入首选项模块
import dataPreference from '@ohos.data.preferences'
-
获取首选项实例,读取指定文件
dataPreference.getPreferences(this.context,'MyAppPreferences') .then(preferences => { //获取成功 }) .catch(reason =>{ //获取失败 })
-
数据操作
// 3.1.写入数据,如果已经存在则会覆盖,可利用.has()判断是否存在 preferences.put('key', val) .then(() => preferences.flush()) // 刷到磁盘 .catch(reason => {}) // 处理异常 //3.2.删除数据 preferences.delete(' key') .then(() => []).catch(reason => []) //3,3查询数据 preferences.get('key','defaultValue') .than(value=>console.log('查询成功')) .catch(reason=>console.log('查询失败'))
说明:
- Key为string类型,要求非空且长度不超过80字节
- Value可以是string、number、boolean及以上类型数组大小不超过8192字节
- 数据量不要超过一万条
PreferencesUtil
import preferences from '@ohos.data.preferences'
import { expect } from '@ohos/hypium'
class PreferencesUtil{
prefMap:Map<string,preferences.Preferences> = new Map()
//同步方法
async loadPreference(context,name:string){
try {
let pref = await preferences.getPreferences(context,name)
this.prefMap.set(name,pref)
console.log(`testTag`,`加载Preferences[${name}]成功`);
}catch (e){
console.log(`testTag`,`加载Preferences[${name}]失败`);
}
}
async putPreference(name:string,key:string,value:preferences.ValueType){
if (!this.prefMap.has(name)) {
console.log(`testTag`,`Preferences[${name}]尚未初始化`)
return
}
try {
let pref = this.prefMap.get(name)
//写入数据
await pref.put(key,value);
//刷盘
await pref.flush()
console.log(`testTag`,`保存Preferences[${name}.${key} = ${value}]成功`)
}catch (e){
console.log(`testTag`,`保存Preferences[${name}.${key} = ${value}]失败`,JSON.stringify(e))
}
}
async getPreference(name:string,key:string,defaultValue:preferences.ValueType){
if (!this.prefMap.has(name)) {
console.log(`testTag`,`Preferences[${name}]尚未初始化`)
return
}
try {
let pref = this.prefMap.get(name)
//读取数据
let value = await pref.put(key,defaultValue);
console.log(`testTag`,`读取Preferences[${name}.${key} = ${value}]成功`)
}catch (e){
console.log(`testTag`,`读取Preferences[${name}.${key}]失败`,JSON.stringify(e))
}
}
}
const preferencesUtil = new PreferencesUtil()
export default preferencesUtil as PreferencesUtil
8.2、关系型数据库
关系型数据库(RDB)是基于SQLite组件提供的本地数据库,用于管理应用中的结构化数据。例如:记账本、备忘录。
-
初始化数据库
- 导入关系型数据库模块
import relationalStore from '@ohos.data.relationalStore';
- 初始化数据库表
//2..rdb配置 const config = { name:'MyApplication.db',// 数据库文件名 securityLevel: relationalStore.SecurityLevel.S1 //数据库安全级别 } //2.2.初始化表的SOL const sql = `CREATE TABLE IF NOT EXISTS TASK ( ID INTEGER PRIMARY KEY, NAME TEXT NOT NULL, FINISHED bit )` // 2.3.获取rdb relationalStore.getRdbStore(this.context,config,(err,rdbStore) => { // 2.4执行SgL,后续的所有增删改查都是使用rdbstore对象 rdbStore.executeSql(sql) })
-
增、删、改数据
- 新增数据
// 1.1.准备数据 let task = {id: 1,name: '任务1',finished: false}; // 1.2.新增 this.rdbStore.insert(this.tableName, task)
- 修改
//2.1要更新的数据 let task = {'finished': true}; //2.2.查询条件,RdbPredicates就是条件谓词 let predicates = new relationalStore.RdbPredicates(this,tableName) predicates.equalTo('ID',id) //2.3.执行更新 this.rdbStore.update(task, predicates)
- 删除
//3.1.查询条件 let predicates = new relationalStore.RdbPredicates(this.tableName) predicates.equalTo('ID',id) //3.2.执行删除 this.rdbStore.delete(predicates)
-
查询数据
- 查询数据
// 1.1.查询条件 let predicates = new relationalstore.RdbPredicates(this.tableName) // 1.2.执行查询 let result= await this.rdbStore.query(predicates, ['ID','NAME','FINISHED'])
- 解析结果
// 2.1.准备数组保存结果 let tasks: any[] = [] //2.2循环遍历结果集,判断是否结果是否遍历到最后一行 while (!result.isAtLastRow){ // 指针移动到下一行数据 result.goToNextRow() // 根据字名获取字index,从而获取字段值 let id = result.getLong(result.getColumnIndex('ID')); let name = result.getString(result.getColumnIndex('NAME')); tasks.push(fid,name}) }
ID | NAME | FINISHED |
---|---|---|
1 | 任务1 | false |
2 | 任务2 | false |
3 | 任务3 | true |
九、通知
9.1、基础通知
应用可以通过通知接口发送通知消息,提醒用户关注应用中的变化。用户可以在通知栏查看和操作通知内容。
通知常见的使用场景:
- 显示接收到的短消息、即时消息等。
- 显示应用的推送消息,如广告、版本更新等。
- 显示当前正在进行的事件,如下载等。
-
导入notification模块
import notificationManager from '@ohos.notificationManager'
-
发布通知
//2.1.构建通知请求 let request: notificationManager.NotificationRequest = { id: 10, content:{ // 通知内容: } } //2.2.发布通知 notificationManager.publish(request) .then(() => console.log('发送通知成功')) .catch(reason => console,log('发送通知失败',JSON.stringify(reason)))
-
取消通知
//取消指定id的通知 notificationManager.cancel(10) // 取消当前应用所有通知 notificationManager.cancelAll()
类型 | 描述 |
---|---|
NOTIFICATION_CONTENT_BASIC_TEXT | 普通文本类型。 |
NOTIFICATION_CONTENT_LONG_TEXT | 长文本类型。 |
NOTIFICATION_CONTENT_MULTILINE | 多行文本类型。 |
NOTIFICATION_CONTENT_PICTURE | 图片类型。 |
- 普通文本类型通知由标题、文本内容和附加信息三个字段组成,其中标题和文本内容是必填字段。
let notificationRequest = {
id: 1,
content: {
contentType: NotificationManager.ContentType.NOTIFICATION_CONTENT_BASIC_TEXT, // 普通文本类型通知
normal: {
title: 'test_title',//通知标题
text: 'test_text',//通知内容
additionalText: 'test_additionalText',//通知附加的内容
}
}
}
NotificationManager.publish(notificationRequest, (err) => {
if (err) {
console.error(`[ANS] failed to publish, error[${err}]`);
return;
}
console.info(`[ANS] publish success`);
});
- 长文本类型通知继承了普通文本类型的字段,同时新增了长文本内容、内容概要和通知展开时的标题。通知默认显示与普通文本相同,展开后,标题显示为展开后标题内容,内容为长文本内容。
let notificationRequest = {
id: 1,
content: {
contentType: NotificationManager.ContentType.NOTIFICATION_CONTENT_LONG_TEXT, // 长文本类型通知
longText: {
title: 'test_title',//通知标题
text: 'test_text',//通知内容
additionalText: 'test_additionalText',//通知附加的内容
longText: 'test_longText',//通知的长文本
briefText: 'test_briefText',//通知的概要和总结
expandedTitle: 'test_expandedTitle',//通知展开时的标题
}
}
}
// 发布通知
NotificationManager.publish(notificationRequest, (err) => {
if (err) {
console.error(`[ANS] failed to publish, error[${err}]`);
return;
}
console.info(`[ANS] publish success`);
});
- 多行文本类型通知继承了普通文本类型的字段,同时新增了多行文本内容、内容概要和通知展开时的标题。通知默认显示与普通文本相同,展开后,标题显示为展开后标题内容,多行文本内容多行显示。
let notificationRequest = {
id: 1,
content: {
contentType: NotificationManager.ContentType.NOTIFICATION_CONTENT_MULTILINE, // 多行文本类型通知
multiLine: {
title: 'test_title',//通知标题
text: 'test_text',//通知内容
briefText: 'test_briefText',//通知的概要和总结
longTitle: 'test_longTitle',//展开后的标题
lines: ['line_01', 'line_02', 'line_03', 'line_04'],
}
}
}
// 发布通知
NotificationManager.publish(notificationRequest, (err) => {
if (err) {
console.error(`[ANS] failed to publish, error[${err}]`);
return;
}
console.info(`[ANS] publish success`);
});
- 图片类型通知继承了普通文本类型的字段,同时新增了图片内容、内容概要和通知展开时的标题,图片内容为PixelMap型对象,其大小不能超过2M。
let imagePixelMap: PixelMap = undefined; // 需要获取图片PixelMap信息
let notificationRequest: notificationManager.NotificationRequest = {
id: 1,
content: {
contentType: notificationManager.ContentType.NOTIFICATION_CONTENT_PICTURE,
picture: {
title: 'test_title',
text: 'test_text',
additionalText: 'test_additionalText',
briefText: 'test_briefText',//通知概要
expandedTitle: 'test_expandedTitle',
picture: this.pixel//像素图
}
}
};
async aboutToAppear(){
//获取资源管理器
let rm = getContext(this).resourceManager;
//读取图片
let file = await rm.getMediaContent($r('app.media.watchGT4'))
//创建PixelMap
image.createImageSource(file.buffer).createPixelMap()
.then(value => this.pixel = value)
.catch(reason => console.log('testTag,载图片异常',JSON.stringify(reason)))
}
// 发布通知
notificationManager.publish(notificationRequest, (err) => {
if (err) {
console.error(`Failed to publish notification. Code is ${err.code}, message is ${err.message}`);
return;
}
console.info('Succeeded in publishing notification.');
});
更多属性
let notificationRequest = {
id: 1,
content: {
contentType: NotificationManager.ContentType.NOTIFICATION_CONTENT_BASIC_TEXT, // 普通文本类型通知
normal: {
title: 'test_title',//通知标题
text: 'test_text',//通知内容
additionalText: 'test_additionalText',//通知附加的内容
}
},
deliveryTime: new Date().getTime(),
showDeliveryTime: true,
groupName: 'wechat',
slotType: notify.slotType.SOCIAL_COMMUNICATION,
}
类型枚举 | 说明 | 状态栏图标 | 提示音 | 横幅 |
---|---|---|---|---|
SOCIAL_COMMUNICATION | 社交类型 | √ | √ | √ |
SERVICE_INFORMATION | 服务类型 | √ | √ | × |
CONTENT_INFORMATION | 内容类型 | √ | × | × |
OTHER_TYPES | 其它 | × | × | × |
9.2、进度条通知
进度条通知会展示一个动态的进度条,主要用于文件下载、长任务处理的进度显示。
isSupportTemplate()
是查询模板是否支持接口,目前仅支持进度条模板。
-
导入模块。
import NotificationManager from '@ohos.notificationManager';
-
查询系统是否支持进度条模板,查询结果为支持downloadTemplate模板类通知。
NotificationManager.isSupportTemplate('downloadTemplate').then((data) => { console.info(`[ANS] isSupportTemplate success`); let isSupportTpl: boolean = data; // isSupportTpl的值为true表示支持支持downloadTemplate模板类通知,false表示不支持 // ... }).catch((err) => { console.error(`[ANS] isSupportTemplate failed, error[${err}]`); });
-
构造进度条模板对象,并发布通知。
let template = { name:'downloadTemplate', data: { title: '标题:', fileName: 'music.mp4', progressValue: 30, progressMaxValue:100, } } //构造NotificationRequest对象 let notificationRquest = { id: 1, slotType: notify.SlotType.OTHER_TYPES, template: template, content: { contentType: notify.ContentType.NOTIFICATION_CONTENT_BASIC_TEXT, normal: { title: template.data.title + template.data.fileName, text: "sendTemplate", additionalText: "30%" } }, deliveryTime: new Date().getTime(), showDeliveryTime: true } notify.publish(notificationRquest).then(() => { console.info(`[ANS] publish success `); }).catch((err) => { console.error(`[ANS] failed to publish, error[${err}]`); });
9.3、通知行为意图
我们可以给通知或其中的按钮设置的行为意图 (want),从而实现拉起应用组件或发布公共事件等能力
接口名 | 描述 |
---|---|
getWantAgent(info: WantAgentInfo, callback: AsyncCallback<WantAgent>): void | 创建WantAgent。 |
trigger(agent: WantAgent, triggerInfo: TriggerInfo, callback?: Callback<CompleteData>): void | 触发WantAgent意图。 |
cancel(agent: WantAgent, callback: AsyncCallback<void>): void | 取消WantAgent。 |
getWant(agent: WantAgent, callback: AsyncCallback<Want>): void | 获取WantAgent的want。 |
equal(agent: WantAgent, otherAgent: WantAgent, callback: AsyncCallback<boolean>): void | 判断两个WantAgent实例是否相等。 |
//1.意图行为信息
let wantInfo = {
wants: [
{
deviceId:'',
bundleName:'com.example.myapplication',
abilityName:'EntryAbility',
action:'',
entities:[]
}
},
operationType: wantAgent.OperationType.START_ABILITY,
requestCode: 0,
wantAgentFlags: [wantAgent.WantAgentFlags.CONSTANT_FLAG]
}
// 2.创建wantAgent实例
this.wantAgentInstance = await wantAgent.getwantAgent(wantInfo)
// 3.通知请求
let request: notify.NotificationRequest = {
id: 999,
template: template,
wantAgent; this.wantAgentInstance,// 设置通知意图
content: {
//..
}
}