HarmonyOS NEXT ArkTS 实战:构建「聊天机器人」App 完整教程
HarmonyOS NEXT ArkTS 实战:构建「聊天机器人」App 完整教程


目录
1. 应用概览
1.1 什么是聊天机器人 App
「聊天机器人」是一个模拟真人对话的交互式 App。用户发送消息后,内置的机器人会随机从 25 条预设回复中选一条回应,并伴有「正在输入……」的延迟提示,营造真实的聊天体验。
| 功能 | 说明 |
|---|---|
| 发送消息 | 用户输入文字,点击发送按钮 |
| 消息气泡 | 用户消息紫色右对齐,机器人消息白色左对齐 |
| 自动回复 | 25 条中文回复池,随机选取,支持 emoji |
| 输入延迟 | 800~2000ms 随机延迟 + 正在输入状态 |
| 快捷话题 | 4 个预设话题,点击即发送,适合新手引导 |
| 清空聊天 | 一键清空所有消息记录 |
| 时间戳 | 每条消息显示发送时间(HH:mm) |
1.2 为什么选聊天机器人作为 ArkTS 示例
聊天界面是移动端最经典的交互模式之一,涵盖了 ArkTS 开发中的多个核心知识:
- 列表渲染:
@State msgs[]+ForEach动态渲染消息 - 条件渲染:用户/机器人消息分别渲染不同的气泡样式
- 滚动容器:
Scroll自动滚到底部查看最新消息 - 输入处理:
TextInput双向绑定 + 发送逻辑 - 异步操作:
setTimeout模拟网络延迟 - 状态切换:
@State typing控制「正在输入」提示的显隐
168 行代码实现一个完整的聊天交互,是 ArkTS 声明式 UI 效率的最佳体现。
2. 项目架构设计
2.1 代码结构
1-2 import 导入(promptAction / pasteboard)
4-9 Msg 接口定义
11-37 BOT_REPLIES 回复池(25 条)
39 MSG_ID 自增 ID
41-168 ChatApp 主结构体
├── 44-46 @State 状态(msgs / input / typing)
├── 48-113 build() UI 布局
│ ├── 50-61 顶栏
│ ├── 64-98 消息列表(Scroll)
│ └── 100-112 输入区
├── 116-118 quickTopics 快捷话题
├── 120-144 @Builder MsgBubble 消息气泡
├── 146-161 sendMsg 发送逻辑
└── 163-167 getTime 时间格式化
2.2 UI 布局层级
Column(全屏)
├── Row 顶栏(💬 聊天机器人 · 在线 🗑️)
├── Scroll 消息列表
│ └── Column
│ ├── 空状态(🤖 + 快捷话题)
│ ├── ForEach → MsgBubble × N
│ └── 正在输入提示
└── Row 输入区
├── TextInput
└── ➡️ 发送按钮
2.3 数据流
用户输入文字
↓ onChange 更新 @State input
点击发送按钮
↓ sendMsg(input)
↓ 1. 清空 input
↓ 2. 创建 Msg 对象,push 到 msgs
↓ 3. @State msgs 变化 → ForEach 渲染新消息气泡
↓ 4. @State typing = true → 显示「正在输入……」
↓ 5. setTimeout 延迟 0.8~2 秒
↓ 6. @State typing = false → 隐藏提示
↓ 7. 随机选回复消息,push 到 msgs
↓ 8. @State msgs 变化 → 机器人气泡出现
3. 数据模型
3.1 Msg 接口
interface Msg {
id: number; // 唯一标识,用于 ForEach key
text: string; // 消息文本
from: string; // 发送者:'me' 或 'bot'
time: string; // 发送时间,格式 "HH:mm"
}
每个消息对象包含 4 个字段,覆盖了一条聊天记录的全部信息。
3.2 回复池
const BOT_REPLIES: string[] = [
'哈哈,有意思!😄',
'原来如此,继续说~',
'我在听呢 👂',
'这个想法不错!👍',
'我也这么觉得!',
'明天天气好像不错 ☀️',
'你最近在忙什么呀?',
'今天心情怎么样?😊',
'给你推荐一首歌吧~',
'生活就像一盒巧克力 🍫',
'你说得对,确实是这样',
'嗯嗯,有道理!',
'要不要出去走走?🚶',
'晚安,好梦 🌙',
'早安!新的一天开始了 🌅',
'加油!你可以的 💪',
'这个话题很有趣!',
'让我想想……🤔',
'好主意!我支持你',
'开心最重要!🎉',
'今天吃了什么好吃的?🍜',
'周末有什么计划吗?',
'一起努力吧!',
'你说的话让我思考了很多',
'谢谢分享~🌟',
];
25 条回复覆盖了日常聊天的常见场景:认同、反问、分享、鼓励、问候。每条都带 emoji,让回复显得更自然。
3.3 自增 ID
let MSG_ID: number = 1;
全局自增 ID,确保每条消息有唯一的标识符,用于 ForEach 的 keyGenerator。
4. 聊天界面布局
4.1 整体结构
使用 Column 从上到下排列三个区域:
build() {
Column() {
// 1. 顶栏
this.TopBar();
// 2. 消息列表(可滚动)
this.MessageList();
// 3. 输入区(固定底部)
this.InputArea();
}.width('100%').height('100%').backgroundColor('#F5F0EB');
}
4.2 顶栏
Row() {
Text('💬').fontSize(20);
Column({ space: 2 }) {
Text('聊天机器人').fontSize(16).fontColor('#2C3E50');
Text(this.typing ? '正在输入……' : '在线').fontSize(10)
.fontColor(this.typing ? '#27AE60' : '#27AE60');
}.alignItems(HorizontalAlign.Start).margin({ left: 8 });
Blank();
Text('🗑️').fontSize(18).onClick(() => { this.msgs = []; });
}.width('100%').padding({ left: 16, right: 16, top: 10, bottom: 10 }).backgroundColor('#FFF');
顶栏包含三部分:
- 头像 💬 + 名称「聊天机器人」+ 状态「在线/正在输入……」
Blank()占据中间空间,将状态推到右侧- 🗑️ 清空按钮:点击清空所有消息
状态文字:绑定 @State typing,当机器人正在输入时显示绿色「正在输入……」,平时也显示绿色「在线」。
4.3 消息列表
Scroll() {
Column() {
// 空状态(无消息时显示)
if (this.msgs.length === 0) { ... }
// 消息气泡列表
ForEach(this.msgs, (m: Msg) => {
this.MsgBubble(m);
}, (m: Msg) => m.id.toString());
// 正在输入提示
if (this.typing) {
Row() {
Text('🤖 正在输入……').fontSize(12).fontColor('#AAA');
}.width('100%').padding({ left: 16, top: 4 });
}
Blank().height(10);
}.width('100%').padding({ top: 12 });
}.width('100%').backgroundColor('#F5F0EB');
Scroll 是 ArkUI 的可滚动容器,当消息数量超过屏幕高度时自动启用滚动。消息列表从上到下依次是:空状态(条件)、消息气泡(循环)、正在输入提示(条件)、底部留白。
4.4 输入区
Row({ space: 8 }) {
TextInput({ text: this.input, placeholder: '输入消息……' })
.layoutWeight(1).height(40).fontSize(14)
.backgroundColor(Color.White).borderRadius(20).padding({ left: 16 })
.onChange((v: string) => { this.input = v; });
Row() {
Text('➡️').fontSize(20);
}.width(40).height(40).backgroundColor('#6C63FF').borderRadius(20)
.justifyContent(FlexAlign.Center).alignItems(VerticalAlign.Center)
.onClick(() => { this.sendMsg(this.input); });
}.width('100%').padding({ left: 12, right: 12, top: 8, bottom: 12 }).backgroundColor('#FFF');
输入区固定在屏幕底部,包含:
- TextInput:圆角输入框,
layoutWeight(1)占据剩余空间 - 发送按钮:40x40 紫色圆形 + ➡️ 箭头
5. 消息气泡组件
5.1 @Builder MsgBubble
@Builder
MsgBubble(m: Msg) {
Column() {
if (m.from === 'me') {
// 用户消息:右对齐,紫色背景
Row() {
Blank(); // 占满左侧空间,将气泡推到右侧
Column({ space: 4 }) {
Text(m.text).fontSize(14).fontColor('#FFF').lineHeight(20);
Text(m.time).fontSize(9).fontColor('rgba(255,255,255,0.5)').width('100%');
}.maxWidth('75%').padding(12).backgroundColor('#6C63FF').borderRadius(16)
.borderRadius({ topLeft: 16, topRight: 16, bottomLeft: 16, bottomRight: 4 });
}.width('100%').padding({ left: 60, right: 12, top: 4, bottom: 4 });
} else {
// 机器人消息:左对齐,白色背景 + 头像
Row({ space: 6 }) {
Text('🤖').fontSize(20);
Column({ space: 4 }) {
Text(m.text).fontSize(14).fontColor('#2C3E50').lineHeight(20);
Text(m.time).fontSize(9).fontColor('#CCC').width('100%');
}.maxWidth('65%').padding(12).backgroundColor(Color.White).borderRadius(16)
.borderRadius({ topLeft: 4, topRight: 16, bottomLeft: 16, bottomRight: 16 });
Blank();
}.width('100%').padding({ left: 12, right: 60, top: 4, bottom: 4 });
}
}
}
5.2 用户气泡与机器人气泡对比
| 特性 | 用户气泡 (me) | 机器人气泡 (bot) |
|---|---|---|
| 对齐 | Right(右侧) | Left(左侧) |
| 背景色 | 紫色 #6C63FF | 白色 |
| 文字颜色 | 白色 | 深色 #2C3E50 |
| 头像 | 无 | 🤖 emoji |
| 最大宽度 | maxWidth('75%') | maxWidth('65%') |
| 圆角 | 右上 4,其余 16 | 左上 4,其余 16 |
| 内边距 | left: 60, right: 12 | left: 12, right: 60 |
5.3 不规则圆角
borderRadius 支持分别设置四个角:
.borderRadius({ topLeft: 16, topRight: 16, bottomLeft: 16, bottomRight: 4 })
用户气泡:右上角小圆角(bottomRight: 4),模拟聊天气泡的「尾巴」效果。机器人气泡:左上角小圆角(topLeft: 4),同样模拟气泡尾巴。
5.4 气泡对齐原理
// 用户气泡:Blank 在左侧,推到右侧
Row() {
Blank(); // ← 占满左侧空间
Column() { // ← 气泡内容
...
};
}
// 机器人气泡:Blank 在右侧,推到左侧
Row({ space: 6 }) {
Text('🤖'); // ← 头像
Column() { // ← 气泡内容
...
};
Blank(); // ← 占满右侧空间
}
Blank() 是 ArkUI 中的弹性空间组件,会自动占据父容器的剩余空间。将其放在 Row 的开头或结尾,就能将内容推到另一侧。
6. 发送消息与自动回复
6.1 sendMsg 方法
private sendMsg(text: string): void {
const t = text.trim();
if (!t) { return; }
this.input = '';
const now = this.getTime();
this.msgs.push({ id: MSG_ID++, text: t, from: 'me', time: now });
// 自动回复
this.typing = true;
setTimeout(() => {
this.typing = false;
const reply = BOT_REPLIES[Math.floor(Math.random() * BOT_REPLIES.length)];
this.msgs.push({ id: MSG_ID++, text: reply, from: 'bot', time: this.getTime() });
}, 800 + Math.random() * 1200);
}
6.2 执行流程
1. 用户点击发送
↓
2. text.trim() 去空格
↓
3. 空内容检查 → 空则直接返回
↓
4. this.input = '' 清空输入框
↓
5. 创建用户 Msg → push 到 msgs → UI 刷新显示用户气泡
↓
6. this.typing = true → UI 刷新显示「正在输入……」
↓
7. setTimeout 延迟 800~2000ms(随机)
↓
8. this.typing = false → UI 刷新隐藏提示
↓
9. 随机选取回复 → push 到 msgs → UI 刷新显示机器人气泡
6.3 随机延迟
setTimeout(() => { ... }, 800 + Math.random() * 1200);
800 + Math.random() * 1200 生成 800~2000ms 的随机延迟。这模拟了真人输入所需的思考时间,让聊天体验更真实。
6.4 随机回复
const reply = BOT_REPLIES[Math.floor(Math.random() * BOT_REPLIES.length)];
Math.random() 生成 0~1 的随机浮点数,乘以数组长度后 Math.floor 向下取整,得到一个有效的数组索引。
6.5 @State 的自动刷新
this.msgs.push(...) 和 this.typing = true/false 都会触发 @State 的响应式更新。UI 中的 ForEach 重新渲染新的消息气泡,if (this.typing) 控制提示文字的显隐。
7. 快捷话题与空状态
7.1 空状态设计
当 msgs 数组为空时,显示友好的引导界面:
if (this.msgs.length === 0) {
Column({ space: 12 }) {
Blank().height(80);
Text('🤖').fontSize(60);
Text('你好!我是聊天机器人').fontSize(16).fontColor('#555');
Text('随便说点什么,我会回复你 😊').fontSize(13).fontColor('#AAA');
Blank().height(10);
// 快捷话题
...
}.width('100%').alignItems(HorizontalAlign.Center);
}
包含三个元素:
- 机器人头像 🤖(60px 大字号)
- 自我介绍(两行文字)
- 快捷话题按钮(Flex 网格)
7.2 快捷话题
private readonly quickTopics: string[] = [
'你好', '今天天气', '讲个笑话', '你叫什么',
];
Flex({ wrap: FlexWrap.Wrap, justifyContent: FlexAlign.Center }) {
ForEach(this.quickTopics, (t: string) => {
Row() {
Text(t).fontSize(12).fontColor('#6C63FF');
}.padding({ left: 14, right: 14, top: 8, bottom: 8 })
.backgroundColor('#F0EFFF').borderRadius(20).margin(4)
.onClick(() => { this.sendMsg(t); });
});
}.width('100%');
4 个快捷话题以胶囊按钮形式展示在空状态区域。点击任意话题直接调用 sendMsg(),让用户快速体验聊天功能,降低首次使用的心理门槛。
8. 状态管理详解
8.1 @State 变量
@State private msgs: Msg[] = []; // 消息列表(核心数据)
@State private input: string = ''; // 输入框内容
@State private typing: boolean = false; // 机器人输入状态
三个 @State 变量分别驱动 UI 的不同部分:
| 变量 | 驱动 UI | 修改触发点 |
|---|---|---|
msgs | ForEach 渲染所有消息气泡 | sendMsg() 中 push |
input | TextInput 的当前值 | onChange 回调 |
typing | 顶栏状态文字 + 正在输入提示 | sendMsg() 中设为 true,setTimeout 回调中设为 false |
8.2 数组的响应式操作
push 是数组的变异方法,ArkTS 编译器会自动检测 @State 数组的 push 调用并触发 UI 刷新:
// ✅ push 会触发 UI 刷新
this.msgs.push({ id: MSG_ID++, text: t, from: 'me', time: now });
// ✅ 清空数组也会触发刷新
this.msgs = [];
与 React 的 useState 不同——React 需要 setMsgs([...msgs, newMsg]) 创建新数组,而 ArkTS 允许直接调用 push() 等变异方法。
8.3 setTimeout 中的状态修改
setTimeout(() => {
this.typing = false; // ✅ 箭头函数中 this 指向正确
const reply = BOT_REPLIES[Math.floor(Math.random() * BOT_REPLIES.length)];
this.msgs.push({ ... });
}, 800 + Math.random() * 1200);
ArkTS 的箭头函数(() => {})自动捕获外层 this 的上下文。因此在 setTimeout 回调中可以直接访问 this.typing、this.msgs 等实例变量,无需声明 let self = this。
9. 完整源码逐段分析
9.1 导入与接口
import { promptAction } from '@kit.ArkUI';
import { pasteboard } from '@kit.BasicServicesKit';
interface Msg {
id: number;
text: string;
from: string;
time: string;
}
promptAction 和 pasteboard 虽然在本例中未使用(预留扩展),但导入后可以快速添加 Toast 提示和剪贴板功能。Msg 接口定义了聊天消息的基本结构。
9.2 回复池
25 条预设回复定义在 BOT_REPLIES 常量数组中,每条回复都带 emoji 表情,让机器人的回复更生动。
9.3 build() 方法与 MsgBubble
build() 中的 UI 分为三个区域,使用 @Builder MsgBubble 封装消息气泡组件。气泡的左右对齐通过 Blank() 弹性空间实现。
9.4 sendMsg 与 getTime
sendMsg() 是核心业务方法,包含消息发送和自动回复两个阶段。getTime() 格式化当前时间为 HH:mm 格式。
10. 构建与调试
10.1 构建命令
hvigorw assembleHap --no-daemon --mode module -p module=entry
10.2 构建输出
> CompileArkTS... after 7 s 189 ms
> PackageHap... after 805 ms
> BUILD SUCCESSFUL in 19 s 686 ms
10.3 常见问题
| 问题 | 原因 | 解决 |
|---|---|---|
setTimeout 不执行 | 参数格式错误 | 确保第一个参数是箭头函数 () => {} |
| 消息不显示 | ForEach 缺少 keyGenerator | 添加第三个参数 (m: Msg) => m.id.toString() |
| 输入框不更新 | onChange 未修改 @State | 确保 onChange 中执行 this.input = v; |
| 气泡对齐错误 | Blank() 放置位置有误 | 放开头→右对齐,放结尾→左对齐 |
11. 总结与扩展
11.1 技术知识点总览
| 类别 | 知识点 | 应用位置 |
|---|---|---|
| 装饰器 | @Entry | 页面入口 |
| 装饰器 | @Component | ChatApp 组件定义 |
| 装饰器 | @State | msgs / input / typing |
| 装饰器 | @Builder | MsgBubble 消息气泡 |
| 组件 | Scroll | 消息列表可滚动 |
| 组件 | TextInput | 消息输入框 |
| 组件 | Flex | 快捷话题布局 |
| 组件 | ForEach | 消息循环渲染 |
| 响应式 | @State 数组 push | 新增消息即时显示 |
| UI 技巧 | borderRadius 四角分别设置 | 聊天气泡尾巴效果 |
| UI 技巧 | Blank() 弹性空间 | 左右对齐切换 |
| 异步 | setTimeout | 模拟输入延迟 |
| 随机 | Math.random() | 随机回复 + 随机延迟 |
11.2 交互体验设计
聊天机器人 App 虽然在技术上只有 168 行代码,但在交互体验上做了多个细节设计:
1. 输入延迟:800 + Math.random() * 1200 ms 的随机延迟,模拟真人打字速度。
2. 正在输入提示:延迟期间显示「🤖 正在输入……」状态,让用户知道机器人正在响应。
3. 空状态引导:首次打开显示自我介绍 + 快捷话题,降低用户尝试门槛。
4. 不规则气泡圆角:气泡的「尾巴」圆角让聊天气泡看起来更自然。
5. 时间戳:每条消息显示发送时间,方便追溯聊天记录。
11.3 扩展方向
智能回复增强:
- 接入大模型 API(如华为盘古大模型),实现真正的智能对话
- 基于关键字匹配的智能回复(输入"天气"返回天气预报)
- 上下文记忆,多轮对话连贯性
聊天功能完善:
- 消息已读/未读状态
- 长按消息展示操作菜单(复制/删除/转发)
- 图片/语音消息支持
- 多人群聊界面
UI 增强:
- 聊天气泡动画(淡入/滑动)
- 暗色模式
- 自定义主题颜色
- 消息搜索功能
数据持久化:
- 使用
@ohos.data.preferences保存聊天记录 - 聊天记录导出/导入
- 多会话管理
11.4 写在最后
168 行代码,一个完整的聊天机器人。从空状态的友好引导,到发送消息后的即时反馈,再到「正在输入……」的延迟提示——每个交互细节都展示了 ArkTS 声明式 UI 在即时通讯类应用中的开发效率。
聊天应用是所有移动端开发者必须掌握的技能之一。通过本文的学习,你不仅掌握了 @Builder 气泡组件、Blank() 对齐技巧、setTimeout 异步延迟等技术点,更重要的是理解了「状态驱动 UI」这一 ArkTS 核心设计理念。
本文所有代码基于 HarmonyOS NEXT 6.1.1(API 24)编写。源码文件:entry/src/main/ets/pages/ChatApp.ets(168 行)。
更多推荐



所有评论(0)