资讯详情

Momentum-Firmware 日期时间输入控件 DateTimeInput 实战:从 API 到完整示例应用

📅 2026/9/16 20:12:48 | 华诺云谱 👁 阅读
Momentum-Firmware 日期时间输入控件 DateTimeInput 实战:从 API 到完整示例应用
Momentum-Firmware 日期时间输入控件 DateTimeInput 实战从 API 到完整示例应用【免费下载链接】Momentum-Firmware Feature-rich, stable and customizable Flipper Firmware项目地址: https://gitcode.com/GitHub_Trending/mo/Momentum-Firmware本指南以 example_date_time_input 示例应用为核心系统讲解 Momentum-Firmware 中DateTimeInput日期/时间输入视图的 API 用法、回调机制、字段编辑控制原理并结合仓库内源码GUI 模块实现、RTC 支持、场景管理器集成给出可复制的实战代码路径。读完本文你将掌握如何在任意应用中加入一个支持按需定制编辑字段、带合法性校验回调的日期时间选择界面并理解其底层绘制与按键交互逻辑。一、DateTimeInput 是什么DateTimeInput是 GUI 服务提供的通用视图模块模块头文件它以两行六列的布局让用户调整日期年/月/日和/或时间时/分/秒。示例应用 ReadMe.md 对它的定位只有一句话Simple view that allows the user to adjust a date and/or time.它适用于需要用户设定或校准时间戳的场景例如闹钟设置、预约时间、日志时间戳修正等。该控件以“视图模块”的形式封装在applications/services/gui/modules/date_time_input.c中任何应用都可以通过date_time_input_alloc()创建并嵌入自己的ViewDispatcher。二、核心设计原则一个 DateTime两组回调从 ReadMe.md 的 General principle 一节可以提炼出该控件的两大设计要点二者在源码中均有直接对应实现回调双通道值变更回调changed_callback用户每修改一个字段时触发适合做应用层面的边界检查或校验例如限制时间必须落在某个业务窗口内完成回调done_callback用户在编辑状态按下返回键时触发表示整个输入流程结束。对应源码中 date_time_input.h 定义的两个回调类型/** callback that is executed on value change */ typedef void (*DateTimeChangedCallback)(void* context); /** callback that is executed on back button press */ typedef void (*DateTimeDoneCallback)(void* context);DateTime 对象双向复用调用方传入的DateTime*指针既作为控件的初始值控件打开时显示的当前值又作为结果存储区用户编辑直接写入该结构体。因此读取结果无需额外拷贝输入场景退出后直接访问原结构体即可。这种传入即传出的设计在 date_time_input_set_result_callback 的实现中体现得很直接——它只是把指针保存到视图模型里后续所有编辑操作都通过该指针就地修改DateTime。三、编辑字段控制date_time_input_set_editable_fieldsReadMe 明确说明了字段编辑控制的规则The fields which the user is allowed to edit can be defined usingdate_time_input_set_editable_fields(). Disabled fields are shown but arent able to be selected and dont have an outer box. If all fields are disabled, the view is read-only and no cursor will be shown.即被禁用的字段依然显示数值但无法被选中、不绘制外框如果全部字段都被禁用视图进入只读模式不显示任何光标。API 签名date_time_input.h按顺序接收六个布尔值void date_time_input_set_editable_fields( DateTimeInput* date_time_input, bool year, bool month, bool day, bool hour, bool minute, bool second);各参数含义与默认值如下参数含义内部默认值可选范围year是否允许编辑年true1980–2099month是否允许编辑月true1–12day是否允许编辑日true1–31自动按月份矫正hour是否允许编辑时true0–23循环minute是否允许编辑分true0–59循环second是否允许编辑秒true0–59循环默认值来自 date_time_input_reset_model_input_data其中editable六个字段全部初始化为true取值范围来自date_time_input_date_callback与date_time_input_time_callback的边界逻辑见下文交互与边界。底层实现上该函数在更新完六个标志位后会自动把光标定位到第一个可编辑字段date_time_input.c从row0, column0开始借助is_allowed_to_edit()逐列、逐行轮询直到找到一个可编辑单元若整表都不可编辑则放弃对应 ReadMe 所说的只读、无光标。四、示例应用源码拆解示例应用位于 applications/examples/example_date_time_input由主程序、两个场景和场景配置组成。4.1 应用清单 application.famapplication.fam 定义了这是一个外部应用FAPApp( appidexample_date_time_input, nameExample: Date/Time Input, apptypeFlipperAppType.EXTERNAL, entry_pointexample_date_time_input, requires[gui], stack_size1 * 1024, fap_categoryExamples, )关键字段解读apptypeFlipperAppType.EXTERNAL编译为可独立分发的.fap插件通过应用加载器运行entry_pointexample_date_time_input对应 example_date_time_input.c 中的入口函数int32_t example_date_time_input(void* p)requires[gui]声明依赖 GUI 记录服务因为控件基于ViewDispatcherstack_size1 * 1024为应用线程分配 1 KiB 栈空间。4.2 应用骨架与生命周期主程序 example_date_time_input.c 展示了一个标准的 ViewDispatcher 应用骨架example_date_time_input_alloc()中通过furi_record_open(RECORD_GUI)打开 GUI 服务创建view_dispatcher_alloc()与scene_manager_alloc()并注册自定义事件回调和导航返回键回调date_time_input_alloc()创建输入控件dialog_ex_alloc()创建确认对话框二者视图都通过view_dispatcher_add_view()注册用furi_hal_rtc_get_datetime(app-date_time)读取当前 RTC 时间作为控件的初始值该 API 实现在 targets/f7/furi_hal/furi_hal_rtc.cview_dispatcher_attach_to_gui(..., ViewDispatcherTypeFullscreen)以全屏方式挂载到 GUI首个场景设为ExampleDateTimeInputSceneShowDateTime随后进入view_dispatcher_run()事件循环退出时对称地view_dispatcher_remove_view()、释放控件并furi_record_close(RECORD_GUI)。4.3 场景一展示当前时间show_date_timeexample_date_time_input_scene_show_date_time.c 用DialogEx展示当前编辑结果并提供三个按钮决定编辑哪些字段左键Date仅编辑日期edit_date true, edit_time false右键Time仅编辑时间edit_date false, edit_time true中键Both日期时间都可编辑。值得注意的细节该场景在格式化时间时考虑了12/24 小时制——通过furi_hal_rtc_get_locale_timeformat()实现见 furi_hal_rtc.c判断当前系统时制12 小时制下将hour % 12并附加 AM/PM 后缀避免出现 00:xx 这类显示问题。选择后通过scene_manager_next_scene()切换到输入场景。4.4 场景二日期时间输入input_date_timeexample_date_time_input_scene_input_date_time.c 的on_enter演示了两个核心 API 的标准用法date_time_input_set_result_callback( date_time_input, NULL, // 无需校验时传 NULL example_date_time_input_scene_input_date_time_callback, // 完成回调 context, app-date_time); // 初始值 结果存储 date_time_input_set_editable_fields( date_time_input, app-edit_date, app-edit_date, app-edit_date, // 年/月/日 app-edit_time, app-edit_time, app-edit_time); // 时/分/秒由于本例不需要中途校验changed_callback 传NULLdone_callback 通过view_dispatcher_send_custom_event()发送自定义事件场景的on_event收到SceneManagerEventTypeCustom后调用scene_manager_previous_scene()返回展示场景——这正是 ReadMe 所述用户完成编辑按下返回键的标准流程。场景管理器本身通过 example_date_time_input_scene.c 中宏展开的方式生成on_enter/on_event/on_exit三个处理器数组场景清单定义在 example_date_time_input_scene_config.h这是 Flipper 场景管理器SceneManager约定俗成的代码组织方式。五、底层实现绘制、光标与按键交互5.1 布局两行三列从绘制回调 date_time_input_view_draw_callback 可知控件固定为 2 行 × 3 列第 0 行日期行Y9年%04u、月%02u、日%02u第 1 行时间行Y40时、分、秒均为%02u。每列上方还有一行小号提示文字Y Y Y Y / M M / D D、H H / M M / S S数字用FontBigNumbers大号字体渲染。5.2 字段状态的四种绘制形态get_state 宏 与 EditState 枚举 共同决定每个字段的绘制样式状态触发条件绘制效果EditStateDisabled对应字段不可编辑显示数值无外框EditStateNone可编辑但未选中黑色圆角矩形框rframeEditStateActive当前选中、未进入编辑反白填充矩形rboxEditStateActiveEditing当前选中且正在编辑反白填充 上下小箭头图标也就是说没有外框正是EditStateDisabled的直接结果与 ReadMe 描述完全一致。5.3 按键交互与边界处理输入回调 date_time_input_view_input_callback 在InputTypeShort/InputTypeRepeat短按/长按重复时生效分为两种模式未进入编辑导航模式走 date_time_input_navigation_callback——方向键在行/列间移动并借助is_allowed_to_edit()自动跳过被禁用的字段OK键切换editing状态在编辑态按Back先退出编辑非编辑态按Back触发done_callback即 ReadMe 所说的完成语义。编辑模式改值模式第 0 行走日期回调、第 1 行走时间回调每次改动后若有 changed_callback 则立即调用。边界规则在 date_time_input_date_callback 与 date_time_input_time_callback 中日期年限制 1980–2099月 1–12日 1–31到界不再继续增减时间时、分、秒分别按 24/60/60循环回绕如23:59:59的秒 1 变为 0而不是报错或停在 59非法日期自动矫正每次日期变动后调用 date_time_input_cleanup_date按datetime_get_days_per_month(datetime_is_leap_year(...))计算当月真实天数含闰年把 2 月 30 日这类非法值钳制为当月最后一天。5.4 DateTime 结构体约定控件直接操作DateTime定义见 lib/datetime/datetime.h字段语义为字段类型范围houruint8_t0–2324 小时制存储minuteuint8_t0–59seconduint8_t0–59dayuint8_t1–31monthuint8_t1–12yearuint16_t2000–2099weekdayuint8_t1–7注意控件内部以 24 小时制存储小时12 小时制的 AM/PM 转换仅发生在显示阶段见 4.3 节与 12 小时绘制回调 date_time_input_draw_hour_12hr_callback因此业务代码拿到的hour始终是 0–23 的 24 小时制值。六、在其他应用中的复用方式DateTimeInput作为 GUI 通用模块随固件发布业务应用只需在应用清单requires中声明guidate_time_input_alloc()创建控件并view_dispatcher_add_view()注册进入场景时date_time_input_set_result_callback()绑定DateTime与回调需要限制编辑范围时date_time_input_set_editable_fields()传入六个布尔值退出时view_dispatcher_remove_view()date_time_input_free()。从当前仓库源码检索看date_time_input_*API 的调用点集中在 GUI 模块自身与example_date_time_input示例date_time_input_set_result_callback 调用点说明该控件以通用组件 示例示范的形式沉淀在 GUI 服务中可直接借鉴上述场景代码集成到自己的应用。七、构建与运行示例是外部应用FAP使用项目自带的 fbt 工具链即可编译分发# 在仓库根目录下编译该示例应用 ./fbt fap_example_date_time_input # 或编译全部应用后从 build 目录获取 .fap ./fbt faps编译产物.fap拷贝到设备 SD 卡的apps/Examples目录后即可通过应用菜单加载运行具体分发路径可参考 fbt 文档 与 AppsOnSDCard.md。运行时首先看到当前日期时间的展示页选择 Date / Time / Both 后进入输入页用方向键移动、OK进入/退出编辑、Back返回并保存结果。八、小结DateTimeInput是一个设计紧凑的日期时间输入视图单一DateTime*完成初始值 结果存储的双重职责两个回调覆盖逐字段变更校验与整体完成两种生命周期事件set_editable_fields提供到字段级的编辑权限控制底层则通过状态机四态绘制 导航/编辑双模式实现顺滑的按键交互并对闰年、月末等边界条件做了内置矫正。example_date_time_input示例则以最规范的场景管理器组织方式示范了从展示结果 → 选择编辑范围 → 就地编辑 → 返回结果的完整闭环是集成该控件的可直接参考的模板。【免费下载链接】Momentum-Firmware Feature-rich, stable and customizable Flipper Firmware项目地址: https://gitcode.com/GitHub_Trending/mo/Momentum-Firmware创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
📝

华诺云谱内容团队

资深建站顾问 · 行业研究员

10年+企业数字化服务经验,专注智能建站、SEO优化与品牌营销,持续输出建站技巧、行业洞察与营销干货,已帮助5000+企业实现数字化增长。

你可能需要的服务

订阅华诺云谱资讯周报

每周一封,精选建站技巧、SEO与营销干货,直达邮箱。已有 8,000+ 企业主订阅,助你少走弯路。