ArkUI 开发实例:快五一了,做一个回家的订票动画界面(上)

2,319 阅读7分钟

背景

转眼2024年已经快到五一假期了,最近有空一直在看一些鸿蒙原生开发的文档,ArkUI声明式开发可以快速构建复杂高效的界面和动画效果。

想着快订票了,不如我们就来做一个纯血鸿蒙NEXT开发订票页面吧。

订票动画.gif

掌握技能

本实例虽然只有一个小实例,但是你可以学到一些常用的ArkUI组件的知识,希望通过笔者的实例教程,带你更深刻的理解这些组件的功能,也带你进入原生鸿蒙开发的奇妙世界。

  • Column、Row和Stack布局:通过最常用的三种布局方式,快速学习理解AruUI页面构造;
  • DatePicker:日期选择器,实现快速选择指定范围日期的功能;
  • animation:属性动画,通过组件的某些通用属性变化,实现渐变过渡的动画效果;
  • transition:组件内转场动画,通过配置转场参数,在组件插入和删除时显示渐变过渡的动画效果。
  • Button:按钮组件,响应用户的点击等操作。

需求分析

本实例并非用户真实还原购票场景,只是通过简化版的产品流程设计,模拟用户购票流程,简易梳理产品架构图,如下图所示: image.png

UI设计

通过卡片化的设计,把现实中车票效果与交互界面进行融合,设计订票组件。

image.png

通过“输入信息”与“查询结果”两个页面,实现用户订票流程。

image.png

本实例并未展示用户层输入“地址”和“交通工具”选择功能,主要目的是带领大家了解ArkUI布局和动画功能,故进行功能精简,按照UI导出切图如下。

image.png

开始实例

下面我们打开Deveco Studio开始本实例的教程,首先新建项目,选择OpenHarmony的Empty Ability创建实例。

image.png

本次实例是基于OpenHarmonySDK的api11(当前官方HarmonyOS仅开放到api9,故采用OpenHarmony演示), 软件名称就命名为“Ticketing”,选择Model为Stage(当前主推Model)

image.png

布局分析

层叠布局 (Stack)

页面最底层容器是一个层叠布局 (Stack),由一张背景图和二级内容视图构成。

那么我们了解下第一个知识点Stack

层叠布局(Stack)通过区域内元素一层层堆叠实现布局。

子元素在容器中依次入栈,后元素覆盖前元素。

其方便设置相对位置信息,可以很便捷制作卡片效果。

image.png

如上图,Stack容器内元素红色矩形位于最上方堆叠在蓝色矩形和绿色矩形之上。

image.png

基于UI设计,背景图是固定图片,其宽高也是固定的,我们的Stack容器内是顶部对齐,此时可以通过Stack组件alignContent参数实现位置的相对对齐。

名称描述
TopStart顶部起始端。
Top顶部横向居中。
TopEnd顶部尾端。
Start起始端纵向居中。
Center横向和纵向居中。
End尾端纵向居中。
BottomStart底部起始端。
Bottom底部横向居中。
BottomEnd底部尾端。

根据上方表格内容可看出,我们需要为Stack增加顶部横向居中对齐的方式,故alignContent: Alignment.Top是符合的。

此时代码如下:

@Entry
@Component
export struct TicketingView {
  build() {
    Stack({ alignContent: Alignment.Top }) {
      Image("/pages/ComponentClassification/ExampleComponents/OneReserve/bg.png")
        .height(350)
      Column() {
      }
      .padding(5)
      .alignItems(HorizontalAlign.Center)
      .height(350)
    }
      .width("100%")
      .height('100%')
  }
}

垂直线性布局 (Column)

二级容器为三个子元素组成的垂直线性布局 (Column)

那么我们了解下第二个知识点Column

垂直线性布局(Column)沿垂直方向布局的容器。

子元素在容器中依次排列。

其方便设置垂直排列信息。

image.png

如上图,Column容器内元素蓝色矩形位于最下方,粉色矩形位于最上方。

image.png

基于UI设计,由于我们根据UI里面的绝对高度,需要给给不同子容器定义固定的height,我们的Column容器内是居中对齐,此时可以通过Column组件alignContent参数的HorizontalAlign属性实现子组件在水平方向上的对齐格式。

名称描述
Start起始端对齐。
Center居中对齐,默认对齐方式。
End末端对齐。

此时默认值也是HorizontalAlign.Center,故.alignItems(HorizontalAlign.Center)可以省略。上文Column部分可以替换为下面代码

