文章来自公众号“Harmony自习室”

1、前言
经过我们前面10章的学习,我们基本上可以开发出一个简单的APP了,为了巩固学习的内容,我们先开发一个计算器APP来连个手(文末有源代码),界面如下:

-
包含基本的计算器运算功能
-
支持一键清空,支持逐个删除数字
-
支持将上次计算的过程保存下来,下次打开app继续;
-
支持清理之前保存的记录
这里面我们会用到知识如下:
-
开发UI界面(基本控件的使用以及基本布局的使用);
-
监听用户点击事件,在输入栏中及时反馈(动态交互);
-
支持将过程持久化到本地,下次打开后自动恢复;
let's go!💪🏻💪🏻💪🏻
2、创建项目 & 初始化
打开开发工具 DevEco-Studio,按照以下顺序创建项目,过程不再详述,看截图。



3、UI描述
我们的布局比较简单,分三个大块从上到下,分别是:
-
用户输入与计算结果显示部分;
-
核心数字键盘部分;
-
一个大的=按钮
示意图如下:

我们可以注意到,数字按钮的样式是一样的(蓝色),操作符按钮的样式也是一样的(绿色),三个功能按钮的样式也是一样的(红色),因此,我们可以使用鸿蒙的样式复用只是来减少重复代码量。
我们三部分复用的样式代码如下:
// 数字键盘的公共样式@Extend(Button) function numberBtn(num: number, click: (num: number) => void) {.type(ButtonType.Capsule).width(60).height(60).onClick(() => click(num))}// 运算符公共样式@Extend(Button) function operatorBtn() {.type(ButtonType.Capsule).backgroundColor(Color.Green).width(60).height(60)}// 额外功能公共样式@Extend(Button) function extraBtn() {.type(ButtonType.Capsule).width(60).height(60).backgroundColor(Color.Red)}
紧接着就是我们的UI描述部分代码,如下:
build() {Column() {Column() {Text(this.message).fontSize(20).width('100%').textAlign(TextAlign.End)}.padding(10).backgroundColor('gray').borderWidth(1).borderRadius(10).margin(10)Row() {Button('7').numberBtn(7, this.onNumberClick)Button('8').numberBtn(8, this.onNumberClick)Button('9').numberBtn(9, this.onNumberClick)Button('重置').extraBtn().onClick(this.onResetClick)}.justifyContent(FlexAlign.SpaceAround).numberRow()Row() {Button('4').numberBtn(4, this.onNumberClick)Button('5').numberBtn(5, this.onNumberClick)Button('6').numberBtn(6, this.onNumberClick)Button('删除').extraBtn().onClick(this.onDeleteClick)}.numberRow().justifyContent(FlexAlign.SpaceAround)Row() {Button('1').numberBtn(1, this.onNumberClick)Button('2').numberBtn(2, this.onNumberClick)Button('3').numberBtn(3, this.onNumberClick)Button('清理').extraBtn().onClick(this.onClearClick)}.numberRow().justifyContent(FlexAlign.SpaceAround)Row() {Button('%').type(ButtonType.Capsule).width(60).height(60)Button('0').numberBtn(0, this.onNumberClick)Button('.').type(ButtonType.Capsule).width(60).height(60).onClick(this.onDotClick)Button('保存').operatorBtn().onClick(this.onSaveClick)}.numberRow().justifyContent(FlexAlign.SpaceAround)Row() {Button('x').operatorBtn().onClick(() => this.onOperatorClick('x'))Button('÷').operatorBtn().onClick(() => this.onOperatorClick('÷'))Button('+').operatorBtn().onClick(() => this.onOperatorClick('+'))Button('-').operatorBtn().onClick(() => this.onOperatorClick('-'))}.numberRow().justifyContent(FlexAlign.SpaceAround)Row() {Button('=').width('100%').backgroundColor(Color.Pink).onClick(this.onCalcClick)}.margin(10)}.height('100%')}
4、用户交互
紧接着,我们来实现用户的功能交互
-
用户点击数字按钮时,监听器事件
onNumberClick = (num: number) => {if (this.message === '0') {this.message = `${num}`;} else {this.message += `${num}`}}
-
用户点击运算符按钮时的监听器事件
onOperatorClick = (_opt: string) => {this.message += _opt;this.calcFinished = false;}
-
数据持久化和清空持久化数据
onSaveClick = () => {AppStorage.SetOrCreate('lastResult', this.message);}onClearClick = () => {PersistentStorage.DeleteProp('lastResult')this.message = '0';}
其他的功能感兴趣可以在文末看详细的源代码。演示如下(包含了数据持久化,现场恢复的演示)

