Skip to content

玄铁声明式 UI 库编程指南 ​

对标库版本: v1.5.1

UI 库是基于渲染库的声明式界面框架:界面 = 状态的函数(View = f(State))。你只描述"状态长这样时界面长什么样",框架负责布局、绘制与事件分发。

xuantie
引 "UI" 予 UI        // 铁铺安装后裸包名引用(推荐)
引 "渲染" 予 R

本地项目内也可以相对路径引用:引 "./lib/UI/UI.xt" 予 UI。UI 库内部会再引渲染库,菱形引入是安全的(见 05_模块系统.md 3.2 节)。


五分钟上手:计数器 ​

代码 ​

xuantie
引 "UI"
引 "渲染" 予 R

设 状态 = UI.造状态({"计数": 0})

UI.应用(状态, 函(s) {
    返 UI.列([
        UI.文本("计数器演示", {
            字号: 28
        }),
        UI.文本("当前: " & UI.态取(s, "计数"), {
            字号: 20
        }),
        UI.按钮("点我 +1", {点击: 函() {
            UI.态设(s, "计数", UI.态取(s, "计数") + 1)
        }})
    ], {内边距: 20, 间距: 12})
}, {宽: 640, 高: 420, 标题: "我的应用"})

点按钮,数字会真实递增。这就是全部:没有手动事件循环、没有手动重绘、无需手动进行字体配置(内置鸿蒙字体自动加载,见第 4 节)。

效果 ​

工作原理(了解即可):应用 每帧执行一次你的构建函数,用返回的控件树完成 FlexBox 布局、悬浮/点击处理和绘制。状态变了,下一帧界面自然就是新的。

按需重绘(默认开):开启后静止界面不空耗帧——无动静(窗口无焦点、无触发UI效果:如动画、输入等)时 应用 只泵事件轮询,检测到脏源(状态变更/鼠标移动/左键按住/滚轮/动画进行中/输入栏聚焦)才执行完整的"重建→布局→绘制"帧。空闲 CPU 占用近零;持续动画的界面每帧都脏,行为与全速一致。如需关闭按需重绘回到全量渲染循环可使用 {"按需重绘": 假} 。

异步任务不受主循环影响:应用/刷新 的每个循环周期都会驱动 fiber 跑一拍(运行时 xt_scheduler_step 非阻塞单步泵),fiber 与线程池任务在 UI 主循环期间持续推进,主线程无需 等待 泵送;其他线程的 态设 会在下一个轮询周期(≤8ms)唤醒重绘。


窗口选项(应用 的第三参) ​

UI.应用(状态, 构建函, 选项) 的选项字典控制窗口本体:

键默认说明
宽800窗口宽(像素)
高600窗口高(像素)
标题"XuanTie App"标题栏文字(支持中文)
背景色(40, 40, 50, 255)(深灰)整窗清底色,用 UI.色(r,g,b,a) 或 UI.色16("#RRGGBB")
可调整假真 时窗口允许拖拽调大小;尺寸变化自动按当前尺寸逐帧重排重绘(变化即脏源)
全屏假真 时进入全屏,并自动按真实屏幕尺寸布局(否则内容只占左上角 宽x高)
无边框假真 时去掉标题栏与边框——同时失去系统最小化/关闭按钮,需自行提供退出途径
字体内置鸿蒙字体TTF 路径,指定后自动加载/卸载
字库字号32字体栅格化字号,越大越清晰、纹理越大
按需重绘真静止界面不空耗帧;假 = 纯 60fps 全量循环

想完全自己管窗口(自定义清屏/每帧先画自己的东西): 用 UI.刷新 嵌入手动渲染循环(见第 6 节),此时窗口行为由你经 R.* 全权控制(R.设窗口可调整、R.清背景、R.设窗口无边框、R.设窗口全屏 等,详见 09_渲染库编程指南)。

示例 ​

xuantie
UI.应用(状态, 函(){
    返 UI.文本("Hello World !",{字号: 32, 字色: UI.色16("#000000")})
}, {
    宽: 960, 高: 600, 标题: "我的面板",
    背景: UI.色16("#F5F5F7"),
    可调整: 真,
    按需重绘: 假
})

无边框自绘标题栏三件套(渲染库 v1.2.4): ​

