基于eTS高效开发HarmonyOS课程类应用

HarmonyOS开发者社区 2022-07-15 11:27:12

 原文:基于eTS高效开发HarmonyOS课程类应用,点击链接查看更多技术内容。

 

目录

一、整体介绍

1. 声明式UI描述

2. 循环渲染数据

3. 状态数据管理

二、搭建界面布局

1. 导航栏布局

2. 课程内容布局

三、构建数据模型

1. 定义数据模型

2. 预置数据

3. 加载数据更新UI

四、实现界面联动

1. 导航栏高亮显示

2. 右边滑动,左边变化

3. 左边点击,右边跳转


 

随着HarmonyOS 3.0 Beta版的发布,API Version 8新增了大批JS/eTS API接口,相信很多开发者已经迫不及待想体验基于eTS的HamronyOS应用开发。本期Codelab,我们将基于API Version 8实现一个HarmonyOS课程类应用,帮助大家学习eTS的声明式UI描述、循环渲染、状态数据管理等机制,体验基于eTS的极简高效开发。

 

一、整体介绍

在课程类应用界面中,左侧为课程分类导航栏,右侧为各个类别的课程内容。当用户上下滑动右侧课程内容时,左侧导航栏会跳转至对应的课程分类。当用户点击左侧导航栏的课程分类时,会高亮显示点击的内容,且右侧课程内容会跳转至对应类别的课程列表。

那么如何基于eTS高效实现这样一个HarmonyOS课程类应用?下面我们将从声明式UI描述、循环渲染数据、状态数据管理三个维度来解析。

 

1. 声明式UI描述

界面布局是UI界面的骨架,决定了应用界面的交互和视觉风格。本示例中我们将通过eTS的一系列基础组件以声明式方式进行组合和扩展,并采用接近自然语义的编程语法直观地描述UI界面,包括参数构造配置、属性配置、事件配置以及子组件配置等。

相较于基于Java的命令式开发,eTS采用更接近自然语义的声明式编程语法,让开发者可以更直观地描述UI界面,有效地降低了开发者的上手成本,极大程度地提升了UI界面的构建效率,实现极简高效开发。

 

2. 循环渲染数据

数据模型是UI界面的肉体,描述了界面中数据的静态特征、动态行为和约束条件。本示例中我们将通过eTS直观地定义界面中各个模块的数据模型,包含名称、标识、图片链接等,并根据数据模型写入对应的数据。最后使用eTS提供的循环渲染机制(ForEach)将写入的数据循环渲染至对应的界面中。

相较于基于Java的命令式开发,eTS在渲染数据时UI的更新不需要开发者使用代码主动刷新,而是交给框架层自动处理,开发者不必关心框架如何实现UI绘制和渲染,实现界面数据的高效渲染。

 

3. 状态数据管理

联动效果是UI界面的灵魂,实现了界面中布局与数据的动态交互,本示例中我们将使用eTS提供的状态数据管理机制通过装饰组件拥有的状态属性,当装饰的变量更改时,组件会重新渲染更新UI界面数据,从而实现联动效果。

相较于基于Java的命令式开发,eTS通过功能不同的装饰器给开发者提供了清晰的页面更新渲染流程和管道。开发者要做的就是定义数据与UI的映射关系,后面只需要通过状态装饰器监听数据的状态,UI即可自动刷新,这极大地减轻了程序员对UI的维护工作。

以上就是实现课程类应用的核心原理,下面我们将为大家带来各部分的具体实现。

 

二、搭建界面布局

eTS提供了多种布局方式,不仅保留了经典的弹性布局能力,也提供了列表、宫格、栅格布局和适应多分辨率场景开发的原子布局能力。如图1所示,本示例中整体布局使用Row沿水平方向布局容器,并设置背景颜色为白色,Row内部嵌套Scroll及List容器分别作为应用界面的导航栏布局和课程内容布局,下面我们将为你一一道来。

图1 整体布局

 

1. 导航栏布局

应用界面的导航栏使用可滚动的容器组件Scroll来实现,Scroll内嵌Text组件用于显示“课程分类”名称,如图2所示:

