How to get an NSStackView as accessory view to NSAlert?

901 views Asked by At

I'm writing an app with Swift on macOS. I want to create an NSAlert with a vertical NSStackView that will let the user pick one out of N options. To do that, I hook up my NSStackView in the accessoryView property of my NSAlert, and for some reason my Radio Buttons don't show.

Here's what I've tried so far:

let a = NSAlert()
a.messageText = "Dummy1"
a.informativeText = "Dummy2"
a.addButton(withTitle: "OK")

let rb = NSButton(radioButtonWithTitle: "Foo", target: nil, action: nil)
a.accessoryView = rb

a.runModal()

This shows me my NSAlert with one radio button labelled Foo. So the accessory view seems to work.

Now I place the radio button in a StackView:

let a = NSAlert()
a.messageText = "Dummy1"
a.informativeText = "Dummy2"
a.addButton(withTitle: "OK")

let rb = NSButton(radioButtonWithTitle: "Foo", target: nil, action: nil)
let vsv = NSStackView()
vsv.orientation = NSUserInterfaceLayoutOrientation.vertical
vsv.distribution = NSStackViewDistribution.equalSpacing
vsv.alignment = .leading
vsv.isHidden = false
vsv.addView(rb, in: .center)

a.accessoryView = vsv

a.runModal()

Now the radio button doesn't appear anymore. Adding more radio buttons in the StackView doesn't help either.

1

There are 1 answers

0
kainjow On

I was able to get this working but I didn't setup any constraints since I just needed a fixed size. Here's an example that stacks two text fields with a fixed width:

func makeAccessoryView(usernameField: NSTextField, passwordField: NSTextField) -> NSView {
    let stackView = NSStackView(views: [usernameField, passwordField])
    let width = 300
    let height = usernameField.frame.height + stackView.spacing + passwordField.frame.height
    stackView.setFrameSize(NSSize(width: width, height: height))
    stackView.translatesAutoresizingMaskIntoConstraints = true
    stackView.orientation = .vertical
    return stackView
}

// somewhere else...
let usernameField = NSTextField(...)
let passwordField = NSTextField(...)
alert.accessoryView = makeAccessoryView(usernameField: usernameField, passwordField: passwordField)