exwin UI 窗口管理扩展库
作者:江访 | 最后修改:2026-03-27
一、概述
exwin 是一个轻量级的窗口管理扩展库,为 LuatOS 应用程序提供基于栈的窗口导航和管理功能。该库通过统一的窗口生命周期回调(创建、销毁、获得焦点、失去焦点)简化了多窗口应用的开发,更轻松实现窗口间的跳转和返回。
注意事项:
exwin 为扩展库,没有内置到 LuatOS 内核固件中,使用时需要 exwin = require("exwin")加载后才能正常调用 exwin 的功能;
1.1 主要特性
- 对外接口:exwin 提供四个核心接口,满足窗口导航、状态查询和资源回收需求。
接口名称 功能描述 适用场景 内部逻辑简述 exwin.open(config) 打开一个新窗口,返回唯一窗口 ID `win_id`。 打开一个新窗口。 exwin 将窗口注册信息 `config` 与系统分配的 `win_id` 组合成窗口记录,保存至内部窗口栈 `win_stack` 栈顶;然后调用窗口注册的 `on_create` 回调,并让原栈顶窗口失去焦点(若存在)。 exwin.close(win_id) 关闭指定窗口(通常由窗口自身调用以关闭自己)。 关闭指定窗口。 exwin 根据 `win_id` 查找窗口记录,若找到则调用其 `on_destroy` 回调,并从栈中移除;如果关闭的是当前活动窗口(栈顶),则让新的栈顶窗口获得焦点(调用其 `on_get_focus`)。 exwin.is_active(win_id) 查询指定窗口是否为当前活动窗口(栈顶)。 在定时器或数据更新时判断是否应刷新 UI,避免操作非活动窗口的控件。 exwin 检查栈顶窗口的 `id` 是否等于传入的 `win_id`,返回布尔值。 exwin.return_idle() 一键返回待机窗口(栈底窗口),销毁其余所有窗口。 “返回主窗口”或退出应用场景。 exwin 从栈顶向下遍历,销毁除栈底(待机窗口,通常 ID = 1)外的所有窗口(依次调用其 `on_destroy` 并从栈中移除),最后让待机窗口获得焦点(调用其 `on_get_focus`)。 -
窗口数据栈内部结构:
win_stack是一个 Lua 数组(table),栈顶元素为数组最后一个元素。每个栈元素是一个窗口记录表,栈操作时,系统自动维护这些记录的入栈、出栈,并调用相应的生命周期回调,确保窗口状态与栈顶位置一致。包含以下字段:字段名 类型 描述 win_id number 窗口唯一标识 ID,由系统分配,从 1 开始递增。 on_create function 窗口创建回调(对应 `on_create`),在窗口打开时调用。 on_destroy function 窗口销毁回调(对应 `on_destroy`),在窗口关闭时调用。可选。 on_get_focus function 窗口获得焦点回调(对应 `on_get_focus`),在窗口成为栈顶时调用。可选。 on_lose_focus function 窗口失去焦点回调(对应 `on_lose_focus`),在窗口不再是栈顶时调用。可选。 - 窗口注册信息:每个窗口通过配置表
config注册,必须提供生命周期回调函数。config表包含以下字段:
字段名 类型 描述 on_create function 窗口创建回调,必须提供。在窗口创建时调用,用于构建 UI、初始化资源。 on_destroy function 窗口销毁回调,可选。在窗口销毁时调用,用于释放资源、停止定时器。 on_get_focus function 窗口获得焦点回调,可选。在窗口获得焦点时调用,用于刷新数据、恢复动画。 on_lose_focus function 窗口失去焦点回调,可选。在窗口失去焦点时调用,用于暂停动画、停止后台任务。 1.2 注意事项
- 窗口的创建、销毁、焦点变化均通过所注册的函数执行,开发者应在对应函数中实现 UI 的初始化和资源释放。
- 窗口内部可通过自身的
win_id调用exwin.close(win_id)关闭自身。 - 在定时器或异步任务中,可调用
exwin.is_active(win_id)判断当前窗口是否仍为活动窗口,避免操作非活动窗口的控件。 - 特别注意:不建议一直只打开窗口或者跳转窗口,这样会使内存占用不断增加。如果需要进入窗口时显示内容为最新,可以设置使用变量保存需要动态显示的内容,使用订阅消息或定时器的方式进行更新变量,此方式可以使每次进入窗口显示内容保持为最新状态。所以更推荐退出窗口时使用 exwin.close(win_id)的方式清理 UI 相关组件的内存占用,以维持系统的持续运行。
1.3 应用场景图示

