我正在开发具有
.window
风格的 MenuBarExtra。我知道我可以使用硬编码值或通过存储的变量来设置帧大小。
是否可以通过拖动边缘来调整窗口大小?
我认为 SwiftUI 不支持这一点,所以你必须使用一些 AppKit API。
创建一个
NSViewRepresentable
,并访问自定义 window.styleMask
中的 NSView
属性。只需在其中插入 .resizable
标志即可,
struct Helper: NSViewRepresentable {
class HelperView: NSView {
override func viewWillMove(toWindow newWindow: NSWindow?) {
super.viewWillMove(toWindow: newWindow)
Task {
newWindow?.styleMask.insert(.resizable)
}
}
}
func makeNSView(context: Context) -> HelperView {
HelperView()
}
func updateNSView(_ nsView: HelperView, context: Context) {
}
}
MenuBarExtra("Foo") {
ZStack {
Helper(width: $width, height: $height)
Text("Bar")
.padding()
.frame(maxWidth: .infinity, maxHeight: .infinity)
}
}
.menuBarExtraStyle(.window)
但是,关闭窗口后不会保留新的大小。如果你想这样做,那就有点复杂了。您需要为自定义
NSView
创建一种方法来告诉 SwiftUI 它已调整到什么大小。
这里我正在使用
didEndLiveResizeNotification
,并更新两个绑定,
struct Helper: NSViewRepresentable {
@Binding var width: Double
@Binding var height: Double
class HelperView: NSView {
var cancellable: AnyCancellable?
var didChangeSize: ((CGSize) -> Void)?
override func viewWillMove(toWindow newWindow: NSWindow?) {
super.viewWillMove(toWindow: newWindow)
Task {
newWindow?.styleMask.insert(.resizable)
}
cancellable = NotificationCenter.default.publisher(for: NSWindow.didEndLiveResizeNotification, object: newWindow)
.sink { [weak self] _ in
self?.didChangeSize?(newWindow?.contentView?.bounds.size ?? .zero)
}
}
}
func makeNSView(context: Context) -> HelperView {
HelperView()
}
func updateNSView(_ nsView: HelperView, context: Context) {
nsView.didChangeSize = {
width = $0.width
height = $0.height
}
}
}
然后你可以像这样使用它:
@State private var height: Double = 100
@State private var width: Double = 100
// ...
MenuBarExtra("Foo") {
ZStack {
Helper(width: $width, height: $height)
Text("Bar")
.padding()
.frame(maxWidth: width, maxHeight: height)
}
}
.menuBarExtraStyle(.window)