5、源代码
代码仓库地址:鸿蒙计算器
速览核心的UI代码:
// 数字键盘的公共样式@Extend(Button) function numberBtn(num: number, click: (num: number) => void) {.type(ButtonType.Capsule).width(60).height(60).onClick(() => click(num))}// 运算符公共样式@Extend(Button) function operatorBtn() {.type(ButtonType.Capsule).backgroundColor(Color.Green).width(60).height(60)}// 额外功能公共样式@Extend(Button) function extraBtn() {.type(ButtonType.Capsule).width(60).height(60).backgroundColor(Color.Red)}PersistentStorage.PersistProp('lastResult', '0');type Operator = '+' | '-' | '*' | '/' | '(' | ')';// 传入字符串,运算其结果(可以跳过)function calculate(expression: string): number {//.. 这部分代码是计算用户输入结果d的,不重要,省略}@Entry@Componentstruct Index {@StorageProp('lastResult') message: string = '0'calcFinished: boolean = true;@Styles numberRow() {.width('100%').margin({ bottom: 10 })}build() {Column() {Column() {Text(this.message).fontSize(20).width('100%').textAlign(TextAlign.End)}.padding(10).backgroundColor('gray').borderWidth(1).borderRadius(10).margin(10)Row() {Button('7').numberBtn(7, this.onNumberClick)Button('8').numberBtn(8, this.onNumberClick)Button('9').numberBtn(9, this.onNumberClick)Button('重置').extraBtn().onClick(this.onResetClick)}.justifyContent(FlexAlign.SpaceAround).numberRow()Row() {Button('4').numberBtn(4, this.onNumberClick)Button('5').numberBtn(5, this.onNumberClick)Button('6').numberBtn(6, this.onNumberClick)Button('删除').extraBtn().onClick(this.onDeleteClick)}.numberRow().justifyContent(FlexAlign.SpaceAround)Row() {Button('1').numberBtn(1, this.onNumberClick)Button('2').numberBtn(2, this.onNumberClick)Button('3').numberBtn(3, this.onNumberClick)Button('清理').extraBtn().onClick(this.onClearClick)}.numberRow().justifyContent(FlexAlign.SpaceAround)Row() {Button('%').type(ButtonType.Capsule).width(60).height(60)Button('0').numberBtn(0, this.onNumberClick)Button('.').type(ButtonType.Capsule).width(60).height(60).onClick(this.onDotClick)Button('保存').operatorBtn().onClick(this.onSaveClick)}.numberRow().justifyContent(FlexAlign.SpaceAround)Row() {Button('x').operatorBtn().onClick(() => this.onOperatorClick('x'))Button('÷').operatorBtn().onClick(() => this.onOperatorClick('÷'))Button('+').operatorBtn().onClick(() => this.onOperatorClick('+'))Button('-').operatorBtn().onClick(() => this.onOperatorClick('-'))}.numberRow().justifyContent(FlexAlign.SpaceAround)Row() {Button('=').width('100%').backgroundColor(Color.Pink).onClick(this.onCalcClick)}.margin(10)}.height('100%')}resetCheck() {if (this.calcFinished) {this.message = '0';this.calcFinished = false;}}onNumberClick = (num: number) => {this.resetCheck();if (this.message === '0') {this.message = `${num}`;} else {this.message += `${num}`}}onOperatorClick = (_opt: string) => {this.message += _opt;this.calcFinished = false;}onDotClick = () => {this.resetCheck();this.message += '.';}onResetClick = () => {this.message = '0';this.calcFinished = true;}onDeleteClick = () => {this.resetCheck();if (this.message.length > 1) {this.message = this.message.substr(0, this.message.length - 1);} else {this.message = '0'}}onSaveClick = () => {AppStorage.SetOrCreate('lastResult', this.message);}onClearClick = () => {PersistentStorage.DeleteProp('lastResult')this.message = '0';}onCalcClick = () => {this.message = calculate(this.message.replace(/x/g, '*').replace(/÷/g, '/')) + '';this.calcFinished = true;}}
6、结语
从代码我们可以看到,依旧存在很多相似的重复代码,我们还可以优化下吗?
答案是可以的,使用条件渲染。
请持续关注 "鸿蒙UI开发快速入门 —— part11"
如果你也对鸿蒙开发感兴趣,加入“Harmony自习室”吧!
扫描下面的二维码关注公众号。

1404

被折叠的 条评论
为什么被折叠?



