前言

之前的 PromptHub 有个 Setting 页面,用来展示自定义配置的,预期是点击配置按钮,然后希望 Setting 页面可以完整展示

预期效果

但是实际的展示效果是:

实际效果

核心代码的是如下:

.sheet(isPresented: $showingSettings) {
SettingsView(isPresented: $showingSettings, isComeFromSettingPage: false)
.frame(maxWidth: .infinity, maxHeight: .infinity)
}

随后就是 Debug 之路

Sheet && Frame

从实际效果来看,很明显**.frame(maxWidth: .infinity, maxHeight: .infinity)**并没有生效。从上面代码可以看到涉及到两个 modifier:

  1. sheet
  2. frame

所以需要将这两个 modifier 进行逐个拆解,以及组合从而解释目前的现象.

Frame

先说**frame(maxWidth: .infinity, maxHeight: .infinity)**这行代码只是一个倾向性,告诉父视图在允许的情况下尽可能的占据最大的视图尺寸,这种约束其实是最小的,基本上完全由父视图原本的机制决定。在当前场景下,它的父视图是什么?是 sheet 所以剩下要梳理的是,sheet 的视图机制问题了。

Sheet

官方文档链接:sheet(isPresented:onDismiss:content:)

In vertically compact environments, such as iPhone in landscape orientation, a sheet presentation automatically adapts to appear as a full-screen cover.

即在垂直空间受限的环境中,例如横向模式下的 iPhone,sheet 视图的呈现方式会自动调整为全屏覆盖。不过我们这里是在 macOS 下,Sheet 默认情况下的尺寸大小完全由内容尺寸决定,如果有理想尺寸则由其决定。

回到示例中,SettingsView 并没有设置idealWidthidealHeight, 所以最终还是由SettingsView 的内容尺寸决定。所以这里问题最终回到了SettingsView视图问题

Screenshot 2025-04-20 at 15 09 45

SettingsView

NavigationView {
...
}
NavigationView

NavigationView 在 macOS 10.15–15.4 已经被废弃了,这就可能出现问题的原因吧,甚至有建议把 NavigationView 放到 sheet 下就可以正常工作,并没有去尝试。

.sheet(isPresented: $showSheet) {
  NavigationView {
  
  }
}

当切换到NavigationSplitView基本能够符合预期的工作,但是由于 sheet 的原因会根据内容尺寸去变化大小,在 SettingsView 里俩个标签页大小不一致,所以窗口大小会在切换的时候变化,为了保持一致性,最终使用了另外一种方法,这都是后话了。

最后

和流程图说的那样,如果 Frame 是固定尺寸的话,其实也是可以正常工作的,但是固定尺寸并不灵活,所以在实际休修复这个问题的时候,我也没有去考虑。

参考文档

  1. NavigationView
  2. Navigationsplitview
  3. sheet(isPresented:onDismiss:content:)