Flipper Zero 固件 JS SDK:gui/dialog 对话框视图的完整实战指南
2026/9/14 15:01:54 网站建设 项目流程

Flipper Zero 固件 JS SDK:gui/dialog 对话框视图的完整实战指南

【免费下载链接】flipperzero-firmwareFlipper Zero firmware source code项目地址: https://gitcode.com/GitHub_Trending/fl/flipperzero-firmware

本篇基于 Flipper Zero 固件仓库中的 JS Dialog 视图文档 展开,系统讲解 JS SDK 中gui/dialog模块的模块加载规则、视图属性(Props)与事件(Events)契约、可直接运行的示例脚本,并结合 js_app 的 C 语言绑定实现 剖析底层属性赋值、消息队列到事件循环的完整数据链路。读完后,你能够在 Flipper Zero 的 JS 应用中快速搭建“文本 + 最多三个按钮”的交互对话框,并理解其背后DialogEx视图如何被包装成 JS 对象。

一、模块定位与导入顺序

gui/dialog是 Flipper Zero JS SDK 内置的 GUI 视图之一,用于展示一个带最多三个按钮选项的对话框。文档给出的标准导入方式是:

let eventLoop = require("event_loop"); let gui = require("gui"); let dialogView = require("gui/dialog");

文档特别强调了导入顺序的硬性约束:gui/dialog模块依赖gui模块,而gui又依赖event_loop,因此三者必须按上述顺序导入。从实现上看,这一顺序并非形式要求——对话框的按钮点击事件正是通过event_loop的事件契约(Contract)机制分发到 JS 回调的,若事件循环模块未先行就绪,input事件对象便无从挂接。

二、视图属性(View props)

对话框视图支持以下五个字符串属性,全部通过makeWith()初始化或在运行期用set()动态修改:

属性类型说明
headerstring显示在屏幕顶部、以粗体呈现的标题文本。
textstring显示在屏幕中间区域的主文本。
leftstring左按钮的文本。若未设置,左按钮不显示。
centerstring中间按钮的文本。若未设置,中间按钮不显示。
rightstring右按钮的文本。若未设置,右按钮不显示。

结合 C 语言绑定源码 可以进一步确认每个属性在固件侧的实际落点:

  • header属性经header_assign回调交给底层对话框的标题设置接口,固定绘制在屏幕顶部居中位置(水平居中、顶部对齐,区域宽度 64 像素);
  • text属性经text_assign回调交给主文本设置接口,绘制在屏幕中部(水平与垂直均居中,文本区域宽 64、纵向起点 32);
  • left/center/right三个属性分别对应左、中、右按钮的文本设置接口。

源码中这五个属性在视图描述符里被统一声明为字符串类型(JsViewPropTypeString),数量prop_cnt = 5,与上表完全一一对应。这解释了文档表格中“未设置则按钮不显示”的行为:只要不调用set()makeWith()传入对应属性,底层视图就不会绘制该按钮,用户在物理按键上也就不会收到该方向的点击反馈。

三、视图事件(View events)

事件项类型说明
inputstring当用户按下三个按钮中的任意一个时触发。事件参数为"left""center""right"三者之一,取决于被按下的按钮。

这个字符串事件值的来源在绑定层 input_transformer 函数 中:底层对话框返回的枚举结果(左/中/右)在此被逐一转换为"left""center""right"三个 JS 字符串,若收到无法识别的结果则会直接触发崩溃保护(furi_crash)。

事件的分发链路是理解整个模块的关键,其完整流程如下:

  1. 用户在设备按下对应方向键,底层对话框视图产生结果回调;
  2. 绑定层的 input_callback 将该结果放入一个长度为 2 的FuriMessageQueue
  3. 事件循环在队列上有新消息时(FuriEventLoopEventIn事件),调用input_transformer完成枚举到字符串的转换;
  4. 转换后的字符串作为事件参数交给 JS 侧通过eventLoop.subscribe(views.dialog.input, ...)注册的回调函数。

正是这条“回调 → 消息队列 → 事件循环 → JS 订阅者”的链路,要求 JS 脚本必须先加载event_loop模块——input事件对象本身是在视图创建时(ctx_make)注入到视图对象上的,见 ctx_make 实现 中通过mjs_set(mjs, view_obj, "input", ...)完成的挂载。

四、完整可运行的示例

官方文档指出示例可参考gui.js脚本。仓库中的 gui.js 示例 确实将 dialog 作为多处交互的落点,其核心用法摘录如下:

创建视图(初始不设置任何属性,后续动态填充):

