想要程序做什么首先自己要明确自己想要什么,通过分析选题思考程序需要哪些信息,如何与用户进行交互,以及以什么样的形式反馈给用户(即UI设计),最终通过运行调试完成整个应用程序的开发。
一、做什么
做一款多功能的计算器,其中类型包含标准计算器、科学计算器、程序员计算器、房贷计算器等。
二、做成什么样
计算器给用户提供多功能选择,通过按钮进行交互,文本进行反馈显示,并通过一系列数据处理,最终反馈给用户正确的值。可以通过一幅图或者一个演示Demo来确认是否与预期相符,便于不会因为决策导致返工(本节以标准计算器为例,其他示例不在此处赘述)。
1、分析
将整个页面分为三块,标题栏,显示区,功能按钮区。
- 标题栏: 通过点击图标切换不同计算器,同时提供历史记录查询。
- 显示区: 通过两个文本组件分别显示录入计算表达式和计算结果。
- 功能按钮区: 功能按钮区分为功能按钮(如清空,回退等),符号按钮(如加、减等),及数字按钮(0-9数字键)。
2、 用到的知识点
对即将实现的标准计算器UI界面分析后,从中提炼出需要用到的技术。
- 对于实现设计的UI界面,需要了解ArkUI的【布局约束】。
- 对于三大块自上而下的布局方式,需要了解【Flex布局】或【Column容器组件】。
- 对于三大块内元素(组件)排列,需要了解【Flex布局】或【Row容器组件】。
- 对于UI界面中点击选择,需要了解【Menu控制】。
- 对于UI界面中单个按钮元素(组件),需要了解【Button组件】和【点击事件】。
- 对于UI界面中单个文本显示元素(组件),需要了解【Text组件】和【@State组件状态管理】。
三、编写代码
1、 分析示例代码
创建项目和目录结构已经在 了解一些ArkUI概念并熟悉应用的结构 中介绍过了,有需要可以查看。打开index.ets文件,示例代码实现了页面居中显示Hello World,先来了解每行代码代表的含义。
@Entry
@Component
struct Index {
build() { }
}
1.1 @Entry装饰器
@Entry 注解(装饰,我更愿意称为注解)的自定义组件(在ArkUI中一切皆为组件,使用已有组件组合构成页面)作为页面的默认入口,也可以理解为页面的根节点。当页面被加载时,首先创建并呈现@Entry注解的组件,一个页面中有且仅能使用一个@Entry注解,只有使用@Entry注解的组件或子组件,才会在页面上显示。
1.2 @Component装饰器
@Component 注解(装饰)的代码块具有组件化能力,能够成为一个独立的组件,这个类型组件也称为自定义组件,必须在build()方法描述UI结构,且不能自定义构造函数。
// 这种写法错误,因为缺少build()方法
// 报错 struct 'MyComponent' must be at least or at most one 'build' method.
@Component
struct MyComponent {
Flex() {}
}
自定义组件具有以下特点:
- 可组合:可以使用内置组件、其他组件、公共属性和方法组合需要的UI结构,比如使用Text和Button组件自定义弹窗组件。
- 可重用:自定义组件可以被其他组件重用,并作为不同的实例在不同的父组件或容器中使用,比如自定义弹窗可以多次重复使用。
- 生命周期:生命周期的回调方法可以在组件中配置,用于业务逻辑处理。
- 数据驱动更新:由状态变量的数据驱动,实现UI自动更新。
1.3 build()函数(方法)
build() 满足Build构造器接口定义,用于定义组件的声明式UI描述。在build方法中以声明式方式进行组合自定义组件或系统内置组件,在组件创建和更新场景中都会调用build方法。build方法仅支持组合组件,使用渲染控制语句。
build() {
Flex({ direction: FlexDirection.Column, alignItems: ItemAlign.Center, justifyContent: FlexAlign.Center }) {
Text('Hello World')
.fontSize(50)
.fontWeight(FontWeight.Bold)
}
.width('100%')
.height('100%')
}
2、 Flex容器组件和Flex布局
通过3.1小节的了解,我们可以在被@Entry和@Componet注解的代码块中的build函数中使用框架提供的内置基本组件和布局(容器)组件来构建自定义组件并显示到页面中。当然我们也可以不适用容器组件而直接使用基本组件来构建页面元素,但不推荐这种做法,组件过多无法有效的进行布局控制。如下代码与示例效果相同:
@Entry
@Component
struct Index {
build() {
Text('Hello World')
.fontSize(50)
.fontWeight(FontWeight.Bold)
.textAlign(TextAlign.Center)
.width('100%')
.height('100%')
// Flex({ direction: FlexDirection.Column, alignItems: ItemAlign.Center, justifyContent: FlexAlign.Center }) {
// Text('Hello World')
// .fontSize(50)
// .fontWeight(FontWeight.Bold)
// }
// .width('100%')
// .height('100%')
}
}
为了满足复杂的、可控的、已维护的UI界面,我们必须对容器组件有一定的了解,在不同的场景下使用不同的容器组件,可以快速有效的构建符合需要的UI界面。接下来使用Flex容器组件实现标准计算器三大块分隔。
2.1 Flex容器组件
Flex容器组件称为弹性布局组件,通过简单灵活的控制子组件、并具备响应式,可以实现各种页面布局,因此Flex布局作为首选布局。
Flex容器组件具有以下特点:
- 四种子组件布局模式:Row(行方向)、RowReverse(反Row)、Column(列方向)、ColumnReverse(反列)。
- 容器元素单行/多行显示:NoWrap(单行/列布局)、Wrap(多行/列布局)、WrapReverse(反向多行/列布局),均允许元素超出容器。
- 两种对齐方式:主轴对齐方式和交叉轴对齐方式。
- 仅当父组件为Flex容器组件时,还可以设置子组件在主轴方向上基准尺寸(flexBasis)、子组件在容器剩余空间的比例(flexGrow)、压缩尺寸分配给子组件(flexShrink)以及设置子组件在容器中交叉轴对齐方式(alignSelf)。
@Entry
@Component
struct Index {
build() {
Flex({ direction: FlexDirection.Column, alignItems: ItemAlign.Center,
justifyContent: FlexAlign.Center }) {
Text('主轴与行方向一致作为布局模式')
.fontSize(9)
.fontColor('#CCCCCC')
.width('90%')
// 主轴与行方向一致作为布局模式
Flex({direction: FlexDirection.Row, wrap: FlexWrap.NoWrap,
justifyContent: FlexAlign.Center, alignItems: ItemAlign.Center}) {
Text('A').flexGrow(2).height(100).fontSize(50)
.backgroundColor('#F2F2F2').textAlign(TextAlign.Center)
Text('B').flexGrow(1).height(100).fontSize(50)
.backgroundColor('#E2E2E2').textAlign(TextAlign.Center)
}
.width('100%').height(120).padding(10)
Text('与Row方向相反方向进行布局')
.fontSize(9)
.fontColor('#CCCCCC')
.width('90%')
// 与Row方向相反方向进行布局
Flex({direction: FlexDirection.RowReverse, wrap: FlexWrap.NoWrap,
justifyContent: FlexAlign.Center, alignItems: ItemAlign.Center}) {
Text('A').flexGrow(2).height(100).fontSize(50)
.backgroundColor('#F2F2F2').textAlign(TextAlign.Center)
Text('B').flexGrow(1).height(100).fontSize(50)
.backgroundColor('#E2E2E2').textAlign(TextAlign.Center)
}
.width('100%').height(120).padding(10)
Text('主轴与列方向一致作为布局模式')
.fontSize(9)
.fontColor('#CCCCCC')
.width('90%')
// 主轴与列方向一致作为布局模式
Flex({direction: FlexDirection.Column, wrap: FlexWrap.NoWrap,
justifyContent: FlexAlign.Center, alignItems: ItemAlign.Center}) {
Text('A').flexGrow(2).width('100%').fontSize(50)
.backgroundColor('#F2F2F2').textAlign(TextAlign.Center)
Text('B').flexGrow(1).width('100%').fontSize(50)
.backgroundColor('#E2E2E2').textAlign(TextAlign.Center)
}
.width('100%').height(200).padding(10)
Text('与Column相反方向进行布局')
.fontSize(9)
.fontColor('#CCCCCC')
.width('90%')
// 与Column相反方向进行布局
Flex({direction: FlexDirection.ColumnReverse, wrap: FlexWrap.NoWrap,
justifyContent: FlexAlign.Center, alignItems: ItemAlign.Center}) {
Text('A').flexGrow(2).width('100%').fontSize(50)
.backgroundColor('#F2F2F2').textAlign(TextAlign.Center)
Text('B').flexGrow(1).width('100%').fontSize(50)
.backgroundColor('#E2E2E2').textAlign(TextAlign.Center)
}
.width('100%').height(200).padding(10)
}
.width('100%')
.height('100%')
}
}
2.2 标准计算器Flex布局实现
通过Flex容器布局构建页面,子组件以三个Flex容器组件为主,占比分别为1、2、4,并使用不同的背景色做简单的区域划分,代码如下:
@Entry
@Component
struct Index {
build() {
Flex({ direction: FlexDirection.Column, alignItems: ItemAlign.Center,
justifyContent: FlexAlign.Center }) {
// 顶部功能按钮
Flex({direction: FlexDirection.Row}) {}
.flexGrow(1)
.width('100%')
.backgroundColor('#F2F2F2')
// 回显及结果显示区
Flex({direction: FlexDirection.Column}) {}
.flexGrow(2)
.width('100%')
.backgroundColor('#FFFFFF')
// 功能按钮、符号按钮、数字按钮
Flex({direction: FlexDirection.Column}) {}
.flexGrow(4)
.width('100%')
.backgroundColor('#E5E5E5')
}
.width('100%')
.height('100%')
.backgroundColor('#F5F5F5')
}
}
小结
这并不是完结,而是开始。本篇幅描述了从需求开始一步步到代码实现;从设计图到代码实现;从技术要点到代码实现。从学到用,从用到学,逐渐掌握ArkUI框架的ets项目开发,下一篇将继续本篇幅的内容。