【问题标题】:How to put SwiftUI button into NSToolbar?如何将 SwiftUI 按钮放入 NSToolbar?
【发布时间】:2019-10-23 08:26:49
【问题描述】:

这就是如何使用附属视图控制器将 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)

【问题讨论】:

  • 绝对不是一个好的答案,但您可以在按钮中的文本上使用.padding(EdgeInsets(top: -7, leading: 0, bottom: 0, trailing: 0))。不过肯定有问题。
  • @LucasDerraugh 实际上这是一个很好的答案。可以提交吗?
  • @Vadim 我很好奇你为什么使用ZStack。
  • @BijoyThangaraj 在这种特殊情况下感觉不像 H 或 V 那么奇怪 ????
  • 我注意到,当最终用户使窗口全屏显示时,显然不会发生此错误,从而使所有解决方法(尽管它们很丑)都无法使用... :(

标签: cocoa swiftui nswindow appkit nstoolbar


【解决方案1】:

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

重要的事情:*你仍然需要为框架设置一个固定的高度(但至少你不会依赖“变量”-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)
    }
}

以及创建窗口的位置:

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

【讨论】:

    【解决方案2】:

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

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

    或.offset 在按钮中的文本上。无法保证作为解决方案能持续多久。

    【讨论】:

    • 不幸的是,当/如果用户使窗口全屏时,这可能仍然不起作用。此外,-7 值是“可变的”,取决于实际视图的高度。
    • 就像我说的,更多的是一种解决方法而不是解决方案。我被要求发表我的评论作为答案。
    【解决方案3】:

    工具栏项有更多的垂直空间。要解决这个问题,使用 Spacer 视图会将按钮推到顶部:

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

    【讨论】:

    • 这是可行的,除非附件视图下方有一个实际的工具栏按钮,否则辅助功能 API 无法访问它(正如您通过在其上运行辅助功能检查器所看到的那样),这会阻止辅助设备无法访问这些按钮。
    【解决方案4】:

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

    【讨论】:

      猜你喜欢
      • 2020-12-18
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-02-04
      • 2013-11-08
      • 1970-01-01
      • 1970-01-01
      • 2021-07-28
      相关资源
      最近更新 更多