Shaft多窗口终极指南:用SubWindow快速创建独立原生窗口
【免费下载链接】ShaftA cross-platform GUI framework for Swift, built for demanding workloads and developer ergonomics项目地址: https://gitcode.com/gh_mirrors/sh/Shaft
Shaft 是一个面向 Swift 的跨平台 GUI 框架,而它的SubWindow组件正是多窗口开发的利器——只需几行代码,就能为主窗口之外弹出独立运行的原生窗口,每个窗口拥有独立的控件层级,互不干扰。
如图所示,Shaft 可以同时在屏幕上运行多个独立窗口,它们各自渲染不同的页面内容,这就是SubWindow提供的原生多窗口能力。
什么是 Shaft 的 SubWindow?
SubWindow是一个StatefulWidget,它在被渲染时会自动通过后端(Shaft.Backend)创建一个新的原生视图,并把子控件渲染进去。你可以把它理解为:主窗口里的一个按钮,点一下就能开一个新窗口——而且新窗口完全由框架托管,无需手写平台代码。
它的核心定义位于 View.swift:
public final class SubWindow: StatefulWidget { public init( onCreateWindow: OnCreateWindow? = nil, onWindowCreated: OnWindowCreated? = nil, onWindowDestroyed: OnWindowDestroyed? = nil, @WidgetBuilder child: () -> Widget ) }三个回调各司其职:
| 回调 | 触发时机 | 典型用途 |
|---|---|---|
onCreateWindow | 窗口创建前 | 自定义创建逻辑,返回已有原生视图 |
onWindowCreated | 窗口创建成功后 | 设置标题、大小、位置等属性 |
onWindowDestroyed | 窗口销毁前 | 保存状态、清理资源 |
一键创建独立原生窗口
创建子窗口最简单的写法,就是把内容包进SubWindow即可。官方示例见 Demo_MultiWindow.swift:
SubWindow( onWindowCreated: { view in if let view = view as? DesktopView { view.title = "My Window" view.size = .init(400, 400) } } ) { Text("Sub Window 1") .center() .background(.init(0xFFFF_FFFF)) }这段代码会在主界面下方弹出一个 400×400 的独立窗口,里面居中显示一行文字。子窗口渲染时会通过内部的BoxToViewAdapter自动适配布局约束,你写的控件代码和在主窗口中完全一样,无需任何特殊处理。
快速配置窗口属性
在桌面平台上,创建回调返回的视图实现了DesktopView协议(定义见 Backend.swift),你可以在onWindowCreated中直接配置这些属性:
title:窗口标题size/position:窗口大小与左上角位置alwaysOnTop:是否置顶显示visible:窗口是否可见displayID:窗口所在的显示器(支持多屏场景)requestFocus():主动请求键盘焦点
onWindowCreated: { view in if let view = view as? DesktopView { view.position = .init(100, 100) view.alwaysOnTop = true // 悬浮提示窗口常用技巧 } }这套属性让"悬浮通知面板""多屏看板"这类需求都能轻松实现,而且代码完全跨平台——Windows、Linux、macOS 上行为一致。
窗口生命周期回调:创建与销毁
SubWindow帮你管好窗口的整个生命周期,框架内部实现见 View.swift:
initState阶段:调用backend.createView()创建原生窗口,随后触发onWindowCreated;- 渲染阶段:子控件作为新窗口的根内容渲染;
dispose阶段:窗口不再需要时,先触发onWindowDestroyed,再调用backend.destroyView()销毁窗口。
也就是说,只要SubWindow从 widget 树中移除,对应的原生窗口就会自动关闭并释放——不存在窗口泄漏的顾虑。用户手动点掉窗口、或你通过条件渲染移除它,都走同一条清理路径。
自定义窗口创建:onCreateWindow
如果默认创建方式不够用(比如你想复用某个已存在的原生视图),可以实现onCreateWindow回调,手动返回一个NativeView:
SubWindow( onCreateWindow: { // 返回自定义创建的原生视图,返回 nil 则放弃创建 customBackend.createView() } ) { Text("Custom window") }这正是 Shaft 模块化设计的体现:Backend 层抽象了平台差异,你甚至可以为特殊场景(如终端 UI、Wayland 合成器)实现自己的后端。整体分层如下图所示——SubWindow依赖的createView/destroyView就位于Shaft.Backend协议中。
亲自动手:运行官方 Multi Window 演示
想立刻体验?三步即可跑起来:
git clone https://gitcode.com/gh_mirrors/sh/Shaft cd Shaft swift run Playground启动后,在左侧导航栏的Demos分组中点击Multi Window(菜单注册见 main.swift),即可看到子窗口弹出的完整演示,页面内还附带了分步讲解。
💡 小贴士:Playground 应用本身就是一个可交互的文档,每个演示页都包含原理说明和可复制的代码片段。
为什么选择原生多窗口?
- 零平台代码:不写一行 Cocoa 或 Win32,Swift 控件直接渲染进原生窗口;
- 独立渲染:每个窗口拥有独立的 widget 层级与事件循环接入,主窗口卡顿不影响子窗口;
- 生命周期托管:创建、销毁、内存回收全部由框架处理;
- 跨平台一致:同一份代码在 Windows、Linux、macOS 表现相同。
总结
SubWindow让 Shaft 的多窗口开发回归了声明式的简洁:一个组件、三个可选回调、一段普通控件代码,就能弹出可配置的独立原生窗口。无论你是想做一个悬浮面板、弹出式工具窗口,还是多屏协同应用,它都是 Swift 跨平台开发中最省心的多窗口方案。
【免费下载链接】ShaftA cross-platform GUI framework for Swift, built for demanding workloads and developer ergonomics项目地址: https://gitcode.com/gh_mirrors/sh/Shaft
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考