How to put SwiftUI button into NSToolbar?

为君一笑 提交于 2020-05-13 03:46:41

问题


This is how SwiftUI can be inserted into NSToolbar using an accessory view controller:

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

The code above does work:

If we insert a button however:

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

It would not work as expected:

Any suggestions?

P. S. This is a working solution:

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


回答1:


Posting my comment as an answer per request. Not necessarily a reliable solution but as a workaround you can use

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

or .offset on the Text in the button. No guarantees on how long that will last as a solution.




回答2:


The way I eventually handled it (making it work also when the user makes the window full screen AND regardless of the height* of the content) is below. Note that I'm using Toolbar view in an NSHostingView within NSTitlebarAccessoryViewController of a macOS app built with most recent Xcode version (obviously, on macOS Catalina).

Important things: *you still need to setup a fixed height for the frame (but at least you won't rely to the "variable" -7) and offset to top by half of the actual height ONLY when there is safe area top inset (in full screen mode, apparently, it isn't) and therefore GeometryReader is a must:

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)
    }
}

and where window is created:

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



回答3:


Toolbar item has more vertical space. To fix that use Spacer view it will push the button to the top:

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

  Spacer()
}


来源:https://stackoverflow.com/questions/58518610/how-to-put-swiftui-button-into-nstoolbar

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!