HarmonyOS 开发学习笔记

news2025/1/19 2:42:26

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:图片显示组件

  1. 声明Image组件并设置图片源:
    Image(src: string|PixelMap|Resource)
    
    1. string格式,通常用来加载网络图片,需要申请网络访问权限: ohos.permission.INTERNET
      Image('https://xxx .png')
    2. PixelMap格式,可以加载像素图,常用在图片编辑中
      Image(pixelMapobject)
    3. Resource格式,加载本地图片,推荐使用
      Image($r('app.media.mate60')) 对应在目录中的media目录下的图片
      Image($rawfile('mate60.png'))对应在目录中rawfile目录下的图片
  2. 添加图片属性
    Image($r('app.media.icon'))
    .width(100)宽度
    .height(120) //高度
    .borderRadius(10) //边框圆角
    .interpolation(ImageInterpolation.High) //图片插值
    

2.2、Text文本显示组件

  1. 声明Text组件并设置文本内容
    Text(content?: string|Resource)
    
    在这里插入图片描述
    1. string格式,直接填写文本内容
      Text('图片宽度')
    2. Resource格式,读取本地资源文件
      Text($r('app.string.width_label'))
  2. 添加文本属性
Text('注册账号')
	.lineHeight(32) // 行高
	.fontSize(20) // 字体大小
	.fontColor('#ff1876f8') // 字体颜色
	.fontweight(FontWeight.Medium) //字体粗细

2.3、TextInput文本输入框组件

  1. 声明TextInput组件

    TextInput( {placeholder?: ResourceStr, text?: ResourceStr])
    
    1. placeHoder:输入框无输入时的提示文本
      TextInput([placeholder:'请输入账号或手机号'})
    2. text:输入框当前的文本内容
      TextInput({text:'itcast'})
  2. 添加属性和事件

TextInput({text:'当前输入文本'})
	.width(150) // 宽
	.height(30) // 高
	.backgroundColor('#FFF') // 背景色
	.type(InputType.Password) // 输入框类型
名称描述
Normal基本输入模式。支持输入数字、字母、下划线、空格、特殊字符
Password密码输入模式。支持输入数字、字母、下划线、空格、特殊字符
Email邮箱地址输入模式。支持数字,字母,下划线,以及@字符.
Number纯数字输入模式
PhoneNumber电话号输入模式,支持输入数字、+、-、*、#、长度不限

2.4、Button按钮组件

  1. 声明Button组件,label是按钮文字
    Button(label?: ResourceStr)
    
    1. 文字型按钮
      Button('点我')
    2. 自定义按钮,在Button内嵌套其它组件
      Button(){Image($r('app.media.search')).width(20).margin(10)}
  2. 添加属性和事件
    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)是一种复杂容器,具备下列特点

  1. 列表项(ListItem)数量过多超出屏幕后,会自动提供滚动功能
  2. 列表项 (ListItem)既可以纵向排列,也可以横向排列

在这里插入图片描述

2.9、自定义组件

在这里插入图片描述

  1. 自定义组件\

    @Component
    struct MyComponent {
    	private title: string
    	build(){
    		//组UI描述
    		Text(this.title)
    	}
    }
    
    @Entry
    @Component
    struct XxxPage{
    build(){
    		//引用组件
    		MyComonent({title:'订单列表'})
    	}
    }
    
  2. 自定义构建函数,可以定义在全局或组件内

    //全局自定义构建函数
    @Builder function XxxBuilder(){
    	//UI描达
    }
    
    @Component
    struct XxxComponent {
    	//组件内自定义构建函数
    	@Builder YyyBuilder(){
    		//UI描达
    	}
    	build(){
    		XxxBuilder()
    		this.YyyBuilder()
    	}
    }
    
  3. @Styles装饰器,仅可封装组件通用属性

//全局公共样式
@Styles function fillScreen(){
	.width('100%')
	.height('100%')
}
@Entry
@Component
struct XxxPage [
	//组件内公共样式
	@Styles normalBackground(){
		.backgroundColor('#EFEFEF')
		.padding(14)
	}
	build(){
		Row() {/*...*/}
			.filiScreen()
			.normalBackground()
	}
}
  1. @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亿页面会被移动到栈顶并重新加载

使用:

  1. 首先要导入HarmonyOS提供的Router模块
    import router from  '@ohos .router';
    
  2. 然后利用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
	})
