1、前言
经过我们前面10章的学习,我们基本上可以开发出一个简单的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、源代码
代码仓库地址:
https://gitee.com/lantingshuxu/harmony-calculator
速览核心的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
@Component
struct 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”
声明:本站所有文章,如无特殊说明或标注,均为本站原创发布。任何个人或组织,在未征得本站同意时,禁止复制、盗用、采集、发布本站内容到任何网站、书籍等各类媒体平台。如若本站内容侵犯了原著者的合法权益,可联系我们进行处理。