Search code examples
swiftmacosswiftuiappkit

How to control a menu programmatically in SwiftUI on macOS?


I'm writing a ComboBox in SwiftUI on macOS and want to control it programmatically in a flexible way, rather than click on the button and the list shows.

I can use Menu to create a naive menu referring to Apple Developer - Menu, but cannot find any approach to programmatically control it, like showing or hiding its list.

Then I tried to custom one with a List like shown below. But when that list shows, it takes place and pushes other views down, which doesn't behave like a default system Menu that floating in front of following views.

VStack {
    TextField("Ttitle", text: $string) { isEditing in
        onEditing = isEditing
    }
    if onEditing { List(listItems, id:\.self) { Text($0) } }
}

It couldn't be better if there's a method like this, but it not exists.

SomeViewHere()
    .menu(isPresented: $showMenu) {
        Button("A") {}
        Button("B") {}
        Button("C") {}
    }

Also, I found a post here, but it only works on iOS.

I'm not familiar with AppKit, so I don't know if a solution exists there. But I'm also glad if AppKit works and willing to learn it. Anyway, I always prefer to use native SwiftUI. So, any ideas of how to achieve that?


Solution

  • Referred to this post and this post, I figured out how to bring the floating list into life. An example custom one are shown below.

    @State var showList: Bool = false
    
    var body: some View {
    
        Button("Click Me") { showList.toggle() }
        .frame(width: 100, height: 20)
        .overlay {
            if showList {
                List {
                    Button("AA") {}
                    Button("AA") {}
                    Button("AA") {}
                }
                .frame(width: 200, height: 300)
                .offset(y: 160)
            }
        }
        .zIndex(1)
        
        Text("Hello World")
        Circle().fill(.brown).frame(width: 50, height: 50)
    }