主题
流式布局 UI API 参考
所有扩展方法返回控件本身,支持链式调用。
核心类:LayoutExtensions(布局)、BuilderExtensions(控件属性)、UI(静态构建器)。
Game HUD and round-end presentation
For a game HUD or visual reskin, also read game-visual-production. Choose scene-matching surface/accent/text colors, typography, panel silhouettes and spacing as project tokens before assembling controls. Group health, weapon/ammo and mission/score by importance; keep central aiming space clear. The optional industrial HUD recipe gives a concrete GameUI palette/layout starter, not a mandatory theme.
Gameplay-critical state needs a visible transition. On defeat, show a clear central result panel with a primary restart action; a short screen tint/dim transition can reinforce it when appropriate. Do not rely solely on a small top-bar text change and frozen picture. Route button and keyboard restart through the same round reset, hide/reset transient overlays, and verify the click does not also fire a weapon through the UI.
Test the intended round-end policy for movement, aim, attacks, enemy updates and spawning. Gate gameplay input while a blocking result panel is open, retain its UI input, and check that restart resets health, projectiles, counters and stale pressed inputs. Use screenshots plus ui.snapshot / ui.get_rect and actual button interaction; correct control rectangles alone do not establish visual clarity.
> 先检查项目的对齐默认策略:当前游戏模式引用的 GameDataGameUI 可通过 > UseTopLeftContentAlignmentDefaults 选择新建控件的内容对齐默认值。旧项目缺少该字段或关闭时, > HorizontalContentAlignment / VerticalContentAlignment 保持历史 Center/Center;新版项目模板默认开启, > 改为 Left/Top。该开关只影响之后创建的控件,不改写显式值,也不改变 PositionType。 > 可复用库和需要固定布局语义的控件仍应显式设置对齐,不依赖宿主项目开关。 > > 在历史 Center 模式下,当子控件未显式设置 HorizontalAlignment / VerticalAlignment 时,会继承父控件的 > Center 对齐,导致 Margin 从中心偏移而非从左上角偏移,产生文字偏右下的视觉问题。 > 多个子控件更危险:若容器内有多个子控件都未设对齐,它们全部被居中到同一区域后完全重叠。 > > 按预期布局选择对齐方式。旧项目或可复用库若要从左上角用 Margin 定位,显式设置 Left/Top;需要自动排列时使用对应方向的流式容器。 > 流式扩展与对象初始化器配置同一套属性,可以混用;两者都需检查尺寸、对齐和父子关系。
> 生命周期警告:RemoveFromParent() / RemoveFromVisualTree() 只把控件从 UI 树摘下,ClearChildren() 只移除直接子控件;这些 API 不释放控件、子控件树、事件或 native control。 > 浮字、弹窗、临时面板、战斗 HUD、临时 Canvas 等关闭后不复用的 UI 必须调用 Destroy()。 > 只有临时隐藏、换父节点、对象池复用时才使用 RemoveFromParent() / ClearChildren()。对 Canvas / CanvasAnimated,长期只摘树不销毁在移动端更容易累积渲染资源压力。
发布图片加载
PC 和手机发布都可能把 PNG/JPG 转为 KTX 等纹理容器,路径后缀仍保持不变。不要用 GameGraph.ResourceSystem.Image.Load(path) 的 CPU 解码结果判断 GameUI/Canvas 图片是否存在或允许绘制;CPU 读取失败可能只是格式不支持。普通 UI 直接使用逻辑图片路径。确需提前加载独立散图以实现缺图回落时,用 GameGraph.ResourceSystem.Texture2D.Load(path),现有客户端经 TextureX 取得 Texture2D;不要每帧加载。图集虚拟子图不能按独立纹理文件检查。正确示例与旧客户端边界见发布图片的加载与检查,发布后还需在目标平台验证实际显示。
图集与大图子区域
用户要让普通 UI 控件显示图集里的一小块时,先读自定义 UI 图集,使用现有图集 JSON 配置流程。控件没有 SourceRect / UV 属性,不代表必须改用 Canvas。
- 读取大图尺寸,按用户指定或实际素材识别出每个图标的像素矩形,确认取图区域没有越界。
- 在项目
ui/atlas/写入大图与同名区域 JSON,例如custom_icons.png+custom_icons.json;避开自动生成的atlas_1等名称。 - 合并
ui/atlas/atlas.json清单,保留现有条目。AtlasPath和ConfigPath相对于ui/,分别填写atlas/custom_icons.png和atlas/custom_icons.json。 - 区域数组条目的
RelativePath带ui/,例如ui/image/icons/sword.png;控件Image省略该前缀,填image/icons/sword.png。逻辑名称对应的散图不需要存在。区域格式和必要字段以指南示例为准,名称不要重复。 - 在现有 UI 中给控件配置该
Image与显示尺寸;通过数据编辑器修改控件数据时继续走 DataManager/MCP。图集 JSON 是资源配置,可以由 AI 直接写文件。 - 写完配置后重新预览,结合截图和
ui.snapshot确认每块图标的内容、区域和显示尺寸。图集缓存不属于普通ImageCache.Invalidate的刷新保证,修改配置后重载项目,必要时重启编辑器。
自动打包会用 ui/atlas/ 下同名配对的 PNG/JPG 与 JSON 重建清单,因此保留自定义文件对。Windows PIE 验证通过后,移动端发布仍应单独验收;不要把编译、控件矩形或图片缓存失效返回成功当作显示正确的证据。
发布后,若 Editor MCP 提供 project_publish_verify_resources,用该次成功操作返回的 publish_identity.platform_variants 选择实际变体,启动只读校验,再按返回的 verification_id 调用 status/wait 续查。同一发布操作及变体重复启动会复用任务;等待超时不重发项目。清单和区域 JSON 差异必须处理,PNG 转 KTX 的哈希差异则按容器/格式检查。工具的 not_checked_decoder_unavailable 表示未核对像素;最后仍用目标客户端实际显示验收。旧发布缺少身份时不猜 URL/版本。完整参数见发布包校验 MCP。
转换 FGUI 图集前检查透明裁边和旋转:当前普通区域格式没有裁边偏移和旋转字段,OriginSize 不会自动居中或恢复裁边位置。优先关闭 trimImage 和旋转;已有裁边数据必须利用来源偏移补回透明画布再打包,缺少偏移时不要猜。完整矩形的九宫格使用 CompressType: 0 与 Border: "左 上 右 下" 四侧像素宽度;只有分块压缩格式 CompressType: 4 才使用 Grid-0 至 Grid-8。详细示例见图集指南。
OriginSize 是图片尺寸查询所用的逻辑尺寸,Width/Height 是图集实际存储矩形。完整图片预先缩小后可保留原逻辑尺寸,配合 Scaled: true 换算九宫格采样边宽;九宫格重复区域压缩也可保留处理前尺寸,但不使用整图缩放换算。不要把尺寸差异解释成透明裁边或自动补边。
图集黑白边或串色时,先读黑白边与图块串色:按相邻区域串色、透明像素 RGB 污染、预乘 Alpha 约定、Mipmap 和发布压缩分别定位。生成图集时区分 Padding、Extrude 和 Alpha Bleed;无 Mipmap 的双线性 UI 可从每侧 Extrude 2 像素、原始矩形间距 4 像素起步,按目标缩放/压缩调整,不能当作全平台保证。区域矩形不含外部保护区,OriginSize 和九宫格 Border 不用于补偿保护区。不要未经核对就预乘图片、修改混合模式、内缩所有 UV 或编造区域 JSON 的 Mipmap 字段。
透明像素 RGB 颜色扩散检查清单
- [ ] 检查轮廓附近
Alpha = 0像素的 RGB 是否被黑色或白色填充;同时查看半透明边缘是否已经带有底色。仅看透明背景预览不能确认 RGB 是否正确。 - [ ] 核对源图和渲染链路使用 Straight Alpha 还是 Premultiplied Alpha。下面的 RGB 扩散针对非预乘源图;预乘数据的全透明像素应满足其预乘约定,不直接写入非零 RGB。
- [ ] 需要 Alpha Bleed / Color Dilation 时,将同一子图片中邻近可见像素的 RGB 扩散到全透明区域,保持整个 Alpha 通道逐像素不变;此处理不改写原有可见或半透明像素。半透明边缘已有的底色应另行从原稿修正。
- [ ] 按子图片分别扩散,再进行边缘扩展、图集打包及目标纹理转换;处理已有图集时按各区域隔离,避免颜色从另一个图标扩散过来。RGB 扩散与矩形外的 Extrude 分别检查。
- [ ] 在源图及实际导出/发布纹理中复查边缘颜色和 Alpha 约定,并在浅/深背景、原尺寸及实际缩放下截图验收;记录是否执行过颜色扩散,不把清单勾选当作显示正确的证据。
需要动态指定每次绘制的源矩形时再使用 Canvas.DrawImage 源区域重载;普通图集显示不需要 CPU 裁图、Resize 或重建纹理。
Loading 页面
当用户要自定义 Loading 页面、启动遮罩、场景切换进度或加载提示时,先看 docs/systems/LoadingUIScreen.md。
按以下优先级选择方案:
- 关闭框架默认启动 Loading:在当前
GameDataGameUI中设置ShowDefaultLoading = false。如果 GameMode 仍引用gamesparkcore.ScopeData.GameDataGameUI.Default,先创建项目自己的GameDataGameUI,再让GameDataGameMode.GameUI指向它;不要修改依赖库数据。 - 换肤框架默认启动 Loading:创建项目自己的
GameDataLoadingUI,优先继承 GameSparkCore 的“Loading界面模板”或gamesparkcore.ScopeData.GameDataLoadingUI.Default;在GameDataGameUI中保持ShowDefaultLoading = true,并通过DefaultLoadingUI引用它。 - 代码动态显示同款 Loading:使用
new LoadingUI(configuration)复用GameDataLoadingUI样式。GameEntryLoadingSystem.ShowLoading(...)和无参LoadingUI工厂使用兼容默认样式,不会自动读取项目的DefaultLoadingUI。 - 完全自建页面:只有结构与内置 Loading 明显不同时,才用
Page、Panel、Label、Image、Progress等控件搭页面,并设置.ZIndex(StandardUIType.Loading.ExpectedZIndex ?? 10000);临时遮罩结束后调用Destroy()。
框架在 Game.OnGameplaySettingsInitialization 读取当前 GameDataGameMode.GameUI 的 ShowDefaultLoading / DefaultLoadingUI 并创建启动 Loading。不要为了关闭或换肤在 OnGameDataInitialization 中回写 ScopeData,也不要同时注册另一套相同的启动遮罩。
兼容边界:旧项目缺少新字段时仍显示历史默认样式;DefaultLoadingUI 为空时使用兼容默认配置;ShowDefaultLoading = false 只关闭框架自动创建的启动 Loading,不影响项目代码主动创建的临时 Loading。
依赖地图内容时等待 Scene.Loaded / OnLoadEnd,不要把 GameStart 当作场景加载完成。原生 App 启动图或平台 splash screen 不属于项目内 GameUI,不能用 LoadingUI 解决。
运行时排版验证
当编辑器 MCP 提供 runtime_call_tool,并且用户已经启动普通调试、调试不编译或纯客户端调试时,AI 助手应优先使用 Runtime MCP 获取实时画面和 UI 控件数据,再决定如何调整布局。
推荐闭环:
- 调用
debug.capture_screenshot保存当前客户端截图,确认真实视觉状态。一般布局检查可传maxWidth: 1920, maxHeight: 1080或maxWidth: 1280, maxHeight: 720限制图片尺寸;需要辨认细小文字或像素细节时保留原始分辨率。 - 调用
ui.snapshot获取 GameUI 控件树、文本、可见性和rect_px。 - 用
ui.find查找目标按钮、标签、面板或输入框。 - 用
ui.get_rect获取目标控件的屏幕像素坐标和尺寸。 - 根据截图与坐标调整
.Size()、.Margin()、.Padding()、.Align*()、.Flow*()、.WidthGrow()等布局代码。 - 重新启动调试或刷新客户端后再次截图和查询,确认排版已符合预期。
不要只靠猜测坐标或用户口述来修 UI。若截图和 ui.snapshot 不一致,优先相信截图中的最终视觉结果,再用控件树定位可能的布局来源。Canvas 直接绘制的内容不一定出现在 ui.snapshot 中,此时用截图判断视觉问题,用 UI inspector 检查外围 GameUI 容器。
尺寸
csharp
control.Size(200, 100) // 宽高
control.Size(150) // 正方形
control.Width(200)
control.Height(100)
control.AutoWidth() // 自动宽度
control.AutoHeight() // 自动高度
control.AutoSize() // 自动宽高位置
csharp
control.AbsolutePosition(100, 50) // 相对父容器左上角的绝对定位
control.RelativeOffset(10, 20) // 相对正常排版位置的偏移
control.Position(100, 50) // 只改坐标,保留当前 PositionType;通常不应单独使用对齐
csharp
control.AlignLeft() / .AlignRight() / .AlignTop() / .AlignMiddle() / .AlignBottom()
control.Center()
control.StretchHorizontal() / .StretchVertical() / .Stretch()边距
csharp
control.Margin(10) // 四边均匀
control.Margin(20, 10) // 水平, 垂直
control.Margin(10, 5, 10, 5) // 左, 上, 右, 下
control.Padding(15) // 同上模式流式布局
csharp
control.FlowHorizontal() / .FlowVertical()
control.ContentAlignHorizontal(HorizontalContentAlignment.Left)
control.ContentAlignVertical(VerticalContentAlignment.Top)
control.ContentCenter()
// Flexbox 风格(基于 FlowOrientation 智能选择轴向)
control.JustifySpaceBetween() // 主轴 space-between
control.JustifySpaceAround() // 主轴 space-around
control.AlignSpaceBetween() // 交叉轴 space-between
control.AlignSpaceAround() // 交叉轴 space-around
control.JustifyStretch() // 主轴拉伸
control.AlignStretch() // 交叉轴拉伸
// 组合
control.HorizontalSpread() // = FlowHorizontal + JustifySpaceBetween
control.VerticalSpread() // = FlowVertical + JustifySpaceBetween
// Flex 增长/收缩
control.WidthGrow(1.0f) / .HeightGrow(0.5f) / .GrowRatio(1, 2)
control.WidthShrink(0.5f) / .HeightShrink(0.3f) / .ShrinkRatio(0.5, 0.5)
control.FlexBasis(100, 50) / .FlexBasisWidth(100) / .FlexBasisHeight(50)快速堆叠
csharp
control.VStack(spacing: 10) // 垂直堆叠
control.HStack(spacing: 15) // 水平堆叠控件属性
csharp
control.Visible(true) / .Hidden()
control.Enabled(false) / .Disabled()
control.DataContext(data)
control.Background(Color.Blue) / .Background(brush)
control.Opacity(0.8f)文本控件
先按项目设计分辨率和目标窗口选择字号,详细规则见 UI 字号与可读性。
FontSize是设计坐标单位,会随整个画布缩放;默认 1920×1080 画布在 1280×720 窗口中,16 只对应约 10.7 屏幕像素。不要照搬 App 的 12–16 DIP/sp 正文习惯。- 默认画布的桌面 720p 起点:正文/按钮 24–28,辅助文字 20–24,标题 36–48。按最小目标窗口和实际移动设备截图调整,不把此范围当成所有平台的硬编码标准。
- 不依赖兼容默认字号或
DesignTokens.BaseFontSize保证正文可读;不要再手动乘DevicePixelRatio。放大字号时同步调整框体和间距,长说明用受约束的宽度、换行与自动高度。 - 验收必须覆盖短文本更新为长文本;不要通过
Shrink或改全局设计分辨率掩盖小字或溢出。
csharp
label.Text("Hello").TextColor(Color.Red).FontSize(26).Bold().Italic()
button.Text("按钮").TextColor(Color.White).FontSize(26).Bold()需要在一个 Label 中混排粗体、颜色、换行或局部可点击文字时,使用 Label.Text 富文本标签和 Label.OnLinkClicked,并先阅读 label-rich-text。
TextWrap 已开但不换行或被裁剪
TextWrap 控制文字换行,不建立 Label 的宽度约束。父面板有固定宽度,也不保证 AutoWidth 子 Label 在测量时收到该宽度;自然宽度可能仍按整段文本测量。详细示例和排查见流式布局指南。
- 在有限宽度的垂直流式容器中,优先用
.AutoWidth().StretchHorizontal().AutoHeight().TextWrap();AutoWidth 清除模板的显式宽度,横向拉伸才可在该容器的交叉轴上生效。固定文本列也可用.Width(...).AutoHeight().TextWrap()。不要把横向拉伸套用到所有布局方向。 - 完整说明用换行与自动高度,父容器应能增高或滚动;固定高度可能已经换行但把后续行裁掉。
TextTrimming.Clip可作绘制边界兜底,不能建立宽度约束,也不能代替多行空间。标题/列表按用途选择 Ellipsis,短计分牌才考虑 Shrink;不要手工截字或插入换行来掩盖布局问题。 - 用
ui.find、ui.snapshot/ui.get_rect核对目标 Label 与父内容区的rect_px,考虑 Padding/Margin 与画布缩放。不要把设计坐标的 Width/Padding 直接与屏幕像素相减。截图同时用于判断实际换行与裁剪;尺寸本身不能证明没有引擎 bug。 - 存在多个 Gameplay 时按 Runtime 路由说明 发现并固定目标,再进行整条 UI 检查。重新开局后重新发现目标。调试启动和 DLL 部署沿用项目的调试工具流程,不为仅客户端 UI 改动强制替换两端 DLL。
- 验收短文本 → 超出可用宽度的长文本 → 短文本:宽度保持约束,高度按内容增减(考虑 MinHeight/固定高度等显式限制),父布局同步更新。不要只验证启动文案。
- 如果实际有限宽度、换行和高度策略已正确,却仍不换行或动态更新后尺寸不变,保留复现与运行时数据,继续检查模板覆盖、控件类型、富文本、字体度量及布局失效通知;此时仍可能是实现 bug,不要通过每帧强制刷新绕过。
自定义字体
Label.Font / Input.Font / TextButton.Font 传的是字体 family,不是 .ttf / .otf 文件路径。自定义字体不生效时,优先读取 ui-custom-font。
项目私有字体示例:
text
res/font/my_title/my_title.ttf
ref/fontref.txt: font/my_titlecsharp
#if CLIENT
var label = UI.Label("标题");
label.Font = "font/my_title"u8;
label.FontSize = 32;
#endif新增或修改 ref/fontref.txt 后需要重新进入地图。当前版本先手写维护字体 ref;未来可能会有类似资源收集工具的字体 ref 自动收集工具。
容器
csharp
container.AddChild(child).AddChildren(child1, child2, child3)页面级界面优先使用 UI.Page() 作为根容器:
csharp
var page = UI.Page(
UI.ScrollableVStack(16,
UI.Title("设置"),
UI.Label("这里放页面内容")
).FillParent()
).AddToRoot();Page天生占满 viewport,不需要再调用FullScreen()。- 需要滚动时,在
Page内部放ScrollableVStack、ScrollPanel等可滚动容器。 FillParent()仍然用于页面内部的嵌套容器,而不是定义页面本身的语义。
事件
csharp
button.OnClick((sender, e) => { /* 逻辑 */ })
button.OnClick(() => { /* 简化 */ })外观样式
csharp
control.CornerRadius(8)
control.ZIndex(10)
control.Opacity(0.8f)
control.ClipContent() // 裁剪超出内容
control.NoClip() // 允许内容溢出
control.MinWidth(100).MaxWidth(300).MinHeight(50).MaxHeight(200)图片翻转限制
ImageFlipX、ImageFlipY 以及 .Flip()、.FlipX()、.FlipY() 只对支持图片渲染的控件生效。不要对 PanelScrollable 使用这些属性或扩展方法:它的底层滚动控件不支持图片翻转,扩展方法会记录警告。需要翻转图片时请创建普通 GameUI.Control.Primitive.Panel,例如 new Panel { Image = "icons/arrow.png", ImageFlipX = true }。
UI.Panel() 是便捷构建器,当前返回 PanelScrollable(并关闭滚动);因此需要图片翻转时不要把 UI.Panel() 当作普通 Panel,应显式创建 new Panel()。
UI 序列帧
加载动画、按钮光效、头像框、面板装饰等简单 UI 序列帧优先使用 Sprites 控件。普通单图 sprite sheet 要配置 .SpriteSheet(frameWidth, frameHeight, frameCount, framesPerRow);文件夹序列通常只需要设置 .Image(...)、播放速度和 Play()。
需要 2D 角色、命名动画、图层、命中框或 Canvas 游戏循环时,改用 AnimatedImageSource + CanvasAnimated。详细选型见 ui-sprite-animation。
响应式设计
csharp
control.ResponsiveWidth(100, 300) // min, max
control.ResponsiveHeight(50, 150)
control.ResponsiveSize(100, 300, 50, 150) // wMin, wMax, hMin, hMax
label.ResponsiveFontSize(12, 24, 1.2f) // min, max, multiplier
control.ResponsiveSpacing(8, 24)
control.ResponsivePadding(12, 32)
control.ResponsiveContainer(ResponsiveContainerSize.Standard)
button.ResponsiveButton(ResponsiveButtonSize.Medium)
container.ResponsiveOrientation(Orientation.Horizontal, Orientation.Vertical)
control.ResponsiveVisibility(ResponsiveVisibility.MediumAndUp)屏幕尺寸变化与 viewport 事件
需要在窗口缩放、屏幕旋转、DPI 或移动端安全区变化后重新布局时,优先订阅 ScreenViewport.Primary.OnViewportChanged。该事件在 WidthPx、HeightPx、Size、 DisplayOrientations、DevicePixelRatio、SafeZonePadding 和 GlobalOffsetPx 完成更新后触发; 同尺寸的 Surface 重建也会经过这条通知链路。
csharp
#if CLIENT
var viewport = ScreenViewport.Primary;
void RefreshLayout()
{
var contentWidth = viewport.Size.Width;
var safe = viewport.SafeZonePadding;
// 更新已有控件,不要在每次回调中重复创建整棵 UI 树。
contentPanel.Padding = new Thickness(safe.Left, safe.Top, safe.Right, safe.Bottom);
contentPanel.Width = contentWidth;
}
viewport.OnViewportChanged += RefreshLayout;
RefreshLayout(); // 首次订阅后主动按当前状态布局
#endif使用边界:
- 只关心物理像素宽高时可订阅
OnSizeChanged;只关心横竖屏时可订阅OnOrientationChanged。需要保证整体布局正确时使用统一的OnViewportChanged。 - 回调中直接读取 viewport 当前属性,不要依赖事件参数中的旧尺寸;框架会先更新状态,再触发事件。
- 通过事件更新已有控件,保持操作幂等;页面根优先使用
UI.Page()/.FillParent()和响应式布局,避免把固定像素坐标当作全屏布局方案。 - 同尺寸 Surface 重建通知从客户端能力版本
4开始可用。旧客户端仍会通知实际 drawable 尺寸变化,但不会保证同尺寸重建单独触发回调。 - 页面或系统销毁时解除订阅,避免长期持有已销毁控件;如果同一页面会重复进入,确保订阅和解除订阅成对出现。
高级布局
csharp
// 网格
var grid = TrueGrid(3, rowSpacing: 8, columnSpacing: 12, child1, child2, ...);
var autoGrid = SimpleGrid(10, item1, item2, ...);
// 语义化组件
control.Card(padding: 20, radius: 8, elevation: 2)
button.Button(height: 44, padding: 16, radius: 4)
input.Input(height: 40, width: 280, padding: 12)
item.ListItem(height: 48, padding: 16)
// 文本样式
label.Title(fontSize: 24, margin: 16)
label.Subtitle(fontSize: 18, margin: 12)
label.Body(fontSize: 16, margin: 8)
label.Caption(fontSize: 12, margin: 4)静态构建器
csharp
var page = UI.Page();
var panel = UI.Panel();
var button = UI.Button();
var label = UI.Label("Hello");
var vstack = UI.VStack(spacing: 10,
UI.Label("标题"),
UI.Button(),
UI.Label("底部")
);
var hstack = UI.HStack(spacing: 15, UI.Button(), UI.Label("说明"));
var centered = CenterContainer(UI.Label("居中文本"));
// 预定义样式
UI.Title("标题", size: 24)
UI.Subtitle("副标题", fontSize: 18)
UI.Primary("主要按钮")
UI.Secondary("次要按钮")
UI.Button("按钮")内置颜色
csharp
UI.Colors.Primary / .Secondary / .Success / .Warning / .Error
UI.Colors.Background / .Surface
UI.Colors.OnPrimary / .OnSurface / .OnBackground使用示例
登录界面
csharp
var loginScreen = Page(
VStack(20,
Label("欢迎登录")
.FontSize(32).Bold().Center().Margin(0, 50, 0, 30),
VStack(15,
Label("用户名").Background(Colors.Surface).Padding(15, 10).StretchHorizontal().Height(40),
Label("密码").Background(Colors.Surface).Padding(15, 10).StretchHorizontal().Height(40)
).Margin(40, 0),
HStack(20,
Button().Size(120, 40).Background(Colors.Secondary),
Button().Size(120, 40).Background(Colors.Primary)
).Center().Margin(0, 30, 0, 0)
).FillParent().Background(Colors.Background)
).AddToRoot();工具栏
csharp
var toolbar = Panel().Size(400, 50)
.HorizontalSpread()
.Add(Button("新建"), Button("编辑"), Button("删除"), Button("设置"));更多详细信息
更多 API 与组合示例见 reference.md。