跳转至

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()
      end
      

      4.4 exwin.return_idle()

      功能

      一键返回待机窗口(栈底窗口),销毁其余所有窗口,自动执行其余所有窗口的 on_destroy 函数。

      参数

      返回值

      示例

      -- 在任何二级窗口调用,直接回到待机窗口
      exwin.return_idle()
      

      五、产品支持说明

      exwin UI 窗口管理扩展库可以在支持 lcd、AirUI、u8g2 库、eink 核心库之一的合宙 LuatOS 设备上进行使用