关于 window-management
面向开发者的技能,用于在 macOS 15 及更高版本中按用途定制 SwiftUI 窗口。它指导场景选择、窗口外观、行为与位置设置,并建议仅在 SwiftUI 修饰符无法满足需求时桥接 AppKit。
主要功能
- 01按窗口用途选择场景
- 02自定义工具栏与标题
- 03配置拖动区域和材质
- 04设置恢复与启动行为
- 05控制初始位置和缩放布局
- 06检查窗口可用性
适用场景
- 01设计实用工具或关于窗口
- 02定制媒体播放器窗口
- 03选择窗口恢复行为
- 04按显示器尺寸设置窗口大小
安装
复制下面的命令,在终端中运行。
$
npx skills add https:/ / github.com/ openai/ plugins --skill window-management安装后在 Claude Code 中输入/window-management确认已加载。
附带文件agents/openai.yamlreferences/api-snippets.md
详细介绍
窗口管理
概览
使用此技能,让每个 SwiftUI 窗口都适合其用途。首先确定哪个场景拥有该窗口(Window、WindowGroup 或专用工具场景),然后自定义工具栏/标题区域、背景材质、调整大小与恢复行为,以及初始位置或缩放后的位置。
如果 SwiftUI 能直接提供所需行为,优先使用场景和窗口修饰符,而不是临时搭建 AppKit 桥接。让每个窗口各司其职:主浏览窗口、“关于”窗口和媒体播放器窗口通常需要不同的窗口装饰、可调整大小设置、恢复规则和位置规则。
这些是 macOS 15+ 的 SwiftUI 窗口/场景自定义 API。对于较早的部署目标,预计需要使用更多 AppKit 桥接或可用性检查。
工作流
- 检查相关的场景声明,并确定窗口用途:主应用导航、检查器/详情工具窗口、“关于”/支持窗口、媒体播放窗口、欢迎窗口或无边框自定义界面。
- 调整工具栏和标题的显示方式,使其与内容相符。
- 如果隐藏了工具栏背景或整个工具栏,请确保窗口仍有可用的拖动区域。
- 根据窗口用途调整行为:最小化是否可用、恢复规则、调整大小的预期,以及窗口是否应在启动时出现。
- 为新打开的窗口设置默认位置,并在内容和显示器尺寸很重要时,为缩放行为设置理想位置。
- 使用
build-run-debug构建并启动应用,在真实的前台.app捆绑包中验证结果。 - 如果 SwiftUI 场景/窗口修饰符无法满足需求,请改用
appkit-interop,通过精简的NSWindow桥接实现,而不是让 AppKit 代码遍布整个视图树。
工具栏与标题
- 当窗口标题应继续与窗口关联,以便用于辅助功能和菜单,但不应在标题栏中可见时,使用
.toolbar(removing: .title)。 - 当大型媒体内容或主视觉内容需要在视觉上延伸至窗口顶部边缘时,使用
.toolbarBackgroundVisibility(.hidden, for: .windowToolbar)。 - 如果窗口仍需关闭/最小化/全屏控制按钮,只移除标题和工具栏背景。如果要彻底隐藏工具栏,则改用
.toolbarVisibility(.hidden, for: .windowToolbar)。 - 在叠加新的 SwiftUI 工具栏 API 之前,移除自定义工具栏背景和手绘的标题栏填充。
- 即使标题隐藏,也应让窗口的逻辑标题具有明确含义;系统仍可将其用于辅助功能和菜单项。这些变化仅影响视觉呈现。
拖动区域
- 如果隐藏了工具栏背景或彻底移除了工具栏,请使用
WindowDragGesture()将可拖动区域延伸到内容区域。 - 将手势附加到透明叠加层或非交互式标题区域,避免拦截实际控件的手势。
- 对于带有自定义播放控制的媒体播放器,请将拖动叠加层置于视频内容和控制项之间,以便 AVKit 或传输控制项继续接收输入。
- 将拖动手势与
.allowsWindowActivationEvents(true)配合使用,以便点击并立即拖动后台窗口时,窗口仍会激活并移动。
背景与材质
- 当工具窗口或“关于”窗口应以微妙的磨砂材质替代默认窗口背景时,使用
.containerBackground(.thickMaterial, for: .window)。 - 为风格化窗口优先使用系统材质,而不是硬编码半透明颜色。
- 对于固定内容的工具窗口,如果柔和的背景是设计的一部分,更应使用这种方式。
窗口行为
- 对于始终易于访问的实用工具窗口(例如自定义“关于”窗口),使用
.windowMinimizeBehavior(.disabled),因为最小化几乎没有价值。 - 当窗口内容只有一种预期尺寸时,通过固定尺寸或窗口约束禁用绿色缩放控件。
- 对于不应在下次启动时重新打开的窗口(例如“关于”面板、临时支持/信息窗口或首次运行欢迎界面),使用
.restorationBehavior(.disabled)。 - 对于主要文档窗口或导航窗口,如果重新打开时恢复之前的尺寸和位置更理想,则应启用状态恢复。
- 默认情况下,SwiftUI 会遵循用户在 macOS 系统范围内设置的状态恢复选项。只有当特定窗口需要有意选择遵循或不遵循此系统行为时,才使用
restorationBehavior(...)。 - 对于应在启动时首先显示的窗口(例如欢迎窗口),使用
.defaultLaunchBehavior(.presented),并有意选择此行为,而不要依赖场景创建顺序产生的副作用。
窗口放置
- 使用
.defaultWindowPlacement { content, context in ... }控制新打开窗口的初始尺寸和可选位置。 - 在放置闭包中,调用
content.sizeThatFits(.unspecified)获取内容的理想尺寸。 - 读取
context.defaultDisplay.visibleRect,获取扣除菜单栏和 Dock 后显示器的可用区域。 - 如果媒体或文档内容可能大于显示器,则返回尺寸限制在可见区域内的
WindowPlacement(size: size)。如果未提供位置,窗口默认居中。 - 使用
.windowIdealPlacement { content, context in ... }控制用户从“窗口”菜单选择“缩放”或按住 Option 键并点按绿色工具栏按钮时的行为。对于媒体窗口,应保持宽高比,并扩展到显示器所能容纳的最大尺寸。 - 将默认放置和理想放置视为两种独立策略:
- 默认放置控制新窗口首次出现的位置;
- 理想放置控制缩放后的窗口应达到多大。
- 根据内容尺寸调整播放器窗口或文档窗口时,始终考虑外接显示器以及旋转或较窄的屏幕。
无边框和专用窗口
- 对于无边框或高度自定义窗口装饰的窗口,使用
.windowStyle(.plain),但应确保内容提供清晰的拖动操作区域和可见上下文。 - 对于无边框播放器、HUD 或欢迎窗口,应事先决定,失去标准标题栏操作是否值得换取自定义呈现方式。
- 如果普通样式让窗口变得不明显或难以移动,应保留一条清晰的路径,以便恢复常规窗口管理方式。
如需查看具体的窗口修饰符示例,请阅读 references/api-snippets.md。
审查清单
- 场景类型与窗口的用途和生命周期相匹配。
- 隐藏标题后,仍保留有意义的逻辑标题,以供辅助功能和菜单使用。
- 移除工具栏背景是有意为之,且不会影响标题栏的易读性或窗口控件的位置。
- 隐藏或移除工具栏的窗口仍具有可靠的拖动区域,并支持从背景处点按后拖动来激活窗口。
- 实用工具窗口的恢复和最小化行为符合其用途。
- 仅当场景需要有意区别于用户的系统范围设置时,才覆盖恢复行为。
- 当内容尺寸和显示器尺寸会产生影响时,默认放置和理想放置会使用
content.sizeThatFits(.unspecified)和context.defaultDisplay.visibleRect。 - 媒体窗口保持宽高比,并能适应较小或旋转的显示器。
- 无边框窗口仍提供可用的移动/拖动操作区域。
注意事项
- 不要只为隐藏忘记设置的标题而使用
.toolbar(removing: .title)。 应确保底层窗口标题有意义。 - 不要隐藏工具栏背景或整个工具栏,除非同时提供替代的拖动操作方式。
- 除非用户明确希望应用每次启动时都从头开始,否则不要对主文档/导航窗口禁用恢复功能。
- 调整播放器窗口大小时,不要将某一种显示器尺寸写死,也不要假设只有一个显示器。
- 在尝试修改
NSWindow之前,先检查.windowMinimizeBehavior、.restorationBehavior、.defaultWindowPlacement、.windowIdealPlacement、.windowStyle或.defaultLaunchBehavior是否已能解决问题。 - 不要留下没有明显拖动或关闭方式的纯无边框窗口。
何时使用其他技能
- 对于更广泛的场景、命令、设置、侧边栏和检查器架构,请使用
swiftui-patterns。 - 如果主要问题涉及现代 macOS 视觉设计、Liquid Glass 或采用系统材质,请使用
liquid-glass。 - 如果自定义窗口行为确实需要
NSWindow、NSPanel或响应者链控制,请使用appkit-interop。 - 要启动并验证生成的窗口,请使用
build-run-debug。
评论
支持 Markdown