Project Icon

Settings

Swift库助力macOS应用轻松实现设置功能

Settings是一个用于macOS应用开发的Swift库,能快速实现设置窗口功能。该库支持视图控制器传入、自动界面处理和SwiftUI集成。兼容macOS 13+,自动使用'Settings'作为窗口标题。提供工具栏和分段控制两种样式,支持窗口和标签状态保存,符合macOS界面设计规范。开发者可通过简单配置,轻松为应用添加专业的设置界面。

设置

几分钟内为您的 macOS 应用添加设置窗口

只需传入一些视图控制器,这个包就会处理其余的部分。内置 SwiftUI 支持。

该包兼容 macOS 13,并在 macOS 13 及更高版本中自动使用"设置"而不是"偏好设置"作为窗口标题。

此项目之前被称为 Preferences

要求

macOS 10.13 及更高版本。

安装

在 Xcode 的"Swift Package Manager"选项卡中添加 https://github.com/sindresorhus/Settings

使用方法

运行 Example Xcode 项目以尝试实时示例(需要 macOS 11 或更高版本)。

首先,创建一些设置面板标识符:

import Settings

extension Settings.PaneIdentifier {
	static let general = Self("general")
	static let advanced = Self("advanced")
}

其次,为您想要的设置面板创建几个视图控制器。与实现普通视图控制器的唯一区别是,您必须添加 SettingsPane 协议并实现 paneIdentifiertoolbarItemTitletoolbarItemIcon 属性,如下所示。如果您使用 .segmentedControl 样式,可以省略 toolbarItemIcon

GeneralSettingsViewController.swift

import Cocoa
import Settings

final class GeneralSettingsViewController: NSViewController, SettingsPane {
	let paneIdentifier = Settings.PaneIdentifier.general
	let paneTitle = "通用"
	let toolbarItemIcon = NSImage(systemSymbolName: "gearshape", accessibilityDescription: "通用设置")!

	override var nibName: NSNib.Name? { "GeneralSettingsViewController" }

	override func viewDidLoad() {
		super.viewDidLoad()

		// 在此处设置内容
	}
}

注意:如果您需要支持比 macOS 11 更早的 macOS 版本,您必须为 toolbarItemIcon 添加一个后备方案

AdvancedSettingsViewController.swift

import Cocoa
import Settings

final class AdvancedSettingsViewController: NSViewController, SettingsPane {
	let paneIdentifier = Settings.PaneIdentifier.advanced
	let paneTitle = "高级"
	let toolbarItemIcon = NSImage(systemSymbolName: "gearshape.2", accessibilityDescription: "高级设置")!

	override var nibName: NSNib.Name? { "AdvancedSettingsViewController" }

	override func viewDidLoad() {
		super.viewDidLoad()

		// 在此处设置内容
	}
}

如果您需要间接响应操作,设置窗口控制器会将响应链操作转发给活动面板(如果它响应该选择器)。

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)
	}
}

AppDelegate 中,初始化一个新的 SettingsWindowController 并传入视图控制器。然后为"设置…"菜单项添加一个操作出口以显示设置窗口。

AppDelegate.swift

import Cocoa
import Settings

@main
final class AppDelegate: NSObject, NSApplicationDelegate {
	@IBOutlet private var window: NSWindow!

	private lazy var settingsWindowController = SettingsWindowController(
		panes: [
			GeneralSettingsViewController(),
			AdvancedSettingsViewController()
		]
	)

	func applicationDidFinishLaunching(_ notification: Notification) {}

	@IBAction
	func settingsMenuItemActionHandler(_ sender: NSMenuItem) {
		settingsWindowController.show()
	}
}

设置标签样式

创建 SettingsWindowController 时,您可以选择基于 NSToolbarItem 的样式(默认)和 NSSegmentedControl

// …
private lazy var settingsWindowController = SettingsWindowController(
	panes: [
		GeneralSettingsViewController(),
		AdvancedSettingsViewController()
	],
	style: .segmentedControl
)
// …

.toolbarItem 样式:

基于 NSToolbarItem(默认)

