OpenHarmony 小鸿 AI 开发实战 07:用 LVGL 构建 240×240 语音伙伴界面
240×240 小屏不是把手机页面缩小。当前小鸿界面要同时容纳状态栏、语音焦点、状态提示、对话文本、音量反馈和配网/升级页面还要在 WS63 的 SRAM 与 LiteOS-M 任务模型下稳定刷新。界面代码因此被拆成布局常量、对象创建、视觉状态、事件消费和长文本分页五个部分而不是在一个循环里不断清屏重画。本文依据当前lcd_st7789_driver.h、lvgl_ui_layout.h/.c、lvgl_task.c和显示事件枚举整理。所有尺寸、缓冲区大小、颜色、页面时长和状态文案都来自实际源码。最新 UI 固件包已存在并记录哈希但本轮没有重新烧录后拍摄实机屏幕所以文中使用的是根据代码确定性渲染的结构图不把设计示意图冒充设备照片源码验证与实机视觉验收仍然分开。显示尺寸由 ST7789 驱动向布局层传递面板驱动头文件定义 240×240lvgl_ui_layout.h再把LCD_PANEL_PIXEL_X/Y映射成DISP_WIDTH/HEIGHT。如果驱动没有给出尺寸预处理直接报错不允许布局悄悄使用另一个默认值。这样布局常量和 LVGL display 创建共享同一尺寸来源。#if defined(LCD_PANEL_PIXEL_X) #define DISP_WIDTH LCD_PANEL_PIXEL_X #else #error LCD_PANEL_PIXEL_X unknown #endif #if defined(LCD_PANEL_PIXEL_Y) #define DISP_HEIGHT LCD_PANEL_PIXEL_Y #else #error LCD_PANEL_PIXEL_Y unknown #endif当前 UI 留出 8 像素安全边界状态栏从 y4 开始高 22焦点环位于 64、36尺寸 112中心核心为 90×90。提示文字位于 y149对话摘要从 y179 开始。这些位置围绕 240 像素高度手工组织目标是优先让用户看清“设备现在在做什么”。常态页面由状态栏、焦点区和两段文字组成常态布局上方是 Wi-Fi、音量、亮度和电池状态中间 112×112 区域包含 12 段环形状态点、90×90 核心、咕咕嘎嘎图像或 Emoji以及监听时使用的五根波形条下方两段文字分别承担状态提示和操作/对话摘要。#define UI_STATUS_POS_Y (4) #define UI_STATUS_HEIGHT (22) #define UI_FOCUS_POS_X (64) #define UI_FOCUS_POS_Y (36) #define UI_FOCUS_SIZE (112) #define UI_FOCUS_CORE_SIZE (90) #define UI_PROMPT_POS_Y (149) #define UI_CHAT_TXT_POS_Y (179) #define UI_CHAT_TXT_HEIGHT (49)这种布局不会在回答长文本时继续强行保留大焦点环。进入回答态后中心视觉让位给阅读区域只保留顶部状态和“正在回答”提示。小屏界面的优先级必须随任务改变而不是让所有组件永久同时可见。对象只创建一次状态变化通过隐藏与样式完成disp_create_ui在 LVGL 任务初始化时创建状态栏、焦点环、12 个环段、核心区、图像、5 个波形条、互动文字、回答页装饰、全屏文字和音量覆盖层。运行时不为每个 Agent 状态重复 new 一套对象而是使用LV_OBJ_FLAG_HIDDEN切换可见性并更新文本、颜色、尺寸。status_bar_obj lv_label_create(lv_scr_act()); s_status_divider_obj lv_obj_create(lv_scr_act()); s_focus_ring_obj lv_obj_create(lv_scr_act()); for (uint8_t i 0U; i ASSISTANT_RING_SEGMENT_COUNT; i) { s_focus_ring_segments[i] lv_obj_create(s_focus_ring_obj); } s_focus_core_obj lv_obj_create(lv_scr_act()); s_penguin_image_obj lv_image_create(s_focus_core_obj); for (uint8_t i 0U; i 5U; i) { s_wave_bars[i] lv_obj_create(s_focus_core_obj); }固定对象树减少频繁分配和销毁也让 LVGL 样式与定时器更容易管理。创建完成后代码默认隐藏互动区和焦点区先显示全屏启动文字“咕咕嘎嘎 / 正在醒来”待系统事件到达后再切入常态页面。五种视觉模式与 Agent 状态对齐当前视觉枚举包含空闲、连接、倾听、思考和回答五态。它们不是网络协议状态的完整复制而是 UI 需要表达的最小集合。监听态和思考态都可能来自AGENT_STATE_LISTENING再通过agent_is_waiting_response()区分语音采集尚在进行还是语音已上传、正在等待服务端。typedef enum { ASSISTANT_VISUAL_IDLE 0, ASSISTANT_VISUAL_CONNECTING, ASSISTANT_VISUAL_LISTENING, ASSISTANT_VISUAL_THINKING, ASSISTANT_VISUAL_SPEAKING, ASSISTANT_VISUAL_INVALID } assistant_visual_mode_t;每种模式设置不同的焦点背景、边框和前景色。空闲使用暖黄色连接偏紫倾听使用青色思考使用琥珀色回答使用绿色。12 段焦点环可以固定点亮或旋转五根波形条则按预设高度序列动画帮助用户不读文字也能分辨设备状态。状态文案来自真实分支而不是设计稿显示任务处理eDisp_Prompt_Update时读取 Agent 状态。空闲文案为“咕咕嘎嘎 / 按中键和我说话长按5秒进入配网”连接态显示“正在连接 / 网络连接中请稍候”监听态显示“我在听 / 请开始说话”等待返回时显示“让我想一想 / 语音已上传请稍候”回答态提示“正在回答”。assistant_visual_set_mode(waiting_response ? ASSISTANT_VISUAL_THINKING : ASSISTANT_VISUAL_LISTENING); lv_label_set_text( interact_txt_prompt, waiting_response ? 让我想一想 : 我在听); lv_label_set_text( interact_txt_chat, waiting_response ? 语音已上传请稍候 : 请开始说话);这段逻辑解决了“已经说完但界面还显示我在听”的语义错误。状态文案与颜色必须由同一个状态判断驱动否则用户会看到环在思考、文字却提示继续说话。OpenHarmony 构建只使用 16 行局部缓冲240×240 RGB565 全帧缓冲需要 115,200 字节。当前 OpenHarmony 路径把局部刷新缓冲设为 16 行即240 × 16 × 2 7,680字节非 OpenHarmony 分支使用 80 行、38,400 字节。代码在注释中明确说明缓冲越大刷新可能更快但 SRAM 压力也更高。#if SUPPORT_OHOS #define LVGL_PARTIAL_BUF_LINES (16) #else #define LVGL_PARTIAL_BUF_LINES (80) #endif static uint8_t disp_buffer[ DISP_WIDTH * LVGL_PARTIAL_BUF_LINES * 2];LVGL display 使用LV_DISPLAY_RENDER_MODE_PARTIAL注册该缓冲。局部缓冲不是“屏幕只有 16 行”而是 LVGL 分块绘制后通过 flush 回调送到 ST7789。文章给出精确字节数避免把帧缓冲、对象内存和外部 Flash 混在一起。LVGL tick 与对象更新必须留在显示任务当前代码专门注明不能在硬件定时器 ISR 中调用lv_tick_inc()否则会与LvglTask并发并破坏 LVGL 内部状态。实际循环在同一任务中根据内核 tick 推进 LVGL再调用lv_timer_handler()然后以它返回的下一定时器间隔等待显示消息。等待时间被限制在 120 ms。过大时动画和滚动发涩过小时任务空转、发热增加。显示事件通过g_disp_event_qid进入同一线程调用disp_update_ui因此其他任务只发枚举不直接操作 LVGL 对象。lv_tick_inc(xh_lvgl_elapsed_ms_since(lv_prev_kernel_tick)); uint32_t next_ms lv_timer_handler(); uint32_t qwait next_ms; if (qwait 1U) { qwait 1U; } if (qwait 20U) { qwait 20U; } ret osMessageQueueGet( g_disp_event_qid, (void *)msg_recv, NULL, qwait);回答页用 UTF-8 安全分页而不是按字节硬切动态回答先写入 512 字节 pending buffer。单页最多复制 144 字节页面推进步长为 108 字节相邻页因此保留一部分上下文每页停留 3.2 秒。这里的 144 和 108 是字节数不等于固定中文字数。UTF-8 中文通常占 3 字节Emoji 可能占 4 字节所以切页必须回退到字符起点。#define DISP_LVGL_TEXT_PENDING_MAX (512) #define DISP_SHOW_TEXT_LINE_LEN (108) #define DISP_SHOW_TEXT_MAX_LEN (144) #define DISP_SHOW_TEXT_DELAY_MS (3200)utf8_safe_rollback从目标位置向前跳过所有10xxxxxxcontinuation byte找到一个合法字符起点。第一页显示后创建 LVGL timer后续每次向前移动 108 字节再安全截取最多 144 字节并更新右下角当前页/总页数。最后一页还会完整停留一个周期再清理播放状态避免回答刚显示就返回首页。回答页把 144 像素高度让给正文回答布局的正文从 x16、y64 开始宽度为DISP_WIDTH - 28高度 144左侧有 3×144 的绿色强调条页码放在 y213。相较常态页 49 像素的摘要区回答页可以显示约五到六行 18 px 中文。顶部仍保留状态栏用户不会因为进入长文本页面失去网络、电量等信息。内置lv_font_Chinese_18_UI是兜底字体若 LittleFS 中的外部font.bin可用互动文字可切到流式字体。完整中文字库下载与替换属于第 08 篇范围本文只确认当前 UI 对字体缺失有回退路径不声称所有 Unicode 字形都在内置字体中。音量反馈使用覆盖层不挤压主状态收到eDisp_Volume_Update后显示任务先刷新状态栏再显示位于屏幕下部的音量覆盖层。覆盖层包含音量图标、116×11 的轨道、按百分比计算宽度的填充条和数值。它由定时器自动恢复原界面不需要重建整个对象树。填充最大宽度为 112当前值按112 × volume / 100计算音量为零时隐藏填充条。这个细节比只改状态栏图标更容易给用户及时反馈也不会永久占用回答区。从源码到实机还需要三类验收源码层已经确认 240×240 尺寸、对象层次、五种视觉模式、16 行局部缓冲、单任务 tick、120 ms 等待、512 字节 pending buffer、144/108 字节分页和 3.2 秒停留。最新 UI 包000_BURN_THIS_42_GUGUGAGA_DETAILED_UI_WS63_20260723_2040.fwpkg的大小和 SHA-256 也已在第 04 篇记录。但界面验收还应分三类静态布局检查边缘裁切、字体和页码动态检查焦点环、波形、音量覆盖层和分页节奏长时间运行检查任务占用、发热、队列堵塞和 LVGL fault。本轮没有重新烧录和拍摄设备因此本文结论是“当前 240×240 UI 实现已按源码复核”不是“今天完成了新包的全部实机视觉验收”。