名称参数类型必填描述
durationnumber设置动画时长;默认值: 1000;单位:毫秒。
temponumber动画播放速度。;数值越大,速度越快;默认值:1。
curvestring | Curve设置动画曲线。;默认值: Curve.EaselnOut,平滑开始和结束。
delaynumber设置动画延迟执行的时长;默认值:0,单位:毫秒。
iterationsnumber设置播放次数。;默认值: 1,取值范围:[-1,+∞);说明:设置为-1时表示无限次播放。
playModePlayMode设置动画播放模式,默认播放完成后重头开始播放;默认值: 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},//动画参数
()=>{
	//修改组件属性关联的状态交品
})
名称参数类型必填描述
durationnumber设置动画时长;默认值: 1000;单位:毫秒。
temponumber动画播放速度。;数值越大,速度越快;默认值:1。
curvestring | Curve设置动画曲线。;默认值: Curve.EaselnOut,平滑开始和结束。
delaynumber设置动画延迟执行的时长;默认值:0,单位:毫秒。
iterationsnumber设置播放次数。;默认值: 1,取值范围:[-1,+∞);说明:设置为-1时表示无限次播放。
playModePlayMode设置动画播放模式,默认播放完成后重头开始播放;默认值: 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
	}
}
参数名称参数类型必填参数描述
typeTransitionType类型,默认包括组件新增和删除。默认是ALL
opacitynumber不透明度,为插入时起点和删除时终点的值。默认值: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的启动模式

  1. singLeton启动模式
    每一个UIAbility只存在唯一实例。是默认启动模式任务列表中只会存在一个相同的UIAbility
  2. standard启动模式
    每次启动UIAbitity都会创建一个新的实例。在任务列表中可能存在一个或多个相同的UIAbility
  3. 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数据请求

  1. 导入http模块

    import http from '@ohos .net.http'
    
  2. 使用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

名称描述类型
methodRequestMethod请求方式,GET、POST、PUT、DELETE等
extraDataString|Object请求参数
headerObject请求头字段
connectTimeoutnumber连接超时时间,单位毫秒,默认是60000ms
readTimeoutnumber读取超时间,同上

HttpResponse

名称描述类型
responseCodeResponseCode响应状态码
headerObject响应头
cookiesstring响应返回的cookies
resultstring|object响应体,默认是JSON字符串
resultTypeHttpDataType返回值类型。

7.2、第三方库axios

在这里插入图片描述

  1. 下载和安装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}
      
  2. 下载和安装axios

    • 下载axios
      # 进入项目目录,然后输入下面命令
      ohpm install @ohos/axios
      
    • 开放网络权限
      # 在模块的module.json5文件中配置网路权限
      {
      "module":{
      	"requestPermissions": [
      			{
      			"name":"ohos.permission.INTERNET"
      			}
      		]
      	}
      }
      
  3. 使用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))
      	})
      }
      
名称类型描述
statusnumber响应状态码
headersObject响应头
dataany服务端返回的响应体

八、数据持久化

8.1、用户首选项

用户首选项(Preference)为应用提供Key-Value键值型的数据处理能力,支持应用持久化轻量级数据
在这里插入图片描述

  1. 导入首选项模块

    import dataPreference from '@ohos.data.preferences'
    
  2. 获取首选项实例,读取指定文件

    dataPreference.getPreferences(this.context,'MyAppPreferences')
    	.then(preferences => {
    		//获取成功
    	})
    	.catch(reason =>{
    		//获取失败
    	})
    
  3. 数据操作

    // 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组件提供的本地数据库,用于管理应用中的结构化数据。例如:记账本、备忘录。

在这里插入图片描述
在这里插入图片描述

  1. 初始化数据库

    • 导入关系型数据库模块
    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)
    })
    
  2. 增、删、改数据

    • 新增数据
    // 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)
    
  3. 查询数据

    • 查询数据
    // 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})
    }
    
IDNAMEFINISHED
1任务1false
2任务2false
3任务3true

九、通知

9.1、基础通知

应用可以通过通知接口发送通知消息,提醒用户关注应用中的变化。用户可以在通知栏查看和操作通知内容。