图2 导航栏布局

Scroll容器必须内置一个子组件,我们使用了垂直方向的布局容器Column,并设置填充高度为height('100%')。“课程分类”名称使用Text组件实现,并设置文字颜色为fontColor(0x696969)、文字大小为fontSize(16)、文字对齐方式为textAlign(TextAlign.Center)居中显示、高度为height(60)、宽度为width('100%')。

相关代码如下:

Scroll() {
  Column() {
    ForEach(this.tabArray.map((item1, index1) => {
      return { index: index1, data: item1 };
    }), item => {
      Text(item.data.superName)
        .fontColor(0x696969)
        .backgroundColor(this.index == item.index ? 0xffffff : null)
        .fontSize(16)
        .width('100%')
        .height(60)
        .textAlign(TextAlign.Center)
        .onClick(() => {
          if (this.index != item.index) {
            this.index = item.index
            this.scroller.scrollToIndex(item.data.position)
          }
        })
    }, item => '' + item.data)
  }.height('100%')
}.width(100).height('100%').backgroundColor(0xdddddd).scrollBar(BarState.Off)

 

2. 课程内容布局

应用的课程内容部分的布局使用List列表容器来实现,并使用ForEach循环渲染listArray(课程内容)数据,如图3所示,课程内容布局包含头部和课程信息两部分(头部和左边的导航栏对应),下面我们将分别介绍头部及课程信息的布局的实现。

图3 课程内容布局

(1) 头部布局

头部使用Text组件实现,并设置了文字颜色为fontColor(0x696969)、文字大小为fontSize(20)、高度为height(40)、宽度为width('100%')填充、内边距为padding({ left: 10 })、背景颜色为backgroundColor(0xefefef)。同时,头部的ListItem设置了sticky(Sticky.Normal)属性,使其滑动到顶部时可以呈现固定的效果。代码如下:

