开源软件名称(OpenSource Name):sindresorhus/Preferences开源软件地址(OpenSource Url):https://github.com/sindresorhus/Preferences开源编程语言(OpenSource Language):Swift 98.7%开源软件介绍(OpenSource Introduction):Preferences
Just pass in some view controllers and this package will take care of the rest. Built-in SwiftUI support. This package is compatible with macOS 13 and automatically uses RequirementsmacOS 10.13 and later. InstallAdd UsageRun the First, create some settings pane identifiers: import Preferences
extension Settings.PaneIdentifier {
static let general = Self("general")
static let advanced = Self("advanced")
} Second, create a couple of view controllers for the settings panes you want. The only difference from implementing a normal view controller is that you have to add the
import Cocoa
import Preferences
final class GeneralSettingsViewController: NSViewController, SettingsPane {
let preferencePaneIdentifier = Settings.PaneIdentifier.general
let preferencePaneTitle = "General"
let toolbarItemIcon = NSImage(systemSymbolName: "gearshape", accessibilityDescription: "General settings")!
override var nibName: NSNib.Name? { "GeneralSettingsViewController" }
override func viewDidLoad() {
super.viewDidLoad()
// Setup stuff here
}
} Note: If you need to support macOS versions older than macOS 11, you have to add a fallback for the
import Cocoa
import Preferences
final class AdvancedSettingsViewController: NSViewController, SettingsPane {
let preferencePaneIdentifier = Settings.PaneIdentifier.advanced
let preferencePaneTitle = "Advanced"
let toolbarItemIcon = NSImage(systemSymbolName: "gearshape.2", accessibilityDescription: "Advanced settings")!
override var nibName: NSNib.Name? { "AdvancedSettingsViewController" }
override func viewDidLoad() {
super.viewDidLoad()
// Setup stuff here
}
} If you need to respond actions indirectly, the settings window controller will forward responder chain actions to the active pane if it responds to that selector. final class AdvancedSettingsViewController: NSViewController, SettingsPane {
@IBOutlet private var fontLabel: NSTextField!
private var selectedFont = NSFont.systemFont(ofSize: 14)
@IBAction private func changeFont(_ sender: NSFontManager) {
font = sender.convert(font)
}
} In the
import Cocoa
import Preferences
@main
final class AppDelegate: NSObject, NSApplicationDelegate {
@IBOutlet private var window: NSWindow!
private lazy var settingsWindowController = SettingsWindowController(
preferencePanes: [
GeneralSettingsViewController(),
AdvancedSettingsViewController()
]
)
func applicationDidFinishLaunching(_ notification: Notification) {}
@IBAction
func settingsMenuItemActionHandler(_ sender: NSMenuItem) {
settingsWindowController.show()
}
} Settings Tab StylesWhen you create the // …
private lazy var settingsWindowController = SettingsWindowController(
preferencePanes: [
GeneralSettingsViewController(),
AdvancedSettingsViewController()
],
style: .segmentedControl
)
// …
APIpublic enum Settings {}
extension Settings {
public enum Style {
case toolbarItems
case segmentedControl
}
}
public protocol SettingsPane: NSViewController {
var preferencePaneIdentifier: Settings.PaneIdentifier { get }
var preferencePaneTitle: String { get }
var toolbarItemIcon: NSImage { get } // Not required when using the .`segmentedControl` style
}
public final class SettingsWindowController: NSWindowController {
init(
preferencePanes: [SettingsPane],
style: Settings.Style = .toolbarItems,
animated: Bool = true,
hidesToolbarForSingleItem: Bool = true
)
init(
panes: [SettingsPaneConvertible],
style: Settings.Style = .toolbarItems,
animated: Bool = true,
hidesToolbarForSingleItem: Bool = true
)
func show(preferencePane: Settings.PaneIdentifier? = nil)
} As with any RecommendationThe easiest way to create the user interface within each pane is to use a SwiftUI supportIf your deployment target is macOS 10.15 or later, you can use the bundled SwiftUI components to create panes. Create a Run the There are also some bundled convenience SwiftUI components, like Tip: The struct CustomPane: View {
var body: some View {
Settings.Container(contentWidth: 450.0) {
Settings.Section(title: "Section Title") {
// Some view.
}
Settings.Section(label: {
// Custom label aligned on the right side.
}) {
// Some view.
}
…
}
}
} Then in the // …
private lazy var settingsWindowController = SettingsWindowController(
panes: [
Pane(
identifier: …,
title: …,
toolbarIcon: NSImage(…)
) {
CustomPane()
},
Pane(
identifier: …,
title: …,
toolbarIcon: NSImage(…)
) {
AnotherCustomPane()
}
]
)
// … If you want to use SwiftUI panes alongside standard AppKit let CustomViewSettingsPaneViewController: () -> SettingsPane = {
let paneView = Settings.Pane(
identifier: …,
title: …,
toolbarIcon: NSImage(…)
) {
// Your custom view (and modifiers if needed).
CustomPane()
// .environmentObject(someSettingsManager)
}
return Settings.PaneHostingController(paneView: paneView)
}
// …
private lazy var settingsWindowController = SettingsWindowController(
preferencePanes: [
GeneralSettingsViewController(),
AdvancedSettingsViewController(),
CustomViewSettingsPaneViewController()
],
style: .segmentedControl
)
// … Backwards compatibilitymacOS 11 and later supports SF Symbols which can be conveniently used for the toolbar icons. If you need to support older macOS versions, you have to add a fallback. Apple recommends using the same icons even for older systems. The best way to achieve this is to export the relevant SF Symbols icons to images and add them to your Asset Catalog. Known issuesThe settings window doesn't showThis can happen when you are not using auto-layout or have not set a size for the view controller. You can fix this by either using auto-layout or setting an explicit size, for example, There are no animations on macOS 10.13 and earlierThe FAQHow can I localize the window title?The
Why should I use this instead of just manually implementing it myself?It can't be that hard right? Well, turns out it is:
How is it better than |
2023-10-27
2022-08-15
2022-08-17
2022-09-23
2022-08-13
请发表评论