API说明
R.最小化窗口()最小化到任务栏
R.最大化窗口()工作区最大化(留出任务栏——无边框窗是 WS_POPUP,系统 SW_MAXIMIZE 会盖满全屏含任务栏,故走工作区矩形放置)
R.还原窗口()还原到最大化前的位置尺寸
R.窗口最大化了?()是否最大化(切换钮换图标依据;最大化状态库内跟踪)
R.请求关闭窗口()优雅关闭:投递 WM_CLOSE,主循环下一轮按正常路径退出(不帧中销毁上下文;与程序结束释放资源的 关闭窗口() 不同义)
R.拖拽窗口()标题栏拖拽移动:在自绘标题栏的 触发:"按下" 回调里调用,按住期间窗口跟手移动,松手返回

示例 ​

xuantie
设 状态 = UI.造状态(空)

UI.应用(状态, 函(s) {
    返 UI.叠([
        // 自绘标题栏(双锚横拉,高 40;按下空白处即 Windows 原生拖拽移动)
        UI.叠([
            UI.行([
                UI.文本("  铸造厂(无边框演示)", {"字号": 14, "字色": UI.色彩["浅灰"]}),
                UI.弹性(1, {}),
                UI.图标按钮("./assets/_ic_min.svg", {"点击": 函() { R.最小化窗口() }}),
                UI.图标按钮("./assets/_ic_max.svg", {"点击": 函() {
                    若 R.窗口最大化了?() { R.还原窗口() } 否 { R.最大化窗口() }
                }}),
                UI.图标按钮("./assets/_ic_close.svg", {
                    "悬底色": UI.色(220, 60, 70, 255), "点击": 函() { R.请求关闭窗口() }
                })
            ], {"叉轴对齐": UI.叉中, "内边距": UI.四边(8, 4, 8, 4), "间距": 4,
                "触发": "按下", "点击": 函() { R.拖拽窗口() }})
        ], {"锚": {"左": 0, "上": 0, "右": 1}, "高": 40, "底色": UI.色(36, 40, 52, 255)})
        // 主区:图标按钮陈列 + 计数
    ], {})
}, {"宽": 640, "高": 360, "标题": "无边框演示", "无边框": 真, "可调整": 真})

注意:标题栏空白区(含标题文字/弹性间隔)经 触发:"按下" 调 拖拽窗口() 即 Windows 手感拖拽;图标钮层级更高,点钮不触发拖拽。


状态系统 ​

API说明
UI.造状态(初始字典)创建响应式状态容器
UI.态取(状态, "键")读取状态(渲染期内自动登记依赖)
UI.态设(状态, "键", 新值)写状态;值变化时通知订阅者并标脏
UI.态观(状态, "键", 回调)订阅某键的变化
UI.态设批(状态, 变更表)批量设置多键
UI.态快照(状态)取当前整棵值字典(不登记依赖,引用非深拷贝)
UI.态脏?(状态)查询自上次构建以来是否被标脏
UI.标脏(状态)手动标脏(原地改数组/字典后通知重绘)
UI.态依赖(状态)取上次构建期内被读取过的键列表
UI.态清除(状态)清空订阅、依赖记录与脏标志(业务数据保留)

控件详解 ​

每个控件/容器都是 UI.XX(...) 构造的节点,末参为选项字典(通用键见 3.12)。本节逐控件给出参数、专属选项与示例。

列(竖排容器) ​

UI.列(子列表, 选项) —— 子项自上而下排列,是最常用的布局根。

xuantie
UI.列([
    UI.文本("标题", {字号: 22}),
    UI.按钮("确定", {点击: 函() { ... }}),
], {内边距: UI.全边(16), 间距: 12})

要点:间距 控制子项间隙;弹性 子项会瓜分剩余高度;自身可带 底色/圆角/内边距。

行(横排容器) ​

UI.行(子列表, 选项) —— 子项自左而右排列。选项与 列 相同(主轴换成横向)。

xuantie
UI.行([
    UI.文本("名字:", {}),
    UI.输入栏(s, "名字", {弹性: 1}),
], {间距: 8, 叉轴对齐: UI.叉中})

叠(层叠容器) ​

UI.叠(子列表, 选项) —— 子项在同一区域层叠(后画的盖先画的),用于背景+前景、角标等。

xuantie
UI.叠([
    UI.矩形({底色: UI.色16("#1E2430"), 圆角: 10}),
    UI.文本(盖在最上层, {x: 0, y: 0}),
], {宽: 200, 高: 80})