相关新闻

Rust 的安全编码在企业合规中的价值:CWE Top 25 在 Rust 中的天然消解分析

Rust 的安全编码在企业合规中的价值:CWE Top 25 在 Rust 中的天然消解分析

Rust 的安全编码在企业合规中的价值:CWE Top 25 在 Rust 中的天然消解分析 一、合规审计中的安全编码困境 企业合规审计中,代码安全问题被量化为 CWE(Common Weakness Enumeration)弱点的检出数量。CWE Top 25 汇集了当前最危险的…

2026/7/24 18:43:38 阅读更多 →
Kratos(SneakyLog)AiTM 钓鱼套件技术机理、黑产运营与全域防御研究

Kratos(SneakyLog)AiTM 钓鱼套件技术机理、黑产运营与全域防御研究

摘要 针对 2026 年欧美联合执法行动关停的 Kratos(微软威胁情报命名为 SneakyLog)钓鱼即服务套件展开系统性实证研究。该工具依托对抗中间人(AiTM)反向代理架构实现 Microsoft 365 会话 Cookie 劫持,可完整绕过多因素认…

2026/7/24 18:43:38 阅读更多 →
Unity过场动画制作:Timeline与Cinemachine高效电影感运镜指南

Unity过场动画制作:Timeline与Cinemachine高效电影感运镜指南

