快速入门HarmonyOS应用开发(一)

目录

前言

一、准备工作

二、实战开发

2.1、Navigation简介

2.2、页面路由开发

2.2.1、创建常量

2.2.2、创建字符串资源

2.2.3、创建float资源

2.2.4、创建color资源

2.2.5、创建数据实体

2.2.6、创建页面路由表

2.2.7、创建Navigation根容器

2.2.8、创建NavDestination子页面

2.2.9、页面路由跳转及传参

2.2.10、处理页面返回键

2.2.11、调试运行

前言

写这个系列的目标是准备通过几篇文章的介绍,和大家一起快速入门HarmonyOS应用的开发。初步打算是主要通过代码实战的形式去介绍,基本的语法和使用还是建议大家先阅读官网的文档说明。OK,话不多说,咱们开始。

一、准备工作

首先,最全面的学习资料肯定是官网文档,所以需要快速掌握文档的对应位置,这里把开发中经常用到文档入口都罗列在下面了,按需自取:

开发指南 API文档 最佳实践 FAQ 示例代码

其次,注意搜索时左侧菜单可以选择类别,比如这里可以勾选全部:

OK,接着咱们下载开发工具:下载与安装DevEco Studio,这个没什么好说的,下载完了之后一步一步安装即可。

接着学习开发语言可以参考如下内容,鸿蒙中使用的ArkTS是基于TypeScript做了扩展:

学习ArkTS语言和应用框架中的ArkTs(方舟编程语言)

准备工作就做到这里,接下来就可以上手开发了,今天咱们首先来学习路由如何使用。

二、实战开发

2.1、Navigation简介

Navigation主要用于实现Navigation页面(NavDestination)间的跳转,支持在不同Navigation页面间传递参数,提供灵活的入栈出栈操作,方便快捷的实现对不同页面的访问和复用。关于Navigation更多的介绍及详细使用大家可以参考:

组件导航(Navigation) (推荐)

2.2、页面路由开发

首先我们先创建一个空工程,这里可以根据公司规范或者个人习惯修改相关文件名。在src/main/ets/pages目录下新建navigation文件夹,将Index.ets移动到该文件夹下,并修改文件名为NavigationPage.ets,并且修改代码中Index名称为NavigationPage,同时还需要修改EntryAbility文件中默认加载的页面路径:

上面的NavigationPage作为整个工程页面路由栈的根页面,你可以把它理解为一个相册,我们使用@Entry来修饰它,并且使用Navigation作为它的组件树的根节点。然后我们需要实现的APP的各个展示页面就是相册里面的一张一张的照片,我们使用@Component来修饰它,并且使用NavDestination作为它们的组件树的根节点。简单理解就是:Navigation是容器,NavDestination是页面。在今天的例子中,我们会创建两个页面MainPage和OtherPage。

今天由于是本系列的第一篇,所以一些基础工作我也会介绍一下,后续的文章中将不再赘述。

2.2.1、创建常量

在工程的src/main/ets 目录下新建文件夹constants,用来存放项目中需要用到的常量字段,这里我们创建两个文件:CommonConstant存放公共常量,PageConstant存放页面名称,代码如下:

TypeScript 复制代码
export class CommonConstant {
  static readonly FULL_PERCENT: string = '100%'
  static readonly PAGEINFO_KEY: string = 'PageInfo'
  static readonly EXIT_INFO: string = '再按一次退出应用'
  static readonly PRE_TIME: number = 0
  static readonly EXIT_TIME: number = 2000
}
TypeScript 复制代码
export class PageConstant{
  static readonly PAGE_MAIN: string = 'MainPage'
  static readonly PAGE_OTHER: string = 'OtherPage'
}

2.2.2、创建字符串资源

在resources/base/elment/string.json文件中添加项目中需要用到的字符串资源:

bash 复制代码
{
  "string": [
    {
      "name": "tip_main_page",
      "value": "我是主页点我跳转"
    },
    {
      "name": "tip_other_page",
      "value": "我是其它页面"
    }
  ]
}

2.2.3、创建float资源

在resources/base/elment/float.json文件中添加项目中需要用到的字体大小fp和组件大小vp资源:

bash 复制代码
{
  "float": [
    {
      "name": "fp_20",
      "value": "20fp"
    },
    {
      "name": "vp_100",
      "value": "100vp"
    }
  ]
}

2.2.4、创建color资源

在resources/base/elment/color.json文件中添加项目中需要用到的颜色资源:

bash 复制代码
{
  "color": [
    {
      "name": "color_primiry",
      "value": "#57BE6A"
    }
  ]
}

2.2.5、创建数据实体

在src/main/ets下新建model文件夹,在该文件夹下新建DemoData.ets文件,在这个文件里我们创建页面间传值所需的数据类,这里介绍了两种方式interface和class,都可以定义所需的实体:

TypeScript 复制代码
// MainPage传递参数的数据类
export interface ParamData {
  name: string
}

// OtherPage回传的数据类
export class BackData {
  result?: string