绝对(绝对布局容器) ​

UI.绝对(子列表, 选项) —— 子项带 x/y 选项按坐标直摆(相对容器内容区左上角),完全跳过 flex 测量。

xuantie
UI.绝对([
    UI.文本("左上角", {x: 16, y: 12}),
    UI.按钮("确定", {x: 220, y: 110, 点击: 函() { ... }}),
], {弹性: 1, 底色: UI.色16("#1E2430"), 圆角: 10})

两个注意:① 绝对容器不裁剪——越界子项会画出容器外;② 坐标是死的,不随窗口缩放自适应——要自适应定位请用 锚点布局(顶栏/侧栏/状态栏/居中钮一次写清),弹性拉伸请用 行/列+弹性。

文本 ​

UI.文本("内容", 选项) —— 静态文字。常用键:字号(默认 16)、字色。

xuantie
UI.文本("计数: " & UI.态取(s, "计数"), {字号: 18, 字色: UI.色彩["黄"]})

按钮 ​

UI.按钮("标签", 选项) —— 点击按钮。专属键:

键含义
点击回调:{"点击": 函() { ... }}
触发"点击"(默认,按下并在钮内松开才触发)/"按下"(按下即发)/"按住"(按住连发)
连发间隔按住模式连发间隔毫秒(默认 50;0=每帧)
首按延迟按住超时开始连发的延迟(默认 0)。点击模式设了它:按住超时进连发、延迟内松开仍单击——单击/长按两用
禁用真 时不响应交互并显示禁用色
三态色悬底色/按底色/禁底色 + 悬字色/按字色/禁字色
三态边色悬边色/按边色/禁边色(配合通用键 边框色/边框宽 使用)
悬浮上浮悬浮时上浮像素(默认 2;0=关闭);悬浮同时自动开启并渐增阴影,形成立体感
按下缩放按住时缩放百分(默认 95;100=关闭);松开以回弹曲线复原(灵动摁感)

状态子字典(CSS 伪类风):悬浮/按下/禁用 三个键各装一个状态的覆写,子键为 底色/字色/边色,与平面键可混用。选项键支持裸标识符写法(见手册 6.5.1 节),引号写法继续可用:

xuantie
UI.按钮("点我 +1", {
    宽: 240, 圆角: 8,
    边框色: UI.色彩["灰"], 边框宽: 2,
    悬浮: {边色: UI.色16("#ffd700")},
    按下: {底色: UI.色彩["绿"]},
    点击: 函() { UI.态设(s, "计数", UI.态取(s, "计数") + 1) }
})
UI.按钮("按住连发", {触发: "按住", 首按延迟: 300, 连发间隔: 100, 点击: 函() { ... }})

按下态的登记规则:按下态跟随按压源——按压沿只登记给带 点击 回调的节点。无回调的按钮悬浮提亮仍在,但按下无视觉反馈、松开也不触发(适合纯装饰钮;要可点就必须给 点击)。

矩形 ​

UI.矩形(选项) —— 色块。常用键:宽/高/底色/圆角。

xuantie
UI.矩形({"宽": 120, "高": 64, "底色": UI.色16("#3B82F6"), "圆角": 8})

空白 / 弹性 ​

UI.空白(选项) 占位(默认 弹性1);UI.弹性(弹值, 选项) 按系数挤占剩余空间。

xuantie
UI.行([UI.文本("左", {}), UI.弹性(1, {}), UI.文本("右", {})])   // 两端贴边

输入栏 ​

UI.输入栏(状态, 键, 选项) —— 单行文本输入框。值直接绑定 状态[键](读写双向),无需回调。

参数含义
状态UI.造状态 的容器
键绑定到状态容器的键名(字符串)

专属选项键:

键含义
占位空值时灰色显示的提示文本
占位色占位文本颜色(默认暗灰)
只读真 时不可编辑(仅展示/可选中复制)
提交回车回调:{"提交": 函(值) { ... }}
焦框色获焦时边框高亮色(默认亮蓝)
焦框宽获焦时边框厚度(默认 2)
左图标/右图标栏内左/右侧图标:图片路径字符串,支持 png/bmp/gif 与 svg(.svg 后缀自动走 nanosvg 光栅化;不支持 jpg/tga,详见渲染指南)
图标尺寸图标边长(像素);0 或省略 = 自动(栏内净高)
图标距图标与文本区间的间距(默认 6)
图标色图标着色 tint(默认白色 = 原图原色)
右图标点击右图标点击回调(典型用法:一键清空);命中右图标区不会移动光标/触发框选
通用宽(默认 240)/高/字号/字距/底色/底色2/渐变向/羽化/阴影/字色/框色/边框宽/圆角/内边距

