如何将 SwiftUI 按钮放入 NSToolbar?

How to put SwiftUI button into NSToolbar?

这是使用辅助视图控制器将 SwiftUI 插入 NSToolbar 的方式:

import SwiftUI
import PlaygroundSupport

var hostingView = NSHostingView(rootView:
  ZStack {
    Color.clear
    HStack {
      Text("Hey")
      Text("SwiftUI")
    }
  }
  .padding()
  .edgesIgnoringSafeArea(.all)
)
hostingView.frame.size = hostingView.fittingSize

let titlebarAccessory = NSTitlebarAccessoryViewController()
titlebarAccessory.view = hostingView
titlebarAccessory.layoutAttribute = .trailing

let mask: NSWindow.StyleMask = [.titled, .closable, .miniaturizable, .resizable]
let window = NSWindow(
  contentRect: .init(x: 0, y: 0, width: 480, height: 300),
  styleMask: mask, backing: .buffered, defer: false)
window.center()
window.contentView = NSHostingView(rootView: Color(.windowBackgroundColor))
window.toolbar = .init()
window.titleVisibility = .hidden
window.addTitlebarAccessoryViewController(titlebarAccessory)

PlaygroundPage.current.liveView = window.contentView?.superview

上面的代码确实有效:

但是如果我们插入一个按钮:

HStack {
  Text("Hey")
  Button(action: {}) {
    Text("SwiftUI")
  }
}

它不会按预期工作:

有什么建议吗?

P。 S. 这是一个可行的解决方案:

HStack {
  Text("Hey")
    .offset(x: 0, y: -1)
  Button(action: {}) {
    Text("SwiftUI")
      .offset(x: 0, y: -7)
  }
}
.font(.caption)

将我的评论作为每个请求的答案发布。不一定是可靠的解决方案,但作为解决方法,您可以使用

Text("SwiftUI")
  .padding(EdgeInsets(top: -7, leading: 0, bottom: 0, trailing: 0))

.offset 在按钮的文本上。无法保证该解决方案将持续多长时间。

工具栏项目更垂直 space。要修复该问题,请使用 Spacer 视图,它将按钮推到顶部:

VStack {
  Button(action: {}) {
    Text("Text")
  }.frame(height: 22)

  Spacer()
}

我最终处理它的方式(当用户使 window 全屏并且不管内容的高度*如何时它也能工作)如下所示。请注意,我在使用最新 Xcode 版本构建的 macOS 应用程序的 NSTitlebarAccessoryViewController 中的 NSHostingView 中使用工具栏视图(显然,在 macOS Catalina 上)。

重要的事情:*你仍然需要为框架设置一个固定的高度(但至少你不会依赖于 "variable" -7)并且仅将实际高度的一半偏移到顶部当有安全区域顶部插入时(在全屏模式下,显然不是),因此 GeometryReader 是必须的:

struct Toolbar : View {
    var body: some View {
        GeometryReader { geometry in
            VStack {
                Text("1st row")
                Text("2nd row")
            }
            .offset(y: geometry.safeAreaInsets.top > 0 ? -geometry.size.height / 2 : 0)
        }
        .frame(height: 42)
    }
}

以及创建 window 的位置:

let toolbar = NSHostingView(rootView: Toolbar())
toolbar.frame.size = toolbar.fittingSize
let toolbarController = NSTitlebarAccessoryViewController()
toolbarController.view = toolbar
window.addTitlebarAccessoryViewController(toolbarController)

似乎对按钮应用 PlainButtonStyle 有帮助。 默认样式正在做一些奇怪的魔术,破坏了 NSToolbar 中的布局。