鸿蒙电影票助手应用 - 基于影院信息展示的娱乐服务应用


1. 应用概述
电影票(MovieTicket)是一款基于HarmonyOS ArkTS框架开发的娱乐类工具应用,核心功能是模拟电影购票流程,帮助用户选择场次和座位。这款应用虽然界面简洁,但完整地展示了 ArkUI 声明式开发的核心模式,包括列表渲染、状态管理、组件交互等关键知识点。
从技术实现角度来看,电影票应用充分利用了 ArkUI 框架的列表展示能力。通过 @State 装饰器管理电影场次数据,通过 ForEach 组件实现列表渲染,通过 Button 组件实现购票交互。应用的数据结构清晰,展示了如何用 Record 类型定义业务数据模型,以及如何在列表中展示复杂的业务信息。
本技术博客将从应用架构设计、核心代码实现、数据模型设计、UI 布局设计、组件交互设计等多个维度,对这款电影票应用进行全面的技术剖析。通过本文的深入讲解,读者能够掌握 HarmonyOS ArkTS 开发中的核心知识点,特别是列表类应用的设计模式、Record 类型的使用方法、ForEach 循环渲染的技巧,以及购票类应用的前端交互设计。
2. 技术架构分析
2.1 整体架构设计
电影票应用采用了标准的单页面架构,整个应用仅包含一个主页面,通过垂直布局的 Column 容器组织各个功能区块。从代码组织角度来看,应用主要分为以下几个核心部分:页面入口组件(MovieTicket)、通用标题栏组件(CommonTitleBar)、电影场次列表区域。
┌─────────────────────────────────────────────────────────┐
│ MovieTicket页面 │
│ ┌─────────────────────────────────────────────────┐ │
│ │ CommonTitleBar组件 │ │
│ │ (导航栏+标题显示) │ │
│ └─────────────────────────────────────────────────┘ │
│ ┌─────────────────────────────────────────────────┐ │
│ │ 页面标题区域 │ │
│ │ (正在热映) │ │
│ └─────────────────────────────────────────────────┘ │
│ ┌─────────────────────────────────────────────────┐ │
│ │ 电影场次列表区域 │ │
│ │ (List + ForEach + ListItem) │ │
│ │ 每个Item包含: │ │
│ │ - 电影名称、时间、影厅 │ │
│ │ - 价格、购票按钮 │ │
│ └─────────────────────────────────────────────────┘ │
└─────────────────────────────────────────────────────────┘
电影票应用的结构特点是简洁高效,所有功能集中在一个页面中完成,没有复杂的导航结构。列表区域占据了页面的主要空间,是用户交互的核心区域。
2.2 模块依赖关系
从依赖关系的角度分析,电影票应用主要依赖以下几个核心模块:
首先是 CommonTitleBar 组件,该组件提供了统一的页面标题栏和返回按钮功能,是整个应用的基础导航组件。
其次是 ArkUI 的基础组件:
- Column:列布局容器,用于垂直排列子组件
- Row:行布局容器,用于水平排列子组件
- Text:文本组件,用于显示电影名称、时间、价格等信息
- Button:按钮组件,用于触发购票操作
- List:列表容器组件,用于展示电影场次列表
- ListItem:列表项组件,对应单个电影场次
- ForEach:循环渲染组件,用于渲染电影场次列表
- Blank:空白填充组件,用于调整布局空间
- TextInput:文本输入组件(本应用未使用)
2.3 数据模型设计
电影票应用的数据模型设计了一个电影场次数组:
@State app_movies: Record<string, string>[] = [
{ 'name': '流浪地球2', 'time': '14:00', 'hall': '1号厅', 'price': '45' },
{ 'name': '满江红', 'time': '16:30', 'hall': '2号厅', 'price': '40' },
{ 'name': '深海', 'time': '19:00', 'hall': '3号厅', 'price': '38' }
];
@State app_selectedMovie: Record<string, string> | null = null;
| 状态变量 | 类型 | 初始值 | 说明 |
|---|---|---|---|
| app_movies | Record<string, string>[] | 预定义3条数据 | 电影场次数组 |
| app_selectedMovie | Record<string, string> | null | null | 当前选中的电影场次 |
电影场次的数据结构采用 Record 类型,每个场次包含以下字段:
Record<string, string> = {
'name': '电影名称', // string
'time': '放映时间', // string
'hall': '影厅名称', // string
'price': '票价' // string
}
使用 Record 类型而非自定义接口是 ArkTS 中的常见做法。Record<string, string> 表示键为 string 类型、值为 string 类型的对象,这种灵活的类型定义方式适合业务数据模型的快速定义。
3. 核心代码详解
3.1 页面入口与标题栏
电影票应用的入口点使用了 @Entry 和 @Component 两个装饰器:
@Entry
@Component
struct MovieTicket {
// 状态变量定义
@State app_movies: Record<string, string>[] = [...];
@State app_selectedMovie: Record<string, string> | null = null;
build() {
Column() {
CommonTitleBar({
app_title: '电影票',
app_showBack: true
})
// 页面内容
}
}
}
@Entry 装饰器标记这是应用的入口页面,@Component 装饰器标记这是一个 UI 组件。build() 方法是组件的构建入口,返回组件的 UI 结构。
CommonTitleBar 组件的配置说明了应用的基本信息:
CommonTitleBar({
app_title: '电影票',
app_showBack: true
})
| 参数 | 值 | 说明 |
|---|---|---|
| app_title | ‘电影票’ | 页面标题 |
| app_showBack | true | 是否显示返回按钮 |
3.2 电影列表渲染机制
ForEach 组件是 ArkUI 中渲染列表的核心组件,电影票应用使用它来渲染电影场次列表:
List() {
ForEach(this.app_movies, (app_movie: Record<string, string>) => {
ListItem() {
Row() {
// 左侧:电影信息
Column({ space: 4 }) {
Text(app_movie['name'])
.fontSize(18)
.fontWeight(FontWeight.Medium)
.fontColor($r('app.color.app_color_text_primary'))
Row({ space: 8 }) {
Text(app_movie['time'])
.fontSize(14)
.fontColor($r('app.color.app_color_text_secondary'))
Text(app_movie['hall'])
.fontSize(14)
.fontColor($r('app.color.app_color_text_secondary'))
}
}
Blank()
// 右侧:价格和购票按钮
Column({ space: 4 }) {
Text(`¥${app_movie['price']}`)
.fontSize(18)
.fontWeight(FontWeight.Bold)
.fontColor($r('app.color.app_color_danger'))
Button('购票')
.type(ButtonType.Normal)
.backgroundColor($r('app.color.app_color_primary'))
.onClick(() => {
this.app_selectedMovie = app_movie;
})
}
}
.width('100%')
.padding(12)
.backgroundColor($r('app.color.app_color_white'))
.borderRadius(8)
}
})
}
.width('100%')
.layoutWeight(1)
ForEach 的关键参数:
| 参数 | 说明 |
|---|---|
| this.app_movies | 要遍历的电影场次数组 |
| app_movie | 当前遍历到的电影场次对象 |
| app_index | 当前元素的索引(本例未使用) |
ForEach 的渲染机制:
- 接收电影场次数组作为数据源
- 遍历数组每个元素
- 为每个元素渲染一个 ListItem
- ListItem 内部包含完整的电影信息展示
3.3 列表项布局设计
每个电影场次列表项采用了左右分栏的布局设计:
┌─────────────────────────────────────────────────────────┐
│ 电影名称 │ ¥45 │
│ 14:00 1号厅 │ [购票] │
└─────────────────────────────────────────────────────────┘
左侧区域展示电影的核心信息,包括电影名称、放映时间和影厅。右侧区域展示价格和购票按钮。中间使用 Blank() 组件填充剩余空间,实现左右分离的效果。
布局代码结构:
Row() { // 外层水平布局
Column({ space: 4 }) { // 左侧信息区
Text(app_movie['name']) // 电影名称
Row({ space: 8 }) { // 时间和影厅行
Text(app_movie['time'])
Text(app_movie['hall'])
}
}
Blank() // 中间自适应填充
Column({ space: 4 }) { // 右侧操作区
Text(`¥${app_movie['price']}`) // 价格
Button('购票') // 购票按钮
}
}
.width('100%')
.padding(12)
.backgroundColor($r('app.color.app_color_white'))
.borderRadius(8)
3.4 购票交互实现
购票按钮的交互通过 onClick 事件处理:
Button('购票')
.type(ButtonType.Normal)
.backgroundColor($r('app.color.app_color_primary'))
.onClick(() => {
this.app_selectedMovie = app_movie;
})
购票流程分析:
- 用户点击购票按钮
- onClick 回调触发
- 将当前电影场次赋值给 app_selectedMovie 状态变量
- UI 自动重新渲染(如果后续添加订单确认页面,可以基于此状态显示)
按钮样式配置说明:
| 属性 | 值 | 说明 |
|---|---|---|
| type | ButtonType.Normal | 普通按钮类型 |
| backgroundColor | app_color_primary | 使用主题色作为背景 |
ButtonType.Normal 表示普通按钮,这种类型的按钮有圆角背景,适合作为主要操作按钮。相比之下,ButtonType.Circle 是圆形按钮,ButtonType.Text 是文字按钮。
3.5 页面标题设计
页面标题区域采用了简洁的设计:
Text('正在热映')
.fontSize(18)
.fontWeight(FontWeight.Bold)
.fontColor($r('app.color.app_color_text_primary'))
.width('100%')
标题样式配置:
| 属性 | 值 | 说明 |
|---|---|---|
| fontSize | 18 | 字体大小18vp |
| fontWeight | FontWeight.Bold | 加粗字体 |
| fontColor | app_color_primary | 使用主题色 |
| width | ‘100%’ | 占满宽度 |
.fontWeight(FontWeight.Bold) 使用了字体权重枚举,常见的值还有 FontWeight.Normal(正常)、FontWeight.Medium(中等粗细)。
3.6 整体布局结构
电影票应用的 UI 布局采用垂直堆叠的 Column 容器:
build() {
Column() {
// 1. 标题栏
CommonTitleBar({
app_title: '电影票',
app_showBack: true
})
// 2. 内容区域(垂直排列的Column)
Column({ space: 16 }) {
// 2.1 页面标题
Text('正在热映')
// 2.2 电影列表
List() {
ForEach(...)
}
.layoutWeight(1) // 占据剩余高度
}
.width('100%')
.padding(16)
}
.width('100%')
.height('100%')
.backgroundColor($r('app.color.app_color_background'))
}
布局层级说明:
| 层级 | 组件 | 作用 |
|---|---|---|
| 第1层 | Column | 根容器,满屏显示 |
| 第2层 | CommonTitleBar | 标题栏组件 |
| 第2层 | Column | 内容区域容器 |
| 第3层 | Text | 页面标题 |
| 第3层 | List | 电影列表容器 |
layoutWeight(1) 的作用是让 List 组件占据内容区域的全部剩余空间,实现自适应高度。这种布局方式在移动端开发中非常常见,可以确保列表填满屏幕剩余区域。
4. UI 布局设计
4.1 布局容器选择
电影票应用使用了多种布局容器,每种容器都有其特定的使用场景:
Column(列布局):
- 用于垂直排列子组件
- 本应用用于整体页面布局、内容区域布局、信息区域布局
- space 属性设置子组件之间的间距
Row(行布局):
- 用于水平排列子组件
- 本应用用于列表项的水平布局
- space 属性设置子组件之间的间距
Blank(空白填充):
- 用于占据剩余空间
- 本应用用于将购票按钮推到右侧
- 自动扩展以填满可用空间
4.2 样式属性详解
电影票应用中用到的样式属性:
尺寸相关:
.width('100%') // 宽度100%
.height('100%') // 高度100%
.padding(12) // 内边距12vp
.padding(16) // 内边距16vp
.borderRadius(8) // 圆角8vp
文本相关:
.fontSize(18) // 字体大小18
.fontWeight(FontWeight.Bold) // 加粗
.fontColor($r('app.color.xxx')) // 字体颜色
间距相关:
Column({ space: 16 }) // 垂直间距16vp
Row({ space: 8 }) // 水平间距8vp
颜色资源引用:
$r('app.color.app_color_text_primary') // 主文本色
$r('app.color.app_color_text_secondary') // 次要文本色
$r('app.color.app_color_text_tertiary') // 第三文本色
$r('app.color.app_color_primary') // 主题色
$r('app.color.app_color_danger') // 危险/价格色
$r('app.color.app_color_white') // 白色
$r('app.color.app_color_background') // 背景色
4.3 卡片式列表项设计
电影票的列表项采用了卡片式设计:
Row() {
// 电影信息和购票区域
}
.width('100%')
.padding(12)
.backgroundColor($r('app.color.app_color_white'))
.borderRadius(8)
卡片设计的特点:
- 白色背景与灰色页面背景形成对比
- 8vp 圆角提供柔和的视觉效果
- 12vp 内边距提供舒适的内容空间
- width(‘100%’) 确保卡片宽度填满列表
4.4 价格展示设计
价格展示是购票类应用的关键信息,需要特别设计:
Text(`¥${app_movie['price']}`)
.fontSize(18)
.fontWeight(FontWeight.Bold)
.fontColor($r('app.color.app_color_danger'))
价格样式要点:
- 使用危险色/强调色(红色系)突出价格
- 18号字体配合加粗,确保价格醒目
- ¥ 符号使用模板字符串拼接
5. ArkTS 核心特性应用
5.1 Record 类型详解
电影票应用使用 Record 类型定义电影场次数据结构:
@State app_movies: Record<string, string>[] = [
{ 'name': '流浪地球2', 'time': '14:00', 'hall': '1号厅', 'price': '45' }
];
Record 类型的特点:
- 键的类型固定为 string
- 值的类型固定为 string
- 适合结构相对固定的数据模型
- 访问属性使用数组下标语法(obj[‘key’])
访问 Record 数据的示例:
let movieName: string = app_movie['name']; // 获取电影名称
let movieTime: string = app_movie['time']; // 获取放映时间
let movieHall: string = app_movie['hall']; // 获取影厅
let moviePrice: string = app_movie['price']; // 获取票价
5.2 @State 装饰器使用
@State 是 ArkTS 中用于管理组件状态的装饰器:
@State app_movies: Record<string, string>[] = [...];
@State app_selectedMovie: Record<string, string> | null = null;
@State 的特点:
- 只能在 @Component 修饰的组件中使用
- 状态变化自动触发 UI 重新渲染
- 适合管理组件私有状态
- 数组类型状态修改需要使用数组方法
5.3 $r 资源引用
$r 是 ArkUI 中引用资源的方式:
.fontColor($r('app.color.app_color_text_primary'))
.backgroundColor($r('app.color.app_color_white'))
$r 的优势:
- 支持主题切换(浅色/深色)
- 统一管理颜色等资源
- 提高代码可维护性
5.4 模板字符串使用
电影票应用中使用了模板字符串拼接价格显示:
Text(`¥${app_movie['price']}`)
模板字符串的语法:
- 使用反引号(`)包裹字符串
- ${expression} 嵌入表达式
- 表达式结果自动转换为字符串
6. 购票类应用开发要点
6.1 列表设计模式
购票类应用的列表设计通常包含以下要素:
| 要素 | 说明 |
|---|---|
| 核心信息 | 电影名称、航班号、酒店名等 |
| 次要信息 | 时间、地点、评分等 |
| 价格信息 | 票价、起价等 |
| 操作按钮 | 购票、预订、查看等 |
6.2 左右分栏布局
电影票应用的列表项采用了左右分栏布局:
┌─────────────────────────────────────────────────────────┐
│ │
│ 电影名称 │ │
│ 时间 影厅 │ [购票] │
│ │ ¥45 │
│ │
└─────────────────────────────────────────────────────────┘
实现要点:
- 外层使用 Row 实现水平布局
- 左侧信息区使用 Column 实现垂直排列
- 中间使用 Blank 自动填充剩余空间
- 右侧操作区使用 Column 实现垂直排列
6.3 可复用组件设计
电影票应用的可复用组件包括:
CommonTitleBar:通用标题栏组件,提供了统一的导航和标题显示功能。这个组件在整个应用中被多个页面复用,保证了 UI 的一致性。
6.4 交互反馈设计
购票按钮提供了明确的交互反馈:
Button('购票')
.type(ButtonType.Normal)
.backgroundColor($r('app.color.app_color_primary'))
交互反馈要点:
- 使用主题色背景,表示这是主要操作
- 普通按钮类型,有足够的点击区域
- 点击后更新选中状态,提供视觉反馈
7. 扩展与展望
7.1 当前功能总结
电影票应用实现了以下核心功能:
| 功能模块 | 实现描述 |
|---|---|
| 电影展示 | 使用 List 和 ForEach 渲染电影场次列表 |
| 场次信息 | 显示电影名称、放映时间、影厅信息 |
| 价格显示 | 使用强调色展示票价 |
| 购票操作 | 点击购票按钮选中场次 |
| 状态管理 | 使用 @State 管理选中状态 |
7.2 功能扩展方向
基于当前的电影票应用架构,可以进行以下功能扩展:
座位选择功能:这是电影购票的核心功能,可以扩展座位平面图:
@State app_seats: boolean[][] = []; // 座位状态数组
@State app_selectedSeats: string[] = []; // 已选座位
// 座位选择逻辑
onClick(() => {
if (this.app_seats[row][col] === false) {
this.app_seats[row][col] = true;
this.app_selectedSeats.push(`${row}-${col}`);
}
})
电影详情页:点击电影名称可以进入详情页:
Text(app_movie['name'])
.onClick(() => {
// 跳转到详情页
})
筛选功能:支持按时间、影厅筛选:
@State app_filterType: string = '全部';
Row({ space: 16 }) {
Button('全部')
Button('上午')
Button('下午')
Button('晚上')
}
评论展示:显示其他用户的评分和评论:
interface MovieComment {
userName: string;
rating: number;
comment: string;
}
7.3 数据持久化
当前应用的数据是预定义的静态数据,扩展后可以使用 AppStorage 进行持久化:
aboutToAppear(): void {
// 页面显示时加载数据
}
aboutToDisappear(): void {
// 页面消失时保存数据
}
8. 技术要点总结
8.1 核心代码模块
电影票应用的代码结构:
@Entry
@Component
struct MovieTicket {
@State app_movies: Record<string, string>[] = [
{ 'name': '流浪地球2', 'time': '14:00', 'hall': '1号厅', 'price': '45' },
{ 'name': '满江红', 'time': '16:30', 'hall': '2号厅', 'price': '40' },
{ 'name': '深海', 'time': '19:00', 'hall': '3号厅', 'price': '38' }
];
@State app_selectedMovie: Record<string, string> | null = null;
build() {
Column() {
CommonTitleBar({...})
Column({ space: 16 }) {
Text('正在热映')
List() {
ForEach(this.app_movies, (app_movie) => {
ListItem() { ... }
})
}
.layoutWeight(1)
}
.padding(16)
}
.backgroundColor($r('app.color.app_color_background'))
}
}
8.2 关键技术点
| 技术点 | 在本应用中的体现 |
|---|---|
| @Entry | 标记页面入口 |
| @Component | 标记UI组件 |
| @State | 管理电影列表和选中状态 |
| List组件 | 电影场次列表容器 |
| ForEach组件 | 遍历渲染电影列表 |
| Record类型 | 电影场次数据结构 |
| $r资源引用 | 引用颜色等资源 |
| 模板字符串 | 拼接价格显示 |
| onClick事件 | 处理购票点击 |
| layoutWeight | 自适应列表高度 |
8.3 组件层级结构
| 层级 | 组件 | 说明 |
|---|---|---|
| 1 | Column | 根容器 |
| 2 | CommonTitleBar | 标题栏 |
| 2 | Column | 内容区 |
| 3 | Text | 页面标题 |
| 3 | List | 列表容器 |
| 4 | ForEach | 循环渲染 |
| 4 | ListItem | 列表项 |
| 5 | Row | 列表项内容 |
| 6 | Column | 信息区/操作区 |
| 7 | Text | 文本显示 |
| 7 | Button | 按钮 |
9. 完整代码结构
import { CommonTitleBar } from '../../components/CommonTitleBar';
@Entry
@Component
struct MovieTicket {
@State app_movies: Record<string, string>[] = [
{ 'name': '流浪地球2', 'time': '14:00', 'hall': '1号厅', 'price': '45' },
{ 'name': '满江红', 'time': '16:30', 'hall': '2号厅', 'price': '40' },
{ 'name': '深海', 'time': '19:00', 'hall': '3号厅', 'price': '38' }
];
@State app_selectedMovie: Record<string, string> | null = null;
build() {
Column() {
CommonTitleBar({
app_title: '电影票',
app_showBack: true
})
Column({ space: 16 }) {
Text('正在热映')
.fontSize(18)
.fontWeight(FontWeight.Bold)
.fontColor($r('app.color.app_color_text_primary'))
.width('100%')
List() {
ForEach(this.app_movies, (app_movie: Record<string, string>) => {
ListItem() {
Row() {
Column({ space: 4 }) {
Text(app_movie['name'])
.fontSize(18)
.fontWeight(FontWeight.Medium)
.fontColor($r('app.color.app_color_text_primary'))
Row({ space: 8 }) {
Text(app_movie['time'])
.fontSize(14)
.fontColor($r('app.color.app_color_text_secondary'))
Text(app_movie['hall'])
.fontSize(14)
.fontColor($r('app.color.app_color_text_secondary'))
}
}
Blank()
Column({ space: 4 }) {
Text(`¥${app_movie['price']}`)
.fontSize(18)
.fontWeight(FontWeight.Bold)
.fontColor($r('app.color.app_color_danger'))
Button('购票')
.type(ButtonType.Normal)
.backgroundColor($r('app.color.app_color_primary'))
.onClick(() => {
this.app_selectedMovie = app_movie;
})
}
}
.width('100%')
.padding(12)
.backgroundColor($r('app.color.app_color_white'))
.borderRadius(8)
}
})
}
.width('100%')
.layoutWeight(1)
}
.width('100%')
.padding(16)
}
.width('100%')
.height('100%')
.backgroundColor($r('app.color.app_color_background'))
}
}
10. 结语
电影票应用作为一款模拟购票类应用,展示了 HarmonyOS ArkUI 框架在列表展示和交互设计方面的核心能力。通过 List、ForEach、Button 等组件的组合使用,实现了电影场次列表的完整展示和购票交互功能。
从技术角度来看,应用的核心亮点在于列表渲染和布局设计。ForEach 组件配合 List 组件实现了高效列表渲染,Row 和 Column 的嵌套使用实现了复杂的列表项布局,Blank 组件实现了自适应空间填充。
从应用设计的角度来看,电影票应用遵循了"信息清晰、操作便捷"的设计原则。每个列表项都清晰地展示了电影名称、放映时间、影厅和价格信息,用户可以快速选择场次并完成购票操作。价格使用强调色突出显示,让用户一眼就能看到关键信息。
虽然当前应用功能相对简单,但已经完整展示了 ArkTS 声明式开发的核心理念。通过扩展座位选择、电影详情、筛选功能等,可以逐步演进为一个完整的电影购票应用。
更多推荐



所有评论(0)