通知常见的使用场景:

  • 显示接收到的短消息、即时消息等。
  • 显示应用的推送消息,如广告、版本更新等。
  • 显示当前正在进行的事件,如下载等。
  1. 导入notification模块

    import notificationManager from '@ohos.notificationManager'
    
  2. 发布通知

    //2.1.构建通知请求
    let request: notificationManager.NotificationRequest = {
    id: 10,
    content:{ // 通知内容: }
    }
    //2.2.发布通知
    notificationManager.publish(request)
    	.then(() => console.log('发送通知成功'))
    	.catch(reason => console,log('发送通知失败'JSON.stringify(reason)))
    
  3. 取消通知

    //取消指定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()是查询模板是否支持接口,目前仅支持进度条模板。

  1. 导入模块。

    import NotificationManager from '@ohos.notificationManager';
    
  2. 查询系统是否支持进度条模板,查询结果为支持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}]`);
    });
    
  3. 构造进度条模板对象,并发布通知。

    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: {
	//..
	}
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1441918.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

备战蓝桥杯---搜索(完结篇)

再看一道不完全是搜索的题&#xff1a; 解法1&#xff1a;贪心并查集&#xff1a; 把冲突事件从大到小排&#xff0c;判断是否两个在同一集合&#xff0c;在的话就返回&#xff0c;不在的话就合并。 下面是AC代码&#xff1a; #include<bits/stdc.h> using namespace …

Bee+SpringBoot稳定的Sharding、Mongodb ORM功能(同步 Maven)

Hibernate/MyBatis plus Sharding JDBC Jpa Spring data GraphQL App ORM (Android, 鸿蒙) Bee 小巧玲珑&#xff01;仅 860K, 还不到 1M, 但却是功能强大&#xff01; V2.2 (2024春节・LTS 版) 1.Javabean 实体支持继承 (配置 bee.osql.openEntityCanExtendtrue) 2. 增强批…

放飞梦想,扬帆起航——1888粉丝福利总结

目录 1.祝福 2.准备 3.抽奖 4.制作 5.添加 6.成果 7.感谢 8.福利 9.祝福 1.祝福 马上就是除夕了&#xff0c;在这里提前预祝大家春节快乐&#xff0c;小芒果在这里给大家拜年了&#xff01; 2.准备 其实很早之前我就在幻想着哪一天我的粉丝量能突破1888&#xff0c;…

Redis -- 安装客户端redis-plus-plus

目录 访问reids客户端github链接 安装git 如何安装&#xff1f; 下载/编译、安装客户端 安装过程中可能遇到的问题 访问reids客户端github链接 GitHub - sewenew/redis-plus-plus: Redis client written in CRedis client written in C. Contribute to sewenew/redis-p…

【动态规划】【C++算法】2518. 好分区的数目

作者推荐 【动态规划】【前缀和】【C算法】LCP 57. 打地鼠 本文涉及知识点 动态规划汇总 LeetCode:2518. 好分区的数目 给你一个正整数数组 nums 和一个整数 k 。 分区 的定义是&#xff1a;将数组划分成两个有序的 组 &#xff0c;并满足每个元素 恰好 存在于 某一个 组中…

【QT学习十四】 文件目录操作

目录 一、概述 二、详解 1. QFile QFile 类中的一些静态方法&#xff1a; 使用示例&#xff1a; 注意事项&#xff1a; 2. QDir 成员函数 使用实例&#xff1a; 注意事项&#xff1a; 3. QFileInfo 成员函数 使用实例 4. QTemporaryFile 成员函数 使用实例 注…

医学考试搜题答案这7款足够解决问题 #笔记#知识分享#其他

搜题软件一般都是通过识别题目内容搜索出问题的答案&#xff0c;当识别内容不正确或搜索不到答案时&#xff0c;又得重新到其他软件进行重复的操作&#xff0c;很是麻烦。所以我们可以使用专业的识别工具&#xff0c;对题目内容进行识别&#xff0c;然后把提取出来的内容单独保…

企业内部知识库管理软件的终极指南:如何选择最适合你的工具?

知识库管理软件对于希望提高客户支持和组织效率的公司来说是一个强大的工具。在数字时代&#xff0c;拥有一个可靠的知识库系统对于快速准确地满足客户需求至关重要。在当今的技术条件下&#xff0c;知识库管理软件有很多选择&#xff0c;每个企业都应该仔细评估并选择最适合自…

Visio2007下载安装教程,保姆级教程,附安装包和工具

前言 Visio是负责绘制流程图和示意图的软件&#xff0c;便于IT和商务人员就复杂信息、系统和流程进行可视化处理、分析和交流&#xff0c;可以促进对系统和流程的了解&#xff0c;深入了解复杂信息并利用这些知识做出更好的业务决策。帮助您创建具有专业外观的图表&#xff0c…

图像处理SoC的方案调研(视频编码器和DLA)

最近在公众号和粉丝交流&#xff0c;提到了图像处理SoC&#xff0c;包括的部分有CPU ISP 视频编码器 DLA axi/ahb/apb总线及外设&#xff0c;我觉得很有意思&#xff0c;值得学习和了解&#xff0c;尤其是视频编码器和DLA这两个概念。 1 视频编码器 视频编码器是一种可以…

内网穿透工具

1. nps-npc 1.1 简介 nps是一款轻量级、高性能、功能强大的内网穿透代理服务器。目前支持tcp、udp流量转发&#xff0c;可支持任何tcp、udp上层协议&#xff08;访问内网网站、本地支付接口调试、ssh访问、远程桌面&#xff0c;内网dns解析等等……&#xff09;&#xff0c…

Makefile编译原理 make的隐性规则

一.makefile 中的同名目标 下面程序怎么执行&#xff1f;为什么&#xff1f; 实验1 &#xff1a;makefile 中出现同名目标时 .PHONY : all all : echo "command-1"all : echo "command-2"VAR : testall :echo "all : $(VAR)"mhrubuntu:~/work/…

春节:当代发展及创新传承

为了解中国传统节日——春节&#xff0c;2024年2月9日&#xff0c;曲阜师范大学计算机学院“古韵新声&#xff0c;格物致‘知’”实践队队员贾宣在山东省青岛市西海岸新区的商场中进行了街头调查&#xff0c;探究春节的发展与当代意义。 春节历史悠久&#xff0c;起源于早期人…

vue-内置组件-Suspense

Suspense (实验性功能) <Suspense> 是一项实验性功能。它不一定会最终成为稳定功能&#xff0c;并且在稳定之前相关 API 也可能会发生变化。 <Suspense> 是一个内置组件&#xff0c;用来在组件树中协调对异步依赖的处理。它让我们可以在组件树上层等待下层的多个嵌…

k8s 部署java应用 基于ingress+jar包

k8 集群ingress的访问模式 先部署一个namespace 命名空间 vim namespace.yaml kind: Namespace apiVersion: v1 metadata:name: ingress-testlabels:env: ingress-test 在部署deployment deployment是pod层一层封装。可以实现多节点部署 资源分配 回滚部署等方式。 部署的…

以管理员权限删除某文件夹

到开始菜单中找到—命令提示符—右击以管理员运行 使用&#xff1a;del /f /s /q “文件夹位置” 例&#xff1a;del /f /s /q "C:\Program Files (x86)\my_code\.git"

【Java八股面试系列】JVM-内存区域

目录 Java内存区域 运行时数据区域 线程独享区域 程序计数器 Java 虚拟机栈 StackFlowError&OOM 本地方法栈 线程共享区域 堆 GCR-分代回收算法 字符串常量池 方法区 运行时常量池 HotSpot 虚拟机对象探秘 对象的创建 对象的内存布局 句柄 Java内存区域 运…

P3647 题解

文章目录 P3647 题解OverviewDescriptionSolutionLemmaProof Main Code P3647 题解 Overview 很好的题&#xff0c;但是难度较大。 模拟小数据&#xff01;——【数据删除】 Description 给定一颗树&#xff0c;有边权&#xff0c;已知这棵树是由这两个操作得到的&#xff1…

Hexo更换Matery主题

引言 在数字化时代&#xff0c;拥有一个个人博客已经成为许多人展示自己技能、分享知识和与世界互动的重要方式。而在众多博客平台中&#xff0c;Hexo因其简洁、高效和易于定制的特点而备受青睐。本文将详细介绍如何为你的Hexo博客更换主题&#xff0c;让你的个人博客在互联网…

LabVIEW工业监控系统

LabVIEW工业监控系统 介绍了一个基于LabVIEW软件开发的工业监控系统。系统通过虚拟测控技术和先进的数据处理能力&#xff0c;实现对工业过程的高效监控&#xff0c;提升系统的自动化和智能化水平&#xff0c;从而满足现代工业对高效率、高稳定性和低成本的需求。 随着工业自…