  constructor(result: string) {
    this.result = result
  }
}

2.2.6、创建页面路由表

在src/main/ets/pages/navigaion目录下新建PagesMapBuilder.ets文件,作为项目的页面路由表:

TypeScript 复制代码
import { PageConstant } from "../../constants/PageConstant";
import { MainPage } from "../MainPage";
import { OtherPage } from "../OtherPage";

@Builder
export function PagesMapBuilder(name: string) {
  if (name===PageConstant.PAGE_MAIN) {
    MainPage()
  }else if (name===PageConstant.PAGE_OTHER){
    OtherPage()
  }
}

2.2.7、创建Navigation根容器

在NavigationPage页面中,我们实例化了一个NavPathStack对象:

TypeScript 复制代码
// 页面路由栈
@Provide(CommonConstant.PAGEINFO_KEY) pageStack: NavPathStack = new NavPathStack()

从名字也能看出它是用来管理页面路由的路由栈对象,这里我们使用了@Provide这个装饰器来修饰,它一般是与@Consume成对使用,用于与后代组件的双向数据同步、状态数据在多个层级之间传递的场景。使用详情可以参考:@Provide装饰器和@Consume装饰器:与后代组件双向同步

然后在build()函数中,我们创建Navigation组件并且绑定导航控制器和页面路由表:

TypeScript 复制代码
import { CommonConstant } from '../../constants/CommonConstant'
import { PagesMapBuilder } from './PagesMapBuilder'

@Entry
@Component
struct NavigationPage {
  // 页面路由栈
  @Provide(CommonConstant.PAGEINFO_KEY) pageStack: NavPathStack = new NavPathStack()

  build() {
    Navigation(this.pageStack)
      .hideTitleBar(true)
      .hideToolBar(true)
      .hideNavBar(true)
      .mode(NavigationMode.Stack)
      .navDestination(PagesMapBuilder)
  }
}

这里的build()函数是用于定义自定义组件的声明式UI描述,自定义组件必须定义build()函数。从这里也就看出了HarmonyOS应用的UI是使用的声明式UI,这里提到了它是用于自定义组件的UI描述,因此咱们这里的NavigationPage也是自定义组件,你可以理解在HarmonyOS应用中:一切皆组件!

关于自定义组件的使用可以参考:创建自定义组件

可以看到,我们代码中的@Component struct正是符合这个结构的,至于最上面的@Entry,那是因为它装饰的自定义组件是UI页面的入口。

2.2.8、创建NavDestination子页面

在src/main/ets/pages文件夹下新建MainPage.ets文件,在这个文件中首先定义路由栈对象,承接上文中的@Provide,这里我们可以直接使用@Consume来定义:

TypeScript 复制代码
@Consume(CommonConstant.PAGEINFO_KEY) pageStack: NavPathStack

然后在build()函数中创建NavDestination为根节点的组件树,这里面我们仅添加一个Text文本用于展示:

TypeScript 复制代码
import { CommonConstant } from "../constants/CommonConstant"

@Component
export struct MainPage {
  @Consume(CommonConstant.PAGEINFO_KEY) pageStack: NavPathStack
  @State content: string | Resource = $r('app.string.tip_main_page')

  build() {
    NavDestination() {
      Column() {
        Text(this.content)
          .fontSize($r('app.float.fp_20'))
          .fontColor(Color.Blue)
          .fontWeight(FontWeight.Bold)
      }
      .width(CommonConstant.FULL_PERCENT)
      .height(CommonConstant.FULL_PERCENT)
      .justifyContent(FlexAlign.Center)
    }.hideTitleBar(true)
  }
}

这里的@State同样是一个状态管理的装饰器,用它修饰的变量在组件内数据变更时可以引起UI的自动刷新,具体使用可以参考:@State装饰器:组件内状态

然后以同样的方式创建另一个页面OtherPage.ets:

TypeScript 复制代码
import { CommonConstant } from "../constants/CommonConstant"

@Component
export struct OtherPage {
  @Consume(CommonConstant.PAGEINFO_KEY) pageStack: NavPathStack
  @State content: string | Resource = $r('app.string.tip_other_page')

  build() {
    NavDestination() {
      Column() {
        Text(this.content)
          .fontSize($r('app.float.fp_20'))
          .fontColor(Color.Blue)
          .fontWeight(FontWeight.Bold)
          .onClick(() => {
            let backData = new BackData('我是Other数据')
            this.pageStack.pop(backData)
          })
      }
      .width(CommonConstant.FULL_PERCENT)
      .height(CommonConstant.FULL_PERCENT)
      .justifyContent(FlexAlign.Center)
    }.hideTitleBar(true)
  }
}

2.2.9、页面路由跳转及传参

首先在NavigationPage的aboutToAppear()回调中添加第一个加载的页面视图:

TypeScript 复制代码
aboutToAppear(): void {
  this.pageStack.pushPath({ name: PageConstant.PAGE_MAIN }, false)
}