if (item.tag) {
  ListItem() {
    Text(item.courseName)
      .fontColor(0x696969)
      .fontSize(20)
      .height(40)
      .width('100%')
      .padding({ left: 10 })
      .backgroundColor(0xefefef)
  }.sticky(Sticky.Normal)

(2) 课程信息布局

课程信息部分使用Stack堆叠容器,高度设置为height(120),设置子组件在容器内的对齐方式为Alignment.TopStart。Stack组件内嵌Image、Text、Divider组件,用于呈现课程图片、课程标题、课程价格及分割线等信息。具体如下:

●课程的图片使用Image组件呈现,设置宽度为width(130),高度为height(100),图片的缩放类型为objectFit(ImageFit.Fill),使图片填充满组件,并设置左边、顶部边距均10,使其组件居中对齐。代码如下:

Image(item.imageUrl)
  .objectFit(ImageFit.Cover)
  .width(130)
  .height(100)
  .margin({ left: 10, top: 10 })

●课程名称使用Text组件,设置文字颜色为fontColor(0x363636)、文字大小为fontSize(14),最大显示行数为maxLines(2)两行,文本超长时的显示方式为TextOverflow.Clip,意为进行裁剪显示。代码如下:

Text(item.courseName)
  .fontColor(0x363636)
  .fontSize(14)
  .margin({ left: 150, top: 12 })
  .maxLines(2)
  .textOverflow({ overflow: TextOverflow.Clip })

●课程的价格使用Text组件,设置文字颜色为fontColor(0xff6600)、文字大小为fontSize(24),并使用了绝对定位position({ x: 0, y: '100%' })先让组件显示在Stack容器最底部的外边界下,然后使用锚点定位markAnchor({ x: 0, y: '100%' })使组件以自身高度向上偏移,让组件显示在Stack容器最底部。代码如下:

Text(item.price == 0 ? '免费' : '¥' + item.price)
  .fontColor(0xff6600)
  .fontSize(24)
  .position({ x: 0, y: '100%' })
  .markAnchor({ x: 0, y: '100%' })
  .margin({ bottom: 18, left: 150 })

●分割线使用Divider组件实现,并设置了分割线颜色为color(0xefefef)、分割线宽度为strokeWidth(0.7)、左右边距margin({ left: 10, right: 10 })均为10,并使用绝对定位position({ x: 0, y: '100%' })和锚点定位markAnchor({ x: 0, y: '100%' })使分割线呈现在Stack容器最底部。代码如下:

Divider()
  .margin({ left: 10, right: 10 })
  .color(0xefefef)
  .strokeWidth(0.7)
  .position({ x: 0, y: '100%' })
  .markAnchor({ x: 0, y: '100%' })

至此,我们已经实现了界面布局,此时界面只是一个没有任何内容的骨架。接下来我们将为应用界面添加数据模型。

 

三、构建数据模型

本章节我们将为大家介绍本示例中数据模型的定义、数据的预置以及数据的加载。

 

1. 定义数据模型

本示例需定义两个数据模型,分别是应用界面中左侧导航栏的“课程分类”和右侧的“课程内容”。其中:

● 导航栏“课程分类”定义了名称(superName)和位置(position)属性。数据模型定义如下:

export class TabItem {
  position: number; // 点击该分类时课程内容滑动到的位置
  superName: string; // 课程分类标题




  constructor(position: number, superName: string) {
    this.position = position;
    this.superName = superName;
  }
}

● “课程内容”定义了课程的名称(courseName)、课程的图片地址(imageUrl)、课程的价格(price)、判断是否为此类别课程头部的变量(tag)、课程所对应课程类别的索引位置(index),数据模型定义如下:

export class CourseItem {
  tag: boolean; // 是否此类别课程的头部
  index: number; // 课程所对应课程类别的索引位置
  courseName: string; // 课程名称
  imageUrl: string; // 图片地址
  price: number; // 价格
  constructor(tag: boolean, index: number, courseName: string, imageUrl: string, price: number) {
    this.tag = tag;
    this.index = index;
    this.courseName = courseName;
    this.imageUrl = imageUrl;
    this.price = price;
  }
}

2. 预置数据

在entry/src/main/ets/MainAbility/Model.ets文件中,放入准备好的模拟数据,其中,superId是课程分类的唯一标识、id是课程内容的唯一标识。格式如下:

const LinkData: any[] = [
  { 
    "superId": 1, 
    "superName": "热门课程", 
    "id": 1, 
    "courseName": "应用市场介绍", 
    "imageUrl": "/image/image1.jpg", 
    "price": 0 
  }, 
{
    "superId": 1,
    "superName": "热门课程",
    "id": 2,
    "courseName": "上架流程",
    "imageUrl": "/image/image2.jpg",
    "price": 100
  },
  ... 
]

3. 加载数据更新UI

本章节将介绍如何加载本地构造的模拟数据并呈现到界面。

(1) 加载数据

在index.ets文件中,通过getLinkData()获取预置数据。

aboutToAppear() {
  // 延时数据加载
  setTimeout(() => {
    let linkDataItem = getLinkData();
    this.tabArray = linkDataItem.tabArray;
    this.listArray = linkDataItem.listArray;
    this.requestSuccess = true;
  }, 2000)
}

(2) 渲染

● 导航栏使用ForEach循环渲染tabArray(课程分类)数据。这里的ForEach的第一个参数需要使用数组的map()方法遍历。代码如下:

let superId: number = 0
model.forEach((item) => {
  if (superId != item.superId) {
    let tabItem = new TabItem(this.listArray.length, item.superName);
    this.tabArray.push(tabItem)




    let courseItem = new CourseItem(true, this.tabArray.length - 1, item.superName, '', 0);
    this.listArray.push(courseItem)
  }
})

● 课程内容使用ForEach循环渲染listArray(课程内容)数据。代码如下:

ForEach(this.listArray, item => {
  if (item.tag) {
    ListItem() {
    ......
    }.sticky(Sticky.Normal)
  } else {
    ListItem() {
      Stack({ alignContent: Alignment.TopStart }) {
      ......
      }.height(120)
    }
  }
}, item => '' + item)

通过上文的介绍,我们已经实现了应用界面的布局以及界面数据的呈现,此时界面就像没有灵魂的躯壳。下面我们将为大家介绍应用中联动效果的实现。

 

四、实现界面联动

本示例中的联动效果包括导航栏高亮显示、滑动课程内容对应导航栏变化、点击导航栏课程分类跳转到对应课程内容,下面我们将一一道来。

1. 导航栏高亮显示

实现导航栏高亮显示,主要通过@State装饰器监听导航栏课程分类的索引值的状态变化,当用户滑动课程内容或点击导航栏,对应课程分类的索引值发生变化,此时将调用build方法进行UI刷新,从而实现导航栏背景色的修改。相关代码如下:

@State index: number= 0; // 导航栏课程分类的索引
Text(item.data.superName)
  .backgroundColor(this.index == item.index ? 0xffffff : null)

 

2. 右边滑动,左边变化

滑动右边课程内容,对应左边导航栏变化,主要通过onScrollIndex()事件来判断当前课程内容所属的课程分类,当用户滑动课程内容时,对应课程内容的索引值发生变化,导航栏的课程分类的索引值也随之变化。相关代码如下:

private scroller: Scroller = new Scroller()
List({ scroller: this.scroller }) {
  ......
  }
.onScrollIndex((firstIndex: number) => {
  if (this.index != this.listArray[firstIndex].index) {
    this.index = this.listArray[firstIndex].index
  }
})

 

3. 左边点击,右边跳转

点击左边导航栏跳转到对应课程内容,主要通过onClick()事件监听用户点击,当用户点击导航栏,scrollToIndex()方法会根据点击的导航栏课程分类的索引值跳转到对应的课程内容界面。相关代码如下:

Text(item.data.superName)
  .onClick(() => {
    if (this.index != item.index) {
      this.index = item.index
      this.scroller.scrollToIndex(item.data.position)
    }
  })

以上就是本期全部内容,通过本期Codelab的学习,相信你已经掌握了eTS的声明式UI描述、循环渲染、状态数据管理等机制,赶快趁热打铁,开发更多有趣的应用吧!

...全文
93 回复 打赏 收藏 举报
写回复
用AI写文章
回复
切换为时间正序
请发表友善的回复…
发表回复
内容概要:本文提出了一种基于混沌系统与DNA编码的复合型彩色数字图像加密方案,旨在解决传统加密算法密钥空间小、抗干扰能力弱的问题。该方案利用混沌系统生成伪随机序列,结合DNA碱基编码规则对图像RGB三通道进行像素级置换与混淆扩散,实现高安全性加密;解密过程则通过逆操作精确还原原始图像。文章重点对该方案进行了系统的抗噪声与抗裁剪性能分析,实验结果表明,该算法在面对高斯噪声、椒盐噪声以及不同面积、位置的裁剪攻击时均表现出优良的鲁棒性,能够有效恢复图像核心信息,适用于网络传输与私密存储等复杂环境下的图像安全保护。; 适合人群:具备一定信号处理或信息安全基础知识,从事图像加密、信息隐藏、多媒体安全等相关领域的科研人员及研究生。; 使用场景及目标:①用于提升数字图像在网络传输中的安全性,防止窃听与篡改;②适用于医疗影像、军事测绘、商业机密等对图像安全性和抗干扰性要求较高的应用场景;③为研究高鲁棒性图像加密技术提供理论支持与实验参考。; 阅读建议:建议读者结合Matlab代码实践加密与解密流程,并自行设计不同强度的噪声与裁剪干扰实验,深入理解混沌置乱与DNA编码在提升算法鲁棒性方面的协同机制。

5,354

社区成员

发帖
与我相关
我的任务
社区描述
HarmonyOS是一款“面向未来”、面向全场景的分布式操作系统。在传统的单设备系统能力的基础上,HarmonyOS提出了基于同一套系统能力、适配多种终端形态的分布式理念,能够支持多种终端设备。
分布式学习 企业社区
社区管理员
  • HarmonyOS技术社区
  • Edice
  • BaoWei
加入社区
  • 近7日
  • 近30日
  • 至今

试试用AI创作助手写篇文章吧