带图标文本区自动内缩;长文本滚动被裁剪在文本区内,永远不会遮挡左右图标。图标纹理按 路径@尺寸 缓存,常驻进程生命周期。

交互全集(免配置开箱即用):

  • 鼠标:点击获焦(按点击处定位光标)、按住拖动框选、点外/ESC 失焦;悬浮栏上鼠标自动变 I 形文本光标(禁用时不变)
  • 键盘:字符输入(中文 IME 上屏正常,候选窗跟随光标)、退格(按住连删)、左右方向键(按住连移)、上=到首/下=到尾、回车=提交
  • 组合键:Ctrl+A 全选、Ctrl+C 复制、Ctrl+X 剪切、Ctrl+V 粘贴(自动去换行)
  • 光标闪烁;内容超宽时横向滚动保持光标可见
  • IME 约定:无输入栏焦点时输入法整体禁用(打字不弹候选窗);组合中点击候选条带由输入法消化(Windows 标准行为),点击条带之外的空白一击失焦
xuantie
设 状态 = UI.造状态({"名字": ""})
UI.输入栏(状态, "名字", {"占位": "请输入名字(支持中文)...", "提交": 函(v) { 示("提交了: " & v) }})

// 图标 + 阴影 + 渐变圆角
UI.输入栏(状态, "搜索", {
    "占位": "搜索…",
    "左图标": "assets/search.svg",
    "右图标": "assets/clear.svg",
    "右图标点击": 函() { UI.态设(状态, "搜索", "") },
    "阴影": {"颜色": UI.色(0, 0, 0, 160), "模糊": 10, "y": 3},
    "圆角": 14, "底色": UI.色(40, 60, 120, 255), "底色2": UI.色(120, 40, 160, 255), "渐变向": "横"
})

注意:单行性——粘贴内容会被去掉换行;多行文本请用 多行编辑 控件;暂不支持 Home/End、Shift 选择。

滚动容器 ​

UI.滚动容器(子列表, 选项) —— 子项按列排布,内容超出视口高度时可滚轮滚动或拖拽滚动条,可视区自动裁剪。

键含义
高视口高度;不设则吃布局可用高(可配合 弹性 填满剩余空间)
滚动条默认 真;内容不溢出时自动隐藏且不占位(空容器同样无滚动条)
条宽滚动条宽度像素(默认 6)
轨道色轨道底色(默认 白,16/255 透明度)
拇指色滑块色(默认 白,90/255)
拇指拖色拖拽中的滑块色(默认 白,150/255)
xuantie
UI.滚动容器(条目列表, {
    高: 220, 宽: 300, 间距: 8,
    底色: UI.色(24, 27, 34, 255), 圆角: 8, 内边距: 10,
    条宽: 10, 拇指色: UI.色16("#FFAA3C"), 拇指拖色: UI.色16("#FF7828")
})

交互规则:

  • 悬浮在容器上时滚轮滚动(丝滑补间,一格 40px);滚出视口的子项不响应悬浮与点击
  • 滚动条只有按住滑块(拇指)才拖得动,拖拽中内容钉死跟随;点轨道空白不翻页
  • 按下态跟随按压源:按住左键从别处扫过容器内按钮,按钮不会误显示按下态

注意:仅纵向滚动(无横向);内容高按子项列总高计算;暂无"滚动到指定位置"API;嵌套滚动容器尚未验证,暂不建议。

图片 ​

UI.图片(源, 选项) —— 显示一张图片(png/bmp/gif,.svg 自动光栅化;不支持 jpg/tga,详见渲染指南)。固有尺寸取纹理原尺寸,不设 宽/高 即原大;设了则缩放到指定矩形。配 点击 即成图片按钮。

键含义
源(首参)图片路径;状态覆写可换源(见下)
宽/高显示尺寸(默认纹理原尺寸)
图标色着色 tint(默认白=原图)
不透明度0~100;0 = 不可见且不响应命中(点击穿透到下层)
点击回调:{"点击": 函() { ... }},触发模式同按钮

