I'm building a toolbar that I want to look at least somewhat like Preview's. I want to create the Previous/Next buttons. The way I THINK it's done is with a segmented control, each has an image in the control. The problem is that I can't figure out how to get the labels underneath. I can get ONE label centered under the whole thing, but labeling the segmented control, But I can't get a Next and a Previous label under each part of the control.
What am I missing here?
thanks.
As @frédéric-blanc pointed out: the only way to achieve this is with NSToolbarItemGroup programmatically.
The trick is to assign both a view and a subitems array to the NSToolbarItemGroup.
let group = NSToolbarItemGroup(itemIdentifier: NSToolbarItem.Identifier(rawValue: "NavigationGroupToolbarItem"))
let itemA = NSToolbarItem(itemIdentifier: NSToolbarItem.Identifier(rawValue: "PrevToolbarItem"))
itemA.label = "Prev"
let itemB = NSToolbarItem(itemIdentifier: NSToolbarItem.Identifier(rawValue: "NextToolbarItem"))
itemB.label = "Next"
let segmented = NSSegmentedControl(frame: NSRect(x: 0, y: 0, width: 85, height: 40))
segmented.segmentStyle = .texturedRounded
segmented.trackingMode = .momentary
segmented.segmentCount = 2
// Don't set a label: these would appear inside the button
segmented.setImage(NSImage(named: NSImage.goLeftTemplateName)!, forSegment: 0)
segmented.setWidth(40, forSegment: 0)
segmented.setImage(NSImage(named: NSImage.goRightTemplateName)!, forSegment: 1)
segmented.setWidth(40, forSegment: 1)
// `group.label` would overwrite segment labels
group.paletteLabel = "Navigation"
group.subitems = [itemA, itemB]
group.view = segmented
If you want to dabble with it, see the sample app code below.

This is all you need to test this in a new macOS/Cocoa sample app:
WindowController.swift and paste this code into it.WindowController.import Cocoa
class WindowController: NSWindowController, NSToolbarDelegate {
var _toolbar: NSToolbar!
let toolbarItems: [[String: Any]] = [
["title" : "irrelevant :)", "icon": "NSPreferencesGeneral", "identifier": NSToolbarItem.Identifier(rawValue: "NavigationGroupToolbarItem")],
["title" : "Share", "icon": NSImage.shareTemplateName, "identifier": NSToolbarItem.Identifier(rawValue: "ShareToolbarItem")],
["title" : "Add", "icon": NSImage.addTemplateName, "identifier": NSToolbarItem.Identifier(rawValue: "AddToolbarItem")]
]
var toolbarTabsIdentifiers: [NSToolbarItem.Identifier] {
return toolbarItems.compactMap { $0["identifier"] as? NSToolbarItem.Identifier }
}
override func windowDidLoad() {
_toolbar = NSToolbar(identifier: "TheToolbarIdentifier")
_toolbar.allowsUserCustomization = true
_toolbar.delegate = self
window?.toolbar = _toolbar
}
func toolbar(_ toolbar: NSToolbar, itemForItemIdentifier itemIdentifier: NSToolbarItem.Identifier, willBeInsertedIntoToolbar flag: Bool) -> NSToolbarItem? {
guard let infoDictionary: [String : Any] = toolbarItems.filter({ $0["identifier"] as? NSToolbarItem.Identifier == itemIdentifier }).first
else { return nil }
let toolbarItem: NSToolbarItem
if itemIdentifier == NSToolbarItem.Identifier(rawValue: "NavigationGroupToolbarItem") {
let group = NSToolbarItemGroup(itemIdentifier: itemIdentifier)
let itemA = NSToolbarItem(itemIdentifier: NSToolbarItem.Identifier(rawValue: "PrevToolbarItem"))
itemA.label = "Prev"
let itemB = NSToolbarItem(itemIdentifier: NSToolbarItem.Identifier(rawValue: "NextToolbarItem"))
itemB.label = "Next"
let segmented = NSSegmentedControl(frame: NSRect(x: 0, y: 0, width: 85, height: 40))
segmented.segmentStyle = .texturedRounded
segmented.trackingMode = .momentary
segmented.segmentCount = 2
// Don't set a label: these would appear inside the button
segmented.setImage(NSImage(named: NSImage.goLeftTemplateName)!, forSegment: 0)
segmented.setWidth(40, forSegment: 0)
segmented.setImage(NSImage(named: NSImage.goRightTemplateName)!, forSegment: 1)
segmented.setWidth(40, forSegment: 1)
// `group.label` would overwrite segment labels
group.paletteLabel = "Navigation"
group.subitems = [itemA, itemB]
group.view = segmented
toolbarItem = group
} else {
toolbarItem = NSToolbarItem(itemIdentifier: NSToolbarItem.Identifier(rawValue: itemIdentifier.rawValue))
toolbarItem.label = (infoDictionary["title"] as? String)!
let iconImage = NSImage(named: (infoDictionary["icon"] as? String)!)
let button = NSButton(frame: NSRect(x: 0, y: 0, width: 40, height: 40))
button.title = ""
button.image = iconImage
button.bezelStyle = .texturedRounded
toolbarItem.view = button
}
return toolbarItem
}
func toolbarDefaultItemIdentifiers(_ toolbar: NSToolbar) -> [NSToolbarItem.Identifier] {
return self.toolbarTabsIdentifiers
}
func toolbarAllowedItemIdentifiers(_ toolbar: NSToolbar) -> [NSToolbarItem.Identifier] {
return self.toolbarDefaultItemIdentifiers(toolbar)
}
func toolbarSelectableItemIdentifiers(_ toolbar: NSToolbar) -> [NSToolbarItem.Identifier] {
return self.toolbarDefaultItemIdentifiers(toolbar)
}
func toolbarWillAddItem(_ notification: Notification) {
print("toolbarWillAddItem", (notification.userInfo?["item"] as? NSToolbarItem)?.itemIdentifier ?? "")
}
func toolbarDidRemoveItem(_ notification: Notification) {
print("toolbarDidRemoveItem", (notification.userInfo?["item"] as? NSToolbarItem)?.itemIdentifier ?? "")
}
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With