1. 项目概述:告别手K动画的繁琐时代 如果你还在用Animator Controller一个状态一个状态地手K关键帧来拼接过场动画,或者用脚本笨拙地控制Camera的Transform和Rotation,那真的有点“原始人钻木取火”的味道了。我经历过那个阶段,为…

2026/7/24 18:42:37 阅读更多 →

最新新闻

ELF文件与库的原理

ELF文件与库的原理

库的制作和原理 1 ELF文件 ELF文件主要包含以下4种: 可重定位文件(xxx.o) 可执行文件 共享目标文件(xxx.so) 内核转储ELF的文件构成: 1.ELF header:用于定位文件的其他部分 2.Program header table:列举了所有有效段及其属性&…

2026/7/24 19:56:00 阅读更多 →
抖音视频下载终极指南:douyin-downloader批量去水印工具完全教程

抖音视频下载终极指南:douyin-downloader批量去水印工具完全教程

抖音视频下载终极指南:douyin-downloader批量去水印工具完全教程 【免费下载链接】douyin-downloader A practical Douyin downloader for both single-item and profile batch downloads, with progress display, retries, SQLite deduplication, and browser fall…

2026/7/24 19:56:00 阅读更多 →
环境土壤物理Hydrus2D/3D模型实践技术应用

环境土壤物理Hydrus2D/3D模型实践技术应用

查看原文>>>https://mp.weixin.qq.com/s/zmXj5_HLNEdpIvyi0yE0nA 前言 HYDRUS是基于Windows系统界面开发的环境土壤物理模拟软件,是用于模拟一维和多维变饱和多孔介质的水分运动、溶质(污染物等)运移、根系吸水和溶质吸收、以及热…