状态覆写(全控件通用,v1.5.0 起):悬浮/按下/禁用 三个子字典不再只限颜色——任意选项键都可按状态覆写,解析顺序 禁用 > 按下 > 悬浮 > 常态。颜色三态继续可用平面键(悬底色 等)与子字典混写:

xuantie
// 悬浮换图,按下换图 + 缩小 + 半透
UI.图片("a.png", {
    宽: 96, 高: 96,
    悬浮: {源: "b.png"},
    按下: {源: "c.png", 宽: 72, 高: 72, 不透明度: 60},
    点击: 函() { ... }
})

两个注意:① 宽/高覆写经上一帧悬浮/按压身份在布局期解析(一帧滞后,无感);② 不透明度对整棵子树连乘,渐变背景经绘制 tint 折算(不重建纹理)。

组合示例:输入栏右侧"有字才浮现"的清除按钮——叠 覆盖 + 动值 驱动不透明度:

xuantie
UI.叠([
    UI.输入栏(状态, "框", {宽: 340, 占位: "输入文字"}),
    UI.行([
        UI.弹性(1, {}),
        UI.图片("clear.png", {
            宽: 18, 高: 18, 图标色: UI.色彩["浅灰"],
            点击: 函() { UI.态设(状态, "框", "") },
            不透明度: UI.动值("清钮", 若 UI.态取(s, "框").字符数 > 0 { 100 } 否 { 0 })
        })
    ], {叉轴对齐: UI.叉中, 内边距: UI.四边(0, 12, 0, 0)})
], {})

图标按钮 ​

UI.图标按钮(源, 选项) —— 纯图标按钮(无文本标签):一张图标(png/bmp/gif/svg,jpg/tga 不支持)居中,默认透明底,悬浮淡亮、按下加亮,禁用时图标降透 40%。无边框自绘标题栏三件套(最小化/最大化/关闭)的官配控件。

参数含义
源(首参)图标路径;状态覆写可换源(悬浮/按下/禁用 子字典)

专属选项键:

键含义
宽/高按钮尺寸(默认 28×28)
图标尺寸图标边长(默认 0 = 自动,净区最大边)
图标色图标着色 tint(默认白 = 原图原色)
悬底色悬浮底色(默认 白,24/255)
按底色按下底色(默认 白,44/255)
禁底色禁用底色(默认透明)
通用圆角(默认 6)/内边距(默认 4)/禁用/点击/触发/连发间隔/首按延迟(交互与按钮同套)
xuantie
// 关闭钮:悬浮变红
UI.图标按钮("close.svg", {悬底色: UI.色(220, 60, 70, 255), 点击: 函() { R.请求关闭窗口() }})

// 圆形大钮 + 禁用态
UI.图标按钮("setting.svg", {宽: 36, 高: 36, 圆角: 18, 图标尺寸: 20, 点击: 函() { ... }})
UI.图标按钮("setting.svg", {禁用: 真})

注意:图标纹理按 路径@尺寸 缓存常驻;按下态跟随按压源(带 点击 回调才登记,见 按钮 的按下态登记规则)。

多行编辑 ​

UI.多行编辑(状态, 键, 选项) —— 多行文本编辑器(铸造厂 CodeEdit 地基)。值直接绑定 状态[键] 整段字符串(\n 分行,读写双向),无需回调。

参数含义
状态UI.造状态 的容器
键绑定到状态容器的键名(字符串)

专属选项键:

键含义
占位空值时灰色显示的提示文本
占位色占位文本颜色(默认暗灰)
行号默认 真;行号: 假 关闭左侧行号槽
只读真 时不可编辑(仅展示/可选中复制)
焦框色获焦时边框高亮色(默认亮蓝)
焦框宽获焦时边框厚度(默认 2)
高亮"玄铁" 开启语法高亮:关键字/字符串/注释/数字逐段着色
高亮色调色板覆写:{"高亮色": {"关键字": UI.色(...), "字符串": ..., "注释": ..., "数字": ...}}(只写要改的类)
通用宽(默认 420)/高(默认 120)/字号/字距/底色/字色/框色/边框宽/圆角/内边距