.segmentedControl 样式:

基于 NSSegmentedControl

API

public enum Settings {}

extension Settings {
	public enum Style {
		case toolbarItems
		case segmentedControl
	}
}
public protocol SettingsPane: NSViewController {
	var paneIdentifier: Settings.PaneIdentifier { get }
	var paneTitle: String { get }
	var toolbarItemIcon: NSImage { get } // 使用.`segmentedControl`样式时不需要
}

public final class SettingsWindowController: NSWindowController {
	init(
		panes: [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(pane: Settings.PaneIdentifier? = nil)
}

与任何NSWindowController一样,调用NSWindowController#close()来关闭设置窗口。

建议

在每个面板内创建用户界面最简单的方法是在Interface Builder中使用NSGridView。请参阅此仓库中的示例项目以查看演示。

SwiftUI支持

如果你的部署目标是macOS 10.15或更高版本,你可以使用捆绑的SwiftUI组件来创建面板。使用你的自定义视图和必要的工具栏信息创建一个Settings.Pane(使用AppKit时是SettingsPane)。

在此仓库的Xcode项目中运行Example目标以查看真实示例。Accounts标签页使用SwiftUI实现。

还有一些捆绑的便利SwiftUI组件,如Settings.ContainerSettings.Section,可以自动实现与AppKit的NSGridView类似的对齐。还有一个.settiingDescription()视图修饰符用于将文本样式设置为设置描述。

提示:Defaults包使得持久化设置变得非常容易。

struct CustomPane: View {
	var body: some View {
		Settings.Container(contentWidth: 450.0) {
			Settings.Section(title: "节标题") {
				// 一些视图
			}
			Settings.Section(label: {
				// 自定义标签对齐在右侧
			}) {
				// 一些视图
			}
			…
		}
	}
}

然后在AppDelegate中,初始化一个新的SettingsWindowController并传入面板视图。

// …

private lazy var settingsWindowController = SettingsWindowController(
	panes: [
		Pane(
			 identifier: …,
			 title: …,
			 toolbarIcon: NSImage(…)
		) {
			CustomPane()
		},
		Pane(
			 identifier: …,
			 title: …,
			 toolbarIcon: NSImage(…)
		) {
			AnotherCustomPane()
		}
	]
)

// …

如果你想在标准AppKit NSViewController旁边使用SwiftUI面板,可以将面板视图包装到Settings.PaneHostingController中,然后像使用标准面板一样将它们传递给SettingsWindowController

let CustomViewSettingsPaneViewController: () -> SettingsPane = {
	let paneView = Settings.Pane(
		identifier: …,
		title: …,
		toolbarIcon: NSImage(…)
	) {
		// 你的自定义视图(如果需要的话还可以添加修饰符)
		CustomPane()
		//  .environmentObject(someSettingsManager)
	}

	return Settings.PaneHostingController(paneView: paneView)
}

// …

private lazy var settingsWindowController = SettingsWindowController(
	panes: [
		GeneralSettingsViewController(),
		AdvancedSettingsViewController(),
		CustomViewSettingsPaneViewController()
	],
	style: .segmentedControl
)

// …

这里有完整示例。

向后兼容性

macOS 11及更高版本支持SF Symbols,可以方便地用于工具栏图标。如果你需要支持旧版macOS,你必须添加一个后备方案。Apple建议即使在旧系统上也使用相同的图标。实现这一点的最佳方法是导出相关SF Symbols图标为图像,并将它们添加到你的Asset Catalog中。

已知问题

设置窗口不显示

当你不使用自动布局或未为视图控制器设置大小时,可能会发生这种情况。你可以通过使用自动布局或设置显式大小来解决这个问题,例如在viewDidLoad()中设置preferredContentSize我们打算修复这个问题。

macOS 10.13及更早版本没有动画

在 macOS 10.13 或更早版本上,SettingsWindowController.initanimated 参数没有效果,因为这些版本不支持 NSViewController.TransitionOptions.crossfade

常见问题

如何本地化窗口标题?

SettingsWindowController 遵循 macOS 人机界面指南,并使用以下规则来确定窗口标题:

  • 多个设置面板: 使用当前选中的 paneTitle 作为窗口标题。本地化你的 paneTitle 以获得本地化的窗口标题。
  • 单个设置面板: 将窗口标题设置为 应用名称 设置。应用名称从你的应用程序包中获取。你可以本地化其 Info.plist 来自定义标题。"设置"部分取自"设置…"菜单项,参见 #12。从你的应用程序包中查找应用名称的顺序:
    1. CFBundleDisplayName
    2. CFBundleName
    3. CFBundleExecutable
    4. 如果缺少某些设置,将回退到 "<未知应用名称>"

为什么我应该使用这个而不是自己手动实现?

看起来不难,对吧?其实很复杂:

它比 MASPreferences 好在哪里?

  • 用 Swift 编写。(无需桥接头文件!)
  • 使用协议的 Swift 风格 API。
  • 支持分段控制样式标签。
  • 支持 SwiftUI。
  • 完整的文档。
  • 符合 macOS 人机界面指南
  • 窗口标题通过使用系统字符串自动本地化。

相关项目

你可能也会喜欢 Sindre 的应用程序

这些应用使用了本项目

想告诉世界你的应用正在使用这个包吗?欢迎提交 PR!

维护者

项目侧边栏1项目侧边栏2
推荐项目
Project Cover

豆包MarsCode

豆包 MarsCode 是一款革命性的编程助手,通过AI技术提供代码补全、单测生成、代码解释和智能问答等功能,支持100+编程语言,与主流编辑器无缝集成,显著提升开发效率和代码质量。

Project Cover

AI写歌

Suno AI是一个革命性的AI音乐创作平台,能在短短30秒内帮助用户创作出一首完整的歌曲。无论是寻找创作灵感还是需要快速制作音乐,Suno AI都是音乐爱好者和专业人士的理想选择。

Project Cover

有言AI

有言平台提供一站式AIGC视频创作解决方案,通过智能技术简化视频制作流程。无论是企业宣传还是个人分享,有言都能帮助用户快速、轻松地制作出专业级别的视频内容。

Project Cover

Kimi

Kimi AI助手提供多语言对话支持,能够阅读和理解用户上传的文件内容,解析网页信息,并结合搜索结果为用户提供详尽的答案。无论是日常咨询还是专业问题,Kimi都能以友好、专业的方式提供帮助。

Project Cover

阿里绘蛙

绘蛙是阿里巴巴集团推出的革命性AI电商营销平台。利用尖端人工智能技术,为商家提供一键生成商品图和营销文案的服务,显著提升内容创作效率和营销效果。适用于淘宝、天猫等电商平台,让商品第一时间被种草。

Project Cover

吐司

探索Tensor.Art平台的独特AI模型,免费访问各种图像生成与AI训练工具,从Stable Diffusion等基础模型开始,轻松实现创新图像生成。体验前沿的AI技术,推动个人和企业的创新发展。

Project Cover

SubCat字幕猫

SubCat字幕猫APP是一款创新的视频播放器,它将改变您观看视频的方式!SubCat结合了先进的人工智能技术,为您提供即时视频字幕翻译,无论是本地视频还是网络流媒体,让您轻松享受各种语言的内容。

Project Cover

美间AI

美间AI创意设计平台,利用前沿AI技术,为设计师和营销人员提供一站式设计解决方案。从智能海报到3D效果图,再到文案生成,美间让创意设计更简单、更高效。

Project Cover

AIWritePaper论文写作

AIWritePaper论文写作是一站式AI论文写作辅助工具,简化了选题、文献检索至论文撰写的整个过程。通过简单设定,平台可快速生成高质量论文大纲和全文,配合图表、参考文献等一应俱全,同时提供开题报告和答辩PPT等增值服务,保障数据安全,有效提升写作效率和论文质量。

投诉举报邮箱: service@vectorlightyear.com
@2024 懂AI·鲁ICP备2024100362号-6·鲁公网安备37021002001498号