aboutToAppear()是自定义组件的一个生命周期函数,在组件即将出现时回调该接口,具体时机为在创建自定义组件的新实例后,在执行其build函数之前执行,详情可以参考:

自定义组件生命周期

然后在MainPage中创建需要传递的参数:

TypeScript 复制代码
paramData: ParamData = { name: '我是MainPage数据' }

在MainPage中的Text文本的点击事件里,跳转到OtherPage页面,并将上面的数据作为参数传递过去,同时在onPop回调中可以接收OtherPage页面回传的参数,如果不需要回传参数onPop回调可以不用写:

TypeScript 复制代码
.onClick(() => {
            // 页面跳转,传递参数到Other页面,并通过onPop回调接收Other页面回传的数据
            this.pageStack.pushPath({
              name: PageConstant.PAGE_OTHER, param: this.paramData, onPop: (popInfo: PopInfo) => {
                let backData = popInfo.result as BackData
                this.content = backData.result
              }
            })
          })

接着在OtherPage页面中接收来自MainPage传递的参数,这里接收参数我们介绍两种方式:

第一种:使用NavDestination的onReady()函数进行接收:

TypeScript 复制代码
.onReady((context: NavDestinationContext) => {
      this.paramData = context.pathInfo.param as ParamData
      if (this.paramData) {
        this.content = this.paramData.name
      }
    })

第二种:在aboutToAppear()生命周期函数中通过pageStack的getParamByIndex()函数接收:

TypeScript 复制代码
aboutToAppear(): void {
    this.paramData = this.pageStack.getParamByIndex(this.pageStack.size() - 1) as ParamData
    if (this.paramData) {
      this.content = this.paramData.name
    }
  }

然后在OtherPage的Text文本的点击事件中我们将需要回传的参数通过pageStack的pop(xxx)方法进行回传:

TypeScript 复制代码
.onClick(() => {
            let backData = new BackData('我是Other数据')
            this.pageStack.pop(backData)
          })

2.2.10、处理页面返回键

在Android中我们经常可以看到在点击Back键时会提示:再按一次退出应用,虽然现在很多手机隐藏了返回键,但是我们通过侧滑仍然可以出发页面返回,那如果想要实现上面的效果该怎么做呢?

其实原理是类似的,在HarmonyOS中,我们可以监听页面的onBackPress()事件,在这个函数中处理连续点按退出应用的逻辑:

TypeScript 复制代码
import { CommonConstant } from '../../constants/CommonConstant'
import { common } from '@kit.AbilityKit'

@Entry
@Component
struct NavigationPage {

  private context = this.getUIContext().getHostContext() as common.UIAbilityContext
  private preTime: number = CommonConstant.PRE_TIME
  promptAction = this.getUIContext().getPromptAction()

  // 2秒内连续点按/侧滑后关闭当前应用
  onBackPress(): boolean | void {
    let currentTime = new Date().getTime()
    let flag = currentTime - this.preTime
    if (flag > CommonConstant.EXIT_TIME) {
      this.preTime = currentTime
      this.promptAction.showToast({ message: CommonConstant.EXIT_INFO })
      return true
    } else {
      this.context.terminateSelf()
    }
    return false
  }
}

2.2.11、调试运行

最后使用模拟器或者真机运行程序,运行程序需要先签名,关于签名大家可以参考:

配置调试签名

平常开发使用自动签名即可,方便快捷。最后,来看一下实现的效果吧:

实现效果录屏

完整代码:HarmonyDemos

OK,今天的内容到这里就要和大家说再见了,咱们下期再会!

祝:工作顺利,前程似锦!

相关推荐
爱笑的眼睛115 小时前
HarmonyOS Web组件深度解析:构建高性能JavaScript交互的实践与创新
华为·harmonyos
特立独行的猫a6 小时前
HarmonyOS黑马云音乐项目:全场景在线音乐播放的实现与优化
华为·harmonyos·黑马云音乐
Industio_触觉智能7 小时前
开源鸿蒙SIG-Qt技术沙龙成都站成功举办,产品方案展示
qt·harmonyos·openharmony·开源鸿蒙·sig-qt
Android疑难杂症8 小时前
一文讲清鸿蒙网络开发
前端·javascript·harmonyos
翻斗花园胡英俊9 小时前
新手也能上手:从零写一个鸿蒙(HarmonyOS)应用的最短路径
harmonyos
不爱吃糖的程序媛11 小时前
Electron 如何判断运行平台是鸿蒙系统(OpenHarmony)
javascript·electron·harmonyos
大师兄66681 天前
鸿蒙 ArkTS 入门教程:小白实战 List 列表开发(详解 @State, ForEach, @Builder)
list·harmonyos·arkts·builder·foreach·state·鸿蒙入门
2501_919749031 天前
配置flutter鸿蒙的环境和创建并运行第一个flutter鸿蒙项目【精心制作】
flutter·华为·harmonyos
爱笑的眼睛112 天前
深入解析ArkTS类型系统:构建安全高效的HarmonyOS应用
华为·harmonyos