let views = { // ... helloDialog: dialogView.make(), };

在文本输入确认后,动态设置属性并切换到对话框:

eventLoop.subscribe(views.keyboard.input, function (_sub, name, gui, views) { views.keyboard.set("defaultText", name); // 记住下次使用 views.helloDialog.set("text", "Hi " + name + "! :)"); views.helloDialog.set("center", "Hi Flipper! :)"); gui.viewDispatcher.switchTo(views.helloDialog); }, gui, views);

订阅input事件,在用户按下中间按钮后返回演示选择页:

// 问候对话框之后返回 eventLoop.subscribe(views.helloDialog.input, function (_sub, button, gui, views) { if (button === "center") gui.viewDispatcher.switchTo(views.demos); }, gui, views);

这段代码覆盖了 dialog 的全部典型操作面:make()创建、set()动态修改textcenter属性、switchTo()切换显示、input事件按按钮值分支处理。值得注意的模式是:先设置属性、再切换视图——属性的修改随时可以进行,但只有当视图成为viewDispatcher当前视图时,用户在屏幕上才能看到结果并与其交互。

另一个更简洁的独立示例是 interactive.js,它在创建视图时用makeWith()一步到位地传入全部初始属性:

dialog: dialog.makeWith({ header: "Interactive Console", text: "Press OK to Start", center: "Run Some JS" }),

然后订阅input事件,仅在按下中间按钮时跳转到代码输入视图:

eventLoop.subscribe(views.dialog.input, function (_sub, button, gui, views) { if (button === "center") { gui.viewDispatcher.switchTo(views.textInput); } }, gui, views);

由于该示例只设置了center属性,左、右按钮均不显示,屏幕上只有一个可点击的“Run Some JS”按钮——直观验证了第二节“未设置则按钮不显示”的规则。仓库中的 badusb_demo.js 演示脚本也采用了同样的makeWith+input订阅模式作为交互入口。

五、类型定义与 SDK 工程化支持

对于使用 TypeScript 工具链(如@flipperdevices/fz-sdk)的开发者,仓库提供了 dialog.d.ts 类型声明,它把文档表格中的契约固化为类型:

type Props = { header: string, text: string, left: string, center: string, right: string, } type Child = never; declare class Dialog extends View<Props, Child> { input: Contract<"left" | "center" | "right">; }

两个细节值得关注:

  • input被声明为Contract<"left" | "center" | "right">类型,用字面量联合类型精确锁定了事件参数的取值范围,与文档中的事件表格严格一致,可在 TS 侧做穷举检查;
  • Child = never表明 dialog 视图不接受子元素(区别于可传入元素数组的 widget 类视图),所有显示内容只能通过五个字符串属性表达。

该类型声明由create-fz-app项目模板直接引用(见 fz-sdk 的 dialog 模块),保证脚手架项目开箱即用。

六、绑定层实现细节补充

从源码结构看,gui/dialog模块的 C 侧实现由 js_app 应用清单 中的编译条目sources=["modules/js_gui/dialog.c"]注册进固件,其 JsViewDescriptor 定义了 JS 对象与底层DialogEx视图之间的全部桥梁:

  • alloc/free/get_view分别对应底层对话框视图的分配、释放与句柄获取;
  • custom_make(即ctx_make)在make()/makeWith()调用时创建上下文:分配消息队列、构造事件契约、把input事件对象注入 JS 视图对象,并注册结果回调;
  • custom_destroy(即ctx_destroy)负责在视图销毁时解除事件循环订阅并释放队列与上下文内存。

由此可以得到几条实用的边界结论:

  1. 对话框的文本容量受屏幕宽度约束,底层布局参数(宽 64、居中)固定,超长文本的行为由底层文本渲染决定,建议将text控制在两三行以内;
  2. 由于消息队列长度仅为 2,input事件的消费速度由事件循环的调度决定,回调中应尽快完成逻辑处理或切换视图;
  3. 视图不显示子元素,若需要富文本排版、图标或复杂布局,应改用gui/widget等支持元素数组的视图,dialog 只适合“标题 + 说明 + 少量按钮”的轻量交互场景(确认、取消、选择)。

七、小结

gui/dialog是 Flipper Zero JS SDK 中最轻量的交互视图:五个字符串属性决定显示内容与按钮集合,一个字符串类型的input事件回报按钮点击。文档给出的导入顺序、属性表、事件表在 C 绑定源码 与 TS 类型声明 中均可逐条印证;gui.js 与 interactive.js 两个官方示例则提供了makemakeWith两种创建路径的完整可复制写法,是动手实践时的最佳起点。

【免费下载链接】flipperzero-firmwareFlipper Zero firmware source code项目地址: https://gitcode.com/GitHub_Trending/fl/flipperzero-firmware

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询