2026/7/24 19:56:00 阅读更多 →
C++词法分析器实现:从有限自动机到工程化实践

C++词法分析器实现:从有限自动机到工程化实践

1. 项目概述:从“字符串”到“单词”的翻译官如果你刚开始接触编译原理,可能会觉得这个词法分析听起来特别高大上,甚至有点抽象。其实,你可以把它想象成一个精通多国语言的翻译官,只不过它翻译的对象不是人类语言&…

2026/7/24 19:56:00 阅读更多 →
绝区零一条龙:免费开源的全自动游戏助手完整使用指南

绝区零一条龙:免费开源的全自动游戏助手完整使用指南

绝区零一条龙:免费开源的全自动游戏助手完整使用指南 【免费下载链接】ZenlessZoneZero-OneDragon 绝区零 一条龙 | 全自动 | 自动闪避 | 自动每日 | 自动空洞 | 支持手柄 项目地址: https://gitcode.com/gh_mirrors/ze/ZenlessZoneZero-OneDragon 绝区零一条…

2026/7/24 19:56:00 阅读更多 →
【20年ML系统老兵手记】:为什么你训出的模型一部署就崩?训练/推理数据流、内存模型、精度路径的3维撕裂分析

【20年ML系统老兵手记】:为什么你训出的模型一部署就崩?训练/推理数据流、内存模型、精度路径的3维撕裂分析

更多请点击: https://kaifayun.com 第一章:【20年ML系统老兵手记】:为什么你训出的模型一部署就崩?训练/推理数据流、内存模型、精度路径的3维撕裂分析 训练准确率98%的模型,在生产环境里返回NaN、OOM崩溃、延迟飙升1…

2026/7/24 19:55:00 阅读更多 →

日新闻

用Highcharts 创建可拖拽三维散点立方体3D图表

用Highcharts 创建可拖拽三维散点立方体3D图表

该案例基于Highcharts scatter3d 三维散点图实现空间立方体散点可视化,核心特色:三维 X/Y/Z 三轴空间,所有散点分布在 0~10 立方体空间内;散点使用径向渐变实现立体 3D 圆球质感;支持鼠标 / 触屏拖拽画布,…

2026/7/24 0:00:29 阅读更多 →
AppCertDlls:进程创建路径上的 DLL 入口

AppCertDlls:进程创建路径上的 DLL 入口

AppCertDlls:进程创建路径上的 DLL 入口 AppCertDlls 位于 HKLM\System\CurrentControlSet\Control\Session Manager\AppCertDlls。本文的程序功能是只读列出这个键在 64 位和 32 位注册表视图中的全部值,并显示每条值的来源、名称、类型和可安全显示的数…

2026/7/24 0:00:29 阅读更多 →
我的编程之路:第一篇博客

我的编程之路:第一篇博客

大家好,我是一名编程初学者,同时这也是我编程学习之路上的第一篇博客。在这里,我想要向大家介绍我的一些想法和规划。a.自我介绍我是一个刚刚接触编程的新手,目前在学习c语言,我对编程世界充满了强烈的好奇。当然&…

2026/7/24 0:00:29 阅读更多 →

周新闻

Go语言静态资源打包方案对比与实践指南

Go语言静态资源打包方案对比与实践指南

1. 项目背景与核心需求在Go语言开发中,我们经常需要处理静态资源文件的打包问题。无论是Web应用的模板文件、前端资源,还是配置文件、证书等,都需要随程序一起分发。传统做法是将这些文件与编译后的二进制文件放在同一目录下,但这…

2026/7/24 3:59:20 阅读更多 →
Go语言实现高性能LDAP认证服务的架构与实践

Go语言实现高性能LDAP认证服务的架构与实践

1. 项目背景与核心价值LDAP(轻量级目录访问协议)作为企业级身份认证的黄金标准,已经服务了超过80%的财富500强公司。我在金融科技领域实施统一认证体系时,发现传统Java方案存在启动慢、内存占用高等痛点。而Go语言凭借其协程并发模…

2026/7/24 1:23:39 阅读更多 →
【AI面试官实战指南】:用ChatGPT模拟10类高频技术岗面试,3天提升应答精准度92%

【AI面试官实战指南】:用ChatGPT模拟10类高频技术岗面试,3天提升应答精准度92%

更多请点击: https://intelliparadigm.com 第一章:AI面试官实战指南的核心价值与适用场景 AI面试官并非替代人类HR的“黑箱工具”,而是以可解释、可审计、可迭代的方式,赋能招聘全链路的关键基础设施。其核心价值在于将主观经验沉…

2026/7/24 18:52:18 阅读更多 →

月新闻