HarmonyOS NEXT ArkTS 实战:构建「聊天机器人」App 完整教程在这里插入图片描述

在这里插入图片描述
在这里插入图片描述


目录

  1. 应用概览
  2. 项目架构设计
  3. 数据模型
  4. 聊天界面布局
  5. 消息气泡组件
  6. 发送消息与自动回复
  7. 快捷话题与空状态
  8. 状态管理详解
  9. 完整源码逐段分析
  10. 构建与调试
  11. 总结与扩展

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');

顶栏包含三部分:

  1. 头像 💬 + 名称「聊天机器人」+ 状态「在线/正在输入……」
  2. Blank() 占据中间空间,将状态推到右侧
  3. 🗑️ 清空按钮:点击清空所有消息

状态文字:绑定 @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');

输入区固定在屏幕底部,包含:

  1. TextInput:圆角输入框,layoutWeight(1) 占据剩余空间
  2. 发送按钮: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: 12left: 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);
}

包含三个元素:

  1. 机器人头像 🤖(60px 大字号)
  2. 自我介绍(两行文字)
  3. 快捷话题按钮(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修改触发点
msgsForEach 渲染所有消息气泡sendMsg() 中 push
inputTextInput 的当前值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.typingthis.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;
}

promptActionpasteboard 虽然在本例中未使用(预留扩展),但导入后可以快速添加 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页面入口
装饰器@ComponentChatApp 组件定义
装饰器@Statemsgs / input / typing
装饰器@BuilderMsgBubble 消息气泡
组件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 行)。

Logo

讨论HarmonyOS开发技术,专注于API与组件、DevEco Studio、测试、元服务和应用上架分发等。

更多推荐