二、核心示例
以下示例演示了如何使用 exwin 库创建待机窗口和二级窗口,并实现窗口间的切换。
2.1 待机窗口模块(idle_win.lua)
-- idle_win.lua - 待机窗口 local win_id = nil local main_container local function create_ui() main_container = airui.container({ parent = airui.screen, x = 0, y = 0, w = 480, h = 320, color = 0xF8F9FA }) -- 添加一个按钮,点击后打开二级窗口 airui.button({ parent = main_container, x = 190, y = 140, w = 100, h = 40, text = "进入二级窗口", on_click = function() sys.publish("OPEN_SECOND_WIN") end }) end local function on_create() create_ui() log.info("idle", "待机窗口创建") end local function on_destroy() if main_container then main_container:destroy() end log.info("idle", "待机窗口销毁") end local function on_get_focus() log.info("idle", "待机窗口获得焦点") end local function on_lose_focus() log.info("idle", "待机窗口失去焦点") end -- 订阅打开待机窗口的消息(由 ui_main 发布) local function open_handler() win_id = exwin.open({ on_create = on_create, on_destroy = on_destroy, on_get_focus = on_get_focus, on_lose_focus = on_lose_focus, }) end sys.subscribe("OPEN_IDLE_WIN", open_handler)2.2 二级窗口模块(second_win.lua)
-- second_win.lua - 二级窗口 local win_id = nil local main_container local function create_ui() main_container = airui.container({ parent = airui.screen, x = 0, y = 0, w = 480, h = 320, color = 0xE1F5FE }) -- 返回按钮 airui.button({ parent = main_container, x = 190, y = 140, w = 100, h = 40, text = "关闭窗口", on_click = function() exwin.clos(win_id) -- 关闭当前窗口 -- exwin.return_idle() -- 一键返回待机窗口 end }) end local function on_create() create_ui() log.info("second", "二级窗口创建") end local function on_destroy() if main_container then main_container:destroy() end log.info("second", "二级窗口销毁") end local function on_get_focus() log.info("second", "二级窗口获得焦点") end local function on_lose_focus() log.info("second", "二级窗口失去焦点") end -- 订阅打开待机窗口的消息 local function open_handler() win_id = exwin.open({ on_create = on_create, on_destroy = on_destroy, on_get_focus = on_get_focus, on_lose_focus = on_lose_focus, }) end sys.subscribe("OPEN_SECOND_WIN", open_handler)2.3 UI 管理主模块(ui_main.lua)
-- ui_main.lua require "exwin" require "idle_win" require "second_win" local function ui_mian() -- 初始化显示和触摸 lcd_drv.init() tp_drv.init() -- 打开待机窗口 sys.publish("OPEN_IDLE_WIN") -- 开启背光 gpio.setup(1, 1) end sys.taskInit(ui_mian)三、常量详解
exwin 扩展库没有常量。
四、函数详解
4.1 exwin.open(config)
功能
打开一个新窗口,分配唯一 ID,并执行新窗口创建和旧窗口失去焦点逻辑。
参数
config
**参数含义**:窗口配置表 **数据类型**:table **是否必选**:是 **取值范围**:包含以下子参数: on_create:函数类型,窗口创建回调,必须提供 on_destroy:函数类型,窗口销毁回调,必须提供 on_get_focus:函数类型,窗口获得焦点回调,可选 on_lose_focus:函数类型,窗口失去焦点回调,可选 **注意事项**:必须包含 on_create 和on_destroy 函数,否则会报错重启 **参数示例**: { on_create = on_create, on_destroy = on_destroy, on_lose_focus = on_lose_focus, on_get_focus = on_get_focus, }返回值
local win_id = exwin.open(config)
win_id
含义说明:新窗口的唯一标识 ID 数据类型:number 取值范围:有符号整数 注意事项:ID 从 1 开始递增,系统运行期间唯一 返回示例:1示例
-- 订阅打开待机窗口的消息 local function open_handler() win_id = exwin.open({ on_create = on_create, on_destroy = on_destroy, on_lose_focus = on_lose_focus, on_get_focus = on_get_focus, }) end sys.subscribe("OPEN_IDLE_WIN", open_handler)4.2 exwin.close(win_id)
功能
关闭指定窗口(通常由窗口自身调用以关闭自己)。如果关闭的是当前活动窗口,则自动让下一个窗口获得焦点。
参数
win_id
**参数含义**:要关闭的窗口 ID **数据类型**:number **是否必选**:是 **取值范围**:有效的窗口 ID(由 exwin.open 返回) **注意事项**:若窗口不存在,调用无效果 **参数示例**:1返回值
无
示例
-- 在窗口内部关闭自己 exwin.close(win_id)4.3 exwin.is_active(win_id)
功能
查询指定窗口是否为当前活动窗口。
参数
win_id
**参数含义**:窗口 ID **数据类型**:number **是否必选**:是 **取值范围**:有效的窗口 ID **注意事项**:若传入 nil 或无效 ID,返回 false **参数示例**:1返回值
local is_active = exwin.is_active(win_id)
is_active
含义说明:指定窗口是否为活动窗口 数据类型:boolean 取值范围:true(是活动窗口),false(不是活动窗口或窗口不存在) 注意事项:无 返回示例:true示例
if exwin.is_active(win_id) then -- 只有当前活动窗口才更新 UI update_time() end4.4 exwin.return_idle()
功能
一键返回待机窗口(栈底窗口),销毁其余所有窗口,自动执行其余所有窗口的
on_destroy函数。参数
无
返回值
无
示例
-- 在任何二级窗口调用,直接回到待机窗口 exwin.return_idle()五、产品支持说明
exwin UI 窗口管理扩展库可以在支持 lcd、AirUI、u8g2 库、eink 核心库之一的合宙 LuatOS 设备上进行使用
- 窗口注册信息:每个窗口通过配置表
-