交互全集(免配置开箱即用):

  • 鼠标:点击获焦(按点击处定位到行列)、按住拖动框选(允许拖出边界)、滚轮滚动(一格 40px)、拖拽滚动条拇指、点外/ESC 失焦;悬浮栏上鼠标自动变 I 形文本光标
  • 键盘:字符输入(中文 IME 上屏正常,组合串内联显示在光标处)、退格/方向键(按住连发)、回车换行、Tab 插 4 空格、Home/End 行首行尾
  • 组合键:Ctrl+A 全选、Ctrl+C 复制、Ctrl+X 剪切、Ctrl+V 粘贴(保留换行)
  • 光标 500ms 闪烁;内容超视高时出现滚动条,滚动偏移自动夹取
xuantie
设 状态 = UI.造状态({"源码": "// 在此写代码\n示(1)\n"})
UI.多行编辑(状态, "源码", {
    "宽": 640, "高": 300, "占位": "在此输入代码...",
    "字号": 15, "圆角": 8
})

// 无行号窄栏
UI.多行编辑(状态, "备注", {"宽": 640, "高": 90, "行号": 假, "占位": "备注..."})

注意:横向不滚动(超长行会被裁剪在文本区内);选区为字符索引模型(跨行选区高亮逐行求交);语法高亮经 "高亮": "玄铁" 开启,IME 组合中的光标行暂走纯文本通路(上屏即恢复高亮)。

锚点布局 ​

全控件/容器通用的定位系统:节点按比例+像素偏移钉在父容器给定的槽位内,窗口调大小自动跟随。两个选项键:

键含义
锚子字典 {"左": 比, "上": 比, "右": 比, "下": 比}(0~1,任意子集;缺省=该侧不锚)
偏子字典像素偏移 {"左": px, "上": px, "右": px, "下": px}(默认 0,可负)。正值把该侧边向外推(远离锚边):左/上 正=向右/向下,右/下 正=向右/向下探出。贴边上移须写负值,如底部让位 68px 写 "下": -68

逐轴规则(X/Y 各自独立判定):

  • 双锚(同轴两侧都设)= 拉伸:起点 = 槽位起点 + 槽位尺寸×近侧比 + 近侧偏,尺寸 = 槽位尺寸×(远比-近比) + 远侧偏 - 近侧偏——宽/高随父容器变
  • 单锚(只设一侧)= 定点 + 固有/选项尺寸:比值 <0.5 前向长(锚点是起点)、>0.5 后向长(锚点是终点)、=0.5 居中
  • 无锚 = 维持现有 Flex/容器排布(默认行为,完全兼容旧代码)

容器协同:

  • 叠 内锚定子给满内容区槽位——IDE 壳(顶栏/侧栏/主区/状态栏)直接锚,无需 绝对 手算坐标
  • 列/行 内锚定子仍占 Flex 流位,在其格内锚定(配合 弹性 撑开的格,可做格内左/中/右对齐)
  • 外边距 不适用(锚/偏已含定位语义);平移x/平移y 仍叠加——动值 驱动即可做面板滑入滑出

示例

IDE 壳四区 + 居中钮,窗口可调整,各区随窗口拉伸

xuantie
引 "UI" 予 UI
引 "渲染" 予 R

设 状态 = UI.造状态({})

函 面板(标题, 底色, 选项) {
    设 o = {"底色": 底色, "圆角": 0, "内边距": UI.全边(10)}
    遍历 kv 于 选项 { o[kv] = 选项[kv] }
    返 UI.叠([
        UI.文本(标题, {"字号": 15, "字色": UI.色彩["浅灰"]})
    ], o)
}

UI.应用(状态, 函(s) {
    设 次 = UI.态取(s, "次")
    若 次 == 空 { 次 = 0 }
    返 UI.叠([
        面板("顶栏(双锚横拉, 高40)", UI.色(50, 56, 68, 255), {"锚": {"左": 0, "上": 0, "右": 1}, "高": 40}),
        面板("侧栏(宽220, 上下拉伸)", UI.色(38, 44, 56, 255), {"锚": {"左": 0, "上": 0, "下": 1}, "宽": 220, "偏": {"上": 40, "下": -28}}),
        面板("主区(四锚拉伸, 偏出让位)", UI.色(30, 34, 44, 255), {"锚": {"左": 0, "上": 0, "右": 1, "下": 1}, "偏": {"左": 220, "上": 40, "右": 0, "下": -28}}),
        UI.叠([
            UI.文本("状态栏(底锚后向, 高28) — 点击计数: " & 字(次), {"字号": 13, "字色": UI.色彩["浅灰"]})
        ], {"锚": {"左": 0, "右": 1, "下": 1}, "高": 28, "底色": UI.色(46, 52, 64, 255), "内边距": UI.全边(6)}),
        UI.按钮("居中钮(0.5居中)", {"锚": {"左": 0.5, "上": 0.5}, "宽": 140, "高": 36, "点击": 函() { UI.态设(s, "次", 次 + 1) }}),
        UI.按钮("右上钮(右锚后向)", {"锚": {"右": 1, "上": 0}, "宽": 110, "高": 28, "偏": {"右": -8, "上": 46}, "点击": 函() { UI.态设(s, "次", 次 + 1) }})
    ], {})
}, {"宽": 800, "高": 500, "标题": "锚点演示", "可调整": 真})