Column() {
  Row() {
    }
    .height(92)
  DatePicker({
    start: new Date('2024-1-1'),
    end: new Date('2025-1-1'),
  })
    .padding(3)
    .height(165)
    .width(230)
  Button({ type: ButtonType.Normal }) {
    Text( "开始查询")
      .fontSize(18)
      .fontColor(Color.White)
      .margin({ left: 80, right: 80, top: 5, bottom: 5 })
  }
  .margin(20)
  .height(35)
  .backgroundColor("#FC6A68")
  .borderRadius(8)
}
.padding(5)
.height(350)

image.png

至此,我们的布局已经基本完成(DatePick为日期选择器,Button为按钮,我们将在下文详细讲解,暂时只需要知道其实Column内子元素即可),但是很明显Column内的第一个元素Row还是空的,那么接下来我们开始完善该子元素。

水平线性布局 (Row)

垂直线性布局 (Column)内有三个子元素,其中第一个是Row布局的容器,为了实现展示出发地和目的地的功能。

那么我们了解下第三个知识点Row

水平线性布局(Column)沿水平方向布局的容器。

子元素在容器中依次排列。

其方便设置横向排列信息。

image.png

如上图,Row容器内元素均为水平排列。

image.png

基于UI设计,我们的Row容器内也是五个子元素构成,其中包含三个Column容器和两个高度很低的矩形。我们的Row容器内是居中对齐,此时可以通过Row组件alignContent参数的VerticalAlign属性实现子组件在垂直方向上的对齐格式。

名称描述
Top顶部对齐。
Center居中对齐,默认对齐方式。
Bottom底部对齐。

和Column类似,此时Row容器默认值也是VerticalAlign.Center,故.alignItems(VerticalAlign.Center)可以省略。上文Row部分可以替换为下面代码,其包含五部分组成。

Row() {
  //1
  Column({ space: 5 }) {
    Text("信阳")
      .fontSize(20)
      .fontWeight(FontWeight.Medium)
      .fontColor("#132968")
    Text("XinYang")
      .fontSize(13)
      .fontColor("#132968")
  }
    .width(70)
  //2
  Rect()
    .height(1)
    .width(40)
    .margin(7)
  //3
  Column({ space: 5 }) {

  }
  .width(40)
  //4
  Rect()
    .height(1)
    .width(40)
    .margin(7)
  //5
  Column({ space: 5 }) {
    Text("深圳")
      .fontSize(20)
      .fontWeight(FontWeight.Medium)
      .fontColor("#132968")
    Text("ShenZhen")
      .fontSize(13)
      .fontColor("#132968")
  }
   .width(70)

出发地和目的地是都是Column容器的中文和拼音上下组成,上文我们已经学习了Column的使用方式,此时我们可以通过space实现Column和Row内间距的效果。

  Column({ space: 5 }) {
    Text("信阳")
      .fontSize(20)
      .fontWeight(FontWeight.Medium)
      .fontColor("#132968")
    Text("XinYang")
      .fontSize(13)
      .fontColor("#132968")
  }
    .width(70)

如上代码,出发地和目的地容器只是内部文本不同。

Rect()
    .height(1)
    .width(40)
    .margin(7)

横线部分我们通过高度为1的矩形实现。

image.png

那么接下来是切换目的地的按钮和火车图标,其位于Row容器正中间,既第三个容器。

image.png

分析可知,其也是Column布局,分为上面火车图标和下方切换按钮。

image.png

由于我们要实现切换时火车外圆环图标的转动动画,故火车图标部分需要两张图通过Stack堆叠。

//3
Column({ space: 5 }) {
  Stack() {
    Image("/pages/ComponentClassification/ExampleComponents/OneReserve/train.png")
      .width(20)
    Image("/pages/ComponentClassification/ExampleComponents/OneReserve/reverse.png")
      .width(40)
  }
  Button() {
      Image("/pages/ComponentClassification/ExampleComponents/OneReserve/buttonArrow.png")
        .width(40)
  }
  .backgroundColor("#DEEBF9")
}
.width(40)

我们将上面Row内第三个容器修改成如上代码,因为我们已经了解了Stack和Column的用法,故这种嵌套容器的使用和理解,我相信已经没有什么难度了。

此时基本布局效果已经完成~

image.png

那么下一章,我们开始实现基本的逻辑,比如点击切换图标可以实现出发地与目的地的修改,日期选择后可以查询选择日期的火车票信息,以及通过按钮点击事件实现用户查询与购票操作。

敬请期待。