I have been trying to display a custom NSMenuItem (for a preview page of a menu manager) inside a SwiftUI view. But I can't achieve it. I have figured it needs to wrapped inside a menu first, and thought that there might be a way to pop the menu pragmatically but sadly, those efforts have failed and the app crashes.
So far, my code looks like this:
import Foundation
import SwiftUI
struct NSMenuItemView: NSViewRepresentable {
func makeCoordinator() -> Coordinator {
return Coordinator(self)
}
func makeNSView(context: Context) -> NSView {
let view = NSView()
let menu = NSMenu()
let item = menu.addItem(withTitle: "Do Action", action: #selector(Coordinator.valueChanged(_:)), keyEquivalent: "")
item.target = context.coordinator
view.menu = menu
return view
}
func updateNSView(_ view: NSView, context: Context) {
// App crashes here :/
view.menu?.popUpMenuPositioningItem(
positioning: view.menu?.item(at: 0),
at: NSPoint(x: 0, y: 0),
in: view
)
}
}
extension NSMenuItemView {
final class Coordinator: NSObject {
var parent: NSMenuItemView
init(_ parent: NSMenuItemView) {
self.parent = parent
}
@objc
func valueChanged(_ sender: NSMenuItem) {
}
}
}
Am I missing something here? Is it even possible to just pragmatically display NSMenuItem?
The NSMenu comfors to NSViewRepresentable so I figured it might just workout, and have seen answers on StackOverflow (granted date a while back) showing similar code that should work.
Without the popUpMenuPositioningItem it works - in a way I guess - when I right click in the View, the MenuItem Appears. But I would like to be able to display the menu without the right click, just like that.
The problem is that the menu is shown while the view are still rendering so that the crash happens. To avoid this you should call
popUp(positioning:at:in)after the your view appears on the screen. The way to achieve it, we have to use publisher to trigger an event to show menu insideonAppearmodifier and listen it insideCoordinator. Here is the sample for that solution.I hope it will help you to get what you want.