注意:锚值/偏值暂不支持状态覆写(悬浮/按下/禁用 子字典不含 锚/偏);单锚轴的尺寸取 宽/高 选项,缺省回退固有尺寸(文本/按钮按内容,容器按子树)。

通用选项键速查 ​

所有控件/容器的选项字典通用键(

颜色值:

  • UI.色(r,g,b,a) (RBG颜色值)
  • UI.色16("#RRGGBB")) (十六进制颜色值)

颜色·背景三态:

颜色·文字三态:

外观增强:

  • 底色2(渐变第二色,设置后背景变为 底色→底色2 渐变)
  • 渐变向("横"/"竖",默认 "竖")
  • 羽化(边缘羽化像素,1 = 仅抗锯齿,>1 产生柔边)
  • 阴影(字典 {"颜色":色,"模糊":像素,"x":0,"y":2},默认关闭)
  • 字距(字符间距像素,默认 1)
  • 不透明度(0~100,子树连乘;0 = 不可见且不响应命中)

尺寸布局:

锚点定位(详见 锚点布局):

  • 锚(Godot 风比例锚点:{"左":比,"上":比,"右":比,"下":比},双锚拉伸/单锚定点/0.5 居中)
  • 偏(锚点像素偏移,可负)

文字形状:

交互:

变换与裁剪:

  • 平移x/平移y(像素,可负;渲染与命中间步偏移,不影响兄弟布局,动值 驱动即滑入滑出)
  • 裁剪(容器:子树超出边界即裁,界外不响应交互)

状态覆写:

  • 悬浮/按下/禁用 子字典内可写任意选项键(颜色三态亦可平面键/子字典混写),按状态解析,见 3.11

边距写法三选一:{"内边距": 20}(裸数字自动转全边)、UI.全边(20)、UI.四边(8,16,8,16)。 对齐常量:主轴 UI.对齐始/对齐中/对齐末/对齐间/对齐均/对齐均等;叉轴 UI.叉始/叉中/叉末/叉撑。 颜色常量:UI.色彩["白"/"黑"/"红"/"绿"/"蓝"/"黄"/"灰"/"深灰"/"浅灰"/"透明"/"主题"/"强调"]。


组件动画(贝塞尔缓动) ​

UI 库内建声明式动画:每帧把"目标值"喂给 UI.动值,目标变化当帧起即从当前显示值平滑补间过去。数值与颜色(r/g/b/a 字典)皆可动画。

两个 API:

API含义
UI.造动画(键, 选项)注册动画:{"时长": 毫秒, "曲线": "丝滑"};幂等,可反复调用改配置
UI.动值(键, 目标值)返回当前帧插值;目标变化自动从当前值起播(中途变向也顺滑)

曲线预设(cubic-bezier):线性 / 丝滑(默认,ease-in-out 体感) / 缓入 / 缓出 / 回弹(带过冲)。

规则与语义:

  • 键全局唯一(建议带模块前缀,如 "设置面板.x")
  • 首帧不播:第一次喂目标值时直接钉住(避免开屏乱飞)
  • 时长: 0 即关闭动画,立即到位
  • 动画状态存全局侧表,与节点每帧重建无关——键在,动画状态就在
xuantie
UI.造动画("面板x", {"时长": 300, "曲线": "丝滑"})
// 构建函里:
UI.矩形({"x": UI.动值("面板x", 目标x), ...})   // 目标x 变化时自动滑过去

内建缓动(免配置):按钮悬浮/按下/禁用的底色与字色、输入栏聚焦边框色,状态切换时自动丝滑过渡(120~150ms)。官方组件内建动效一律使用「丝滑」曲线。


