用 HarmonyOS ArkUI 构建「公式速查」App:从零到一开发手记
一、前言
作为一名开发者和曾经的理科生,我深知中小学阶段数学、物理、化学公式记忆的痛点。每到考试前,学生们总要翻遍课本和笔记,手忙脚乱地寻找某个公式。能不能做一个轻量、快速、随时可查的公式速查工具呢?恰好最近在接触 HarmonyOS 生态,便萌生了用 ArkUI 开发一个「公式速查」应用的念头。
本文将从项目初始化、数据建模、UI 设计、编译构建等完整流程,详细记录这款应用的开发全过程。无论你是 HarmonyOS 新手还是有一定经验的开发者,都能从中获得一些实用的开发思路和技巧。
二、项目背景与目标
2.1 为什么要做这个 App
中小学教育阶段,公式是理科学习的核心工具。数学中的勾股定理、一元二次方程求根公式,物理中的欧姆定律、牛顿第二定律,化学中的物质的量浓度、pH 值计算——这些公式几乎贯穿了整个中学学习周期。然而,多数学生面临的问题不是"不会用",而是"记不住"或"找不到"。市面上的公式类 App 要么过于臃肿,要么广告繁多,要么需要联网才能使用。
因此,我们决定开发一款纯净、离线、轻量的公式速查应用。
2.2 目标用户
- 小学高年级学生(需要基础几何、单位换算等)
- 初中生(数学、物理、化学全套公式需求最旺盛的阶段)
- 高中生(进阶公式、三角函数、电学、化学反应等)
- 教师和家长(辅助教学和辅导使用)
2.3 核心功能需求
三、技术选型与项目初始化
3.1 为什么选择 HarmonyOS + ArkUI
选择 HarmonyOS 平台主要基于以下考虑:
第一,生态趋势。 鸿蒙生态正在快速成长,越来越多的设备和用户接入。开发鸿蒙原生应用,是技术储备也是市场先机。
第二,ArkUI 声明式语法。 ArkUI 采用类 SwiftUI / Jetpack Compose 的声明式 UI 风格,使用 TypeScript 的超集 ArkTS 作为开发语言。对于熟悉前端或现代移动端开发的工程师来说,上手门槛极低。
第三,一次开发多端部署。 HarmonyOS 的应用可以运行在手机、平板、智慧屏等多种设备上,公式速查这种工具类应用天然适合多端覆盖。
3.2 开发环境
- 操作系统:Windows 11
- IDE:DevEco Studio(鸿蒙官方 IDE,基于 IntelliJ)
- SDK 版本:HarmonyOS SDK 6.1.0(对应 API Version 12)
- 构建工具:Hvigor(鸿蒙项目构建工具)
- 目标 API:API 24(Android 兼容性层面),实际基于 HarmonyOS API 12
3.3 项目初始化
通过 DevEco Studio 新建项目,选择"Empty Ability"模板,使用 Stage 模型(即 HarmonyOS 推荐的应用模型)。项目的核心结构如下:
AppScope/
app.json5 ← 全局应用配置
entry/
build-profile.json5 ← 模块构建配置
src/main/
ets/
entryability/ ← Ability(类似 Android 的 Activity)
pages/ ← 页面文件
module.json5 ← 模块清单
resources/ ← 资源文件
这里需要解释一下 Stage 模型。它类似于 Android 的组件化架构,每个 Ability 是一个独立的功能单元,页面通过路由跳转实现导航。相比于老的 FA(Feature Ability)模型,Stage 模型更加灵活,资源管理更清晰。
四、数据模型设计
4.1 数据结构规划
公式数据的特点是层级清晰、结构稳定。我们需要设计三级数据模型:
学科(数学 / 物理 / 化学)
└── 子分类(代数基础、几何图形、三角函数……)
└── 公式条目(名称、表达式、说明、参数说明)
对应的 ArkTS 接口定义如下:
// 公式条目
export interface FormulaItem {
name: string; // 公式名称,如"勾股定理"
expression: string; // 公式表达式,如"a² + b² = c²"
desc: string; // 文字说明,解释公式含义
params: string; // 参数说明,解释每个符号的意义
}
// 公式分类(子分类)
export interface FormulaCategory {
title: string; // 分类标题,如"几何图形"
items: FormulaItem[]; // 该分类下的公式列表
}
主页面上的学科数据通过一个 CategoryEntry 接口来管理:
interface CategoryEntry {
icon: string; // 图标 emoji
title: string; // 学科名称
sub: string; // 子标题说明
color: string; // 主题色
}
4.2 公式数据收录情况
在数据收集阶段,我们参考了人教版、北师大版等主流教材目录,确保覆盖中小学阶段的常用公式。最终收录:
| 数学 | 3 | 36 |
| 物理 | 4 | 38 |
| 化学 | 4 | 24 |
| 合计 | 11 | 98 |
每个公式条目都经过仔细校对,确保表达式准确、描述清晰易懂。
4.3 数据文件组织
我们将所有数据集中放在 model/FormulasData.ets 文件中,以常量数组的形式导出。这样做的好处是:
当然,如果公式数量扩展到上千条,后续可以考虑引入 JSON 文件或轻量数据库(如关系型数据库 RDB)。
五、页面设计与实现
5.1 整体导航架构
应用采用两级导航:
首页(Index.ets)──点击学科卡片──→ 分类详情页(CategoryPage.ets)
使用 @ohos.router 模块进行页面跳转。路由配置在 main_pages.json 中注册:
{
"src": [
"pages/Index",
"pages/CategoryPage"
]
}
5.2 首页设计:三大学科入口
首页的设计思路是简洁直观。顶部是一个深蓝色的标题栏,显示"公式速查"和副标题"中小学常用公式大全"。下方是三个学科卡片,使用不同的主题色区分:
- 数学(蓝色 #4A90D9)
- 物理(橙色 #E67E22)
- 化学(绿色 #27AE60)
每个卡片展示学科图标(Emoji)、名称、包含的子分类说明,以及一个"查看全部 →"的引导文字。卡片采用圆角 + 阴影设计,视觉上层次分明。
ArkUI 中实现卡片非常直接,使用 Stack 作为容器,内部用 Column 布局文本内容,通过 backgroundColor 和 .borderRadius() 设置样式。
Stack() {
Column() {
Text(item.icon).fontSize(44)
Text(item.title).fontSize(20).fontWeight(FontWeight.Bold).fontColor(Color.White)
Text('查看全部 →').fontSize(13).fontColor('#AAFFFFFF')
}
}
.width('100%').height(180)
.backgroundColor(item.color as string)
.borderRadius(20)
.shadow({ radius: 8, color: (item.color as string) + '60', offsetY: 4 })
底部有一段提示文字,说明应用覆盖的范围,让用户一目了然。
5.3 分类详情页:公式浏览
当用户点击某个学科卡片时,通过 router.pushUrl() 跳转到 CategoryPage,同时携带学科参数(图标、名称、主题色)。详情页根据参数动态加载对应的公式数据。
详情页的顶部是一个可返回的标题栏,左侧显示"←"返回按钮和学科名称,背景色与学科主题色一致,形成视觉延续。
主内容区域是一个可滚动的列表,按照子分类分组展示:
- 子分类标题:如"📐 代数基础",使用稍大的粗体字
- 公式卡片:每个公式占一个白色圆角卡片,从上到下依次为公式名称、公式表达式(带浅灰背景高亮)、文字说明、参数说明
这种设计参考了卡片式 UI 的最佳实践——信息层级清晰,视觉节奏舒适。每个公式卡片中,公式表达式使用了加粗的主题色字体,使其在页面中一目了然。
5.4 页面间的数据传递
ArkUI 中页面间传递数据需要使用 router.pushUrl() 的 params 参数。由于 ArkTS 对类型安全要求严格,我们传递的是简单的基本类型参数(字符串),在目标页面通过 router.getParams() 接收。
// 发送方
router.pushUrl({
url: 'pages/CategoryPage',
params: {
categoryIcon: item.icon,
categoryTitle: item.title,
categoryColor: item.color
}
});
// 接收方
aboutToAppear(): void {
const params = router.getParams() as Record<string, string>;
if (params) {
this.categoryTitle = params['categoryTitle'] || '公式';
// … 根据 title 加载对应数据
}
}
这里有一个值得注意的点:aboutToAppear 是组件的生命周期方法,在页面即将显示时调用。我们在这个方法中解析路由参数,并根据 categoryTitle 的值决定加载哪套公式数据。
六、ArkTS 开发的注意事项
6.1 严格类型系统
ArkTS 对类型安全的要求比普通 TypeScript 更加严格——通过编译时的严格检查,减少运行时的意外错误。
问题一:对象字面量不能用作类型声明
这是 ArkTS 和标准 TypeScript 最明显的区别之一。在 TypeScript 中可以写 const items: { id: number }[] = […],但在 ArkTS 中必须显式定义接口:
// ArkTS — 必须显式声明接口
interface CategoryEntry {
icon: string;
title: string;
sub: string;
color: ResourceColor;
}
private categories: CategoryEntry[] = [
{ icon: '📐', title: '数学公式', sub: '代数 · 几何 · 三角', color: '#4A90D9' }
];
问题二:Grid 组件只接受 GridItem 子组件
直接往 Grid 里放 Stack 是不行的。解决方案是用 GridItem 包裹,或改用 Column + ForEach:
// ✅ 用 GridItem 包裹,或改用 Column
Column() {
ForEach(this.categories, (item) => {
Stack() { … }.margin({ bottom: 16 })
})
}
在我的实现中选择了 Column + ForEach,因为页面只有三个卡片,Column 更简洁。
6.2 模块导入规则
HarmonyOS SDK 6.1.0 中,一些 API 的导入路径发生了变化。例如 router 模块:
// ✅ 正确(SDK 6.1.0)
import router from '@ohos.router';
// ❌ 错误
import { router } from '@kit.AbilityKit';
import { router } from '@ohos.router';
从这个错误可以看出,HarmonyOS 的 Kit 体系在不断演进中。@kit.AbilityKit 是较新的模块组织方式,但并非所有 API 都已经迁移过去。在实际开发中,建议以 DevEco Studio 的代码提示为准。
另外需要注意的是,不同的导入方式对应不同的用法:
// 默认导入 — import router from '@ohos.router'
router.pushUrl({ url: 'pages/CategoryPage', params: {…} });
// 命名导入在某些模块中也是可以的
import { BusinessError } from '@kit.BasicServicesKit';
6.3 生命周期理解
ArkUI 组件的生命周期与 Android 的 Activity 有相似之处。在本次开发中,主要用到以下回调:
| aboutToAppear | 组件即将显示 | 初始化数据、解析路由参数 |
| aboutToDisappear | 组件即将销毁 | 清理资源 |
| build | 每次渲染 | 描述 UI 结构 |
注意 build 会被频繁调用(每次状态变量变化时),因此不要在 build 中执行耗时操作。数据初始化应放在 aboutToAppear 中:
aboutToAppear(): void {
const params = router.getParams() as Record<string, string>;
if (params) {
this.categoryTitle = params['categoryTitle'] || '公式';
}
if (this.categoryTitle === '数学公式') {
this.categories = mathCategories;
} else if (this.categoryTitle === '物理公式') {
this.categories = physicsCategories;
} else if (this.categoryTitle === '化学公式') {
this.categories = chemistryCategories;
}
}
七、ArkUI 组件详解
7.1 Column 与 Row:布局基础
ArkUI 的布局体系基于弹性盒模型(Flexbox),与 CSS Flexbox 类似。
- Column:垂直排列子组件(相当于 flex-direction: column)
- Row:水平排列子组件(相当于 flex-direction: row)
- Stack:层叠排列子组件
7.2 Scroll:可滚动容器
Scroll 只接受一个子组件。配合 .layoutWeight(1) 可以让 Scroll 占据父容器的剩余高度空间:
Scroll() {
Column() { /* 所有需要滚动的内容 */ }
}
.width('100%')
.layoutWeight(1)
7.3 Text 与字体样式
Text('公式速查')
.fontSize(28)
.fontWeight(FontWeight.Bold)
.fontColor(Color.White)
.textAlign(TextAlign.Center)
字号单位 fp 是 HarmonyOS 特有的字体像素单位,跟随系统字体缩放自动调整,类似 Android 的 sp。
7.4 @Builder:复用 UI 片段
使用 @Builder 提取重复的 UI 单元(如公式卡片),做到一处修改全局生效:
@Builder FormulaCard(item: FormulaItem) {
Column() {
Text(item.name).fontSize(16).fontWeight(FontWeight.Medium)
Text(item.expression).fontSize(18).fontWeight(FontWeight.Bold)
// …
}
}
7.5 @State:响应式状态管理
@State 装饰器是 ArkUI 响应式编程的核心。被 @State 标记的变量发生变化时,自动触发 UI 重新渲染:
@State categories: FormulaCategory[] = [];
this.categories = mathCategories; // 视图自动更新
这种"状态驱动视图"的模式大大减少了手动操作 UI 的代码量。
八、资源与样式管理
8.1 资源文件组织
HarmonyOS 资源按限定词目录组织。本应用使用了以下资源:
resources/
base/
element/
color.json ← 颜色定义
float.json ← 尺寸定义
string.json ← 字符串定义
media/ ← 图片资源
profile/
main_pages.json ← 路由配置
8.2 主题色设计
- 首页标题栏:深蓝色 #2C3E50
- 数学卡片:蓝色系 #4A90D9
- 物理卡片:橙色系 #E67E22
- 化学卡片:绿色系 #27AE60
- 背景:浅灰色 #F5F6FA
8.3 字体与排版
公式排版采用以下策略:
Unicode 方案的呈现效果虽不如 LaTeX 专业,但对中小学阶段的公式展示已经足够,且避免了额外依赖。
九、构建与部署
9.1 构建流程
HarmonyOS 使用 Hvigor 构建工具,类似 Android 的 Gradle:
hvigorw assembleHap –mode module -p module=entry@default -p product=default
构建流程包括:PreBuild → ProcessProfile → CompileResource → CompileArkTS → PackageHap → SignHap。
9.2 遇到的构建问题
ArkTS 语法检查严格:对象字面量不能作为类型声明、数组需可推断类型——通过定义显式接口解决。
组件类型限制:Grid 组件只接受 GridItem 子组件,需要 GridItem 包裹。
资源名称冲突:AppScope 和 entry 模块定义同名资源会产生冲突警告。应只在 AppScope 放全局资源,模块特有资源放各自目录。
十、应用截图与功能演示
使用流程非常直观:启动 → 选择学科 → 浏览公式列表 → 查看公式详情 → 返回。整个过程无需联网,零等待。
十一、总结与展望
11.1 开发心得
通过这个项目,深入体验了 HarmonyOS 应用开发的完整流程。ArkUI 的声明式 UI 风格提升了开发效率——状态驱动视图更新,避免手动操作 DOM 的繁琐。ArkTS 的严格类型系统虽然在初期带来编译报错,但从长期维护看,类型安全能减少运行时错误。
11.2 可扩展方向
11.3 源码获取
项目源码结构清晰,可在 DevEco Studio 中直接打开运行。所有公式数据集中在 model/FormulasData.ets 文件中,方便后续扩充。
十二、写在最后
开发工具类应用最大的成就感不在于技术的复杂度,而在于产品真正能帮到人。"公式速查"虽然功能简单,但它解决的是一个真实的需求——让学生能够在几秒内找到需要的公式,节省翻书的时间,把更多精力用在理解和应用上。
作为一名开发者,能够用自己的技术为教育做一点微小的贡献,是一件很有意义的事。
如果你也在学习 HarmonyOS 开发,希望这篇博客对你有所帮助。欢迎交流你的开发心得和改进建议!




。*