中文字体 ​

UI 库默认字体优先走 GDI 系统字体(微软雅黑):Windows 系统级灰阶抗锯齿(与记事本中渲染的字体完全同质感)、按需栅格化零启动成本、生僻字由系统字体引擎自动回落——不写任何字体代码,中文即开即显且免字体文件(一般来讲默认支持中文字体渲染应该是标配,更别说中文编程语言。但因为底层使用raylib,所以是一个相对特殊的存在)。

GDI 不可用时的回退链:内置鸿蒙字体(HarmonyOS Sans,按 铁铺已安装包 assets → XUANTIE_HOME 安装目录 → 程序自身目录 assets 查找)→ raylib 默认字体(仅 ASCII,中文会显示为问号并打印一行提示)。

xuantie
UI.应用(状态, 构建函, {"宽": 640, "高": 420, "标题": "我的应用"})
// 无需 "字体" 选项,中文自动正常

显式指定(覆盖默认):应用 选项传 "字体": "你的.ttf",手动渲染循环里用 UI.设字体(路径, 字库字号)(必须在窗口初始化之后调用,加载字形纹理需要 GL 上下文);或直接 UI.设字体 传 R.加载系统字体("微软雅黑", 32) 的句柄指定其他系统字体(如 "宋体"/"Consolas")。

  • 字库字号:栅格化字号(默认 32),越大越清晰、纹理越大。
  • ttf 路径的全 CJK 字体纹理较大(数千字形),首次加载约 1-2 秒;框架会先画一帧背景再加载,避免白窗无响应感。

手动渲染循环(嵌入自定义绘制) ​

不用 应用 的主循环时,用 刷新 把 UI 嵌入你自己的帧循环:

xuantie
引 "UI" 予 UI
引 "渲染" 予 R

R.初始化窗口(640, 420, "手动循环")
UI.设字体("HarmonyOS_Sans_SC_Regular.ttf", 32)
设 状态 = UI.造状态({})

当 非 R.窗口应关闭?() {
    R.开始绘图()
    R.清背景(40, 40, 50, 255)
    // 你自己的绘制...
    UI.刷新(状态, 函(s) { 返 UI.列([UI.文本("嵌入UI", {})], {}) }, 0, 0, 640, 420)
    R.结束绘图()
}
R.关闭窗口()

使用禁区与常见错误 ​

错误用法后果正确做法
引 "UI" 予 UI 后又 引 "UI" 予 界面编译报错:同一模块只能用一个别名统一别名
对 空 或数字做索引(如拿错类型的选项值)运行时明确报错退出(索引守卫)按上表写选项;读取返回值前判空
在窗口初始化前 UI.设字体字体加载失败(无 GL 上下文)用 应用 的 "字体" 选项,或在 初始化窗口 之后调用
回调里直接改界面节点无效——下一帧整棵树会被重建只改状态(态设),界面跟着状态走
把控件节点存进变量,再挂进多个容器(双挂)运行时明确报错退出(双挂守卫:同一实例一帧只允许布局一次,否则坐标被后挂载点覆盖、先挂载点内容全不可见)每帧在构建函数内现场调用构造函数;要复用就抽成 函 造XX() 每次调用造新实例
返 [w, h] 这类直接返回字面量旧版编译器会静默返回空;已修复请升级到最新版编译器

能力边界 ​

  • 控件集:文本/按钮/矩形/容器/空白/弹性/输入栏/滚动容器/图片/多行编辑。尚无滑块、复选框(排期中)。
  • 输入栏为单行:不支持多行、Home/End、Shift 选择;IME 候选窗跟随光标已支持(Windows)。
  • 每帧整树重建,简单直接;按需重绘已让静止界面零耗帧,但大型界面(上千控件)每帧全量重建的增量更新仍是后续优化方向。
  • 圆角矩形已支持(圆角 选项);文本无复杂排版(无富文本/多字体混排)。
  • 已知问题与修复进度见项目仓库 issue/更新日志。

上一篇:11_多线程开发深度教程.md | 相关:09_渲染库编程指南.md

基于 VitePress 静态构建 · 文档内容与仓库 GUIDE/ 同源

玄铁玄铁 XUANTIE · 中文系统级编程语言MARK 玄·折 120×120 · STROKE 8 · NO CURVES