我在Xcode中为Mac创建了一个简单的应用程序,它能够成功地构建和编译。
我该如何创建偏好设置菜单?有没有简单的方法,还是必须创建新的界面?然后我如何获取和放置这些偏好设置的值?
我找到了一个教程,但它是针对iOS的。从我所看到的内容来看,如果您正在开发Mac应用程序,则“设置包”不可用。
编辑:下面的链接非常适合此目的:https://developer.apple.com/cocoa/cocoabindings.html
我在Xcode中为Mac创建了一个简单的应用程序,它能够成功地构建和编译。
我该如何创建偏好设置菜单?有没有简单的方法,还是必须创建新的界面?然后我如何获取和放置这些偏好设置的值?
我找到了一个教程,但它是针对iOS的。从我所看到的内容来看,如果您正在开发Mac应用程序,则“设置包”不可用。
编辑:下面的链接非常适合此目的:https://developer.apple.com/cocoa/cocoabindings.html
这是你想要的文档。 更具体地说,如何提供一个首选项界面。
无论如何,你都需要像制作任何其他窗口一样制作自己的首选项菜单/窗口,并拥有一些控件,允许修改值,然后将其存储在用户默认字典中,这通常是用户首选项存储的地方(Cocoa Bindings使这个过程非常容易)。
否则,手动操作,你可能需要引用[NSUserDefaults standardUserDefaults]
,以便你可以使用-setObject:ForKey:
等方法。最好阅读以上链接文档的所有部分(包括其他部分)。
有关如何使用Cocoa Bindings与NSUserDefaults
接口来存储/检索首选项的更多信息,请参见苹果文档此处。
对于窗口本身,我建议使用RHPreferences框架。
该框架在GitHub上可用,采用BSD许可证。
它是一个简单易用的偏好设置窗口控制器,带有多个选项卡,适用于您的下一个Mac应用程序。
此外,它还提供:
https://developer.apple.com/documentation/appkit/nstabviewcontroller/tabstyle
考虑到上述内容,我们可以创建一个NSWindowController
,并将NSWindow.contentViewController
设置为NSTabViewController
,以获取标准的macOS首选项窗口。enum PreferencesPageID: Int, CaseIterable {
case generic, misc
var image: NSImage? {
switch self {
case .generic:
return NSImage(named: NSImage.folderSmartName)
case .misc:
return NSImage(named: NSImage.networkName)
}
}
var title: String {
switch self {
case .generic:
return "Some"
case .misc:
return "Other"
}
}
}
文件: PreferencesTabView.swift – 代表首选项页面的内容视图。
class PreferencesTabView: View {
let id: PreferencesPageID
init(id: PreferencesPageID) {
self.id = id
super.init()
}
required init?(coder decoder: NSCoder) {
fatalError()
}
override func setupUI() {
switch id {
case .generic:
backgroundColor = .red
setIntrinsicContentSize(CGSize(width: 400, height: 200))
case .misc:
backgroundColor = .blue
setIntrinsicContentSize(CGSize(width: 400, height: 300))
}
}
}
文件:PreferenceItemViewController.swift - 控制器,用于维护首选项页面的内容视图。主要用于满足 macOS SDK 的要求。
class PreferenceItemViewController: ViewController {
private let contentView: PreferencesTabView
override func loadView() {
view = contentView
}
init(view: PreferencesTabView) {
contentView = view
super.init(nibName: nil, bundle: nil)
}
required init?(coder: NSCoder) {
fatalError()
}
override func viewDidLayout() {
super.viewDidLayout()
preferredContentSize = view.intrinsicContentSize
}
}
文件名:PreferencesViewController.swift - 作为NSWindow.contentViewController
使用。
class PreferencesViewController: TabViewController {
enum Event {
case selected(PreferencesPageID)
}
var eventHandler: ((Event) -> Void)?
override func setupUI() {
tabStyle = .toolbar // This will "turn" View Controller to standard Preferences window.
transitionOptions = .allowUserInteraction
canPropagateSelectedChildViewControllerTitle = false
let views = [PreferencesTabView(id: .generic), PreferencesTabView(id: .misc)]
views.forEach {
let item = NSTabViewItem(viewController: PreferenceItemViewController(view: $0))
item.label = $0.id.title
item.image = $0.id.image
addTabViewItem(item)
}
}
override func tabView(_ tabView: NSTabView, didSelect tabViewItem: NSTabViewItem?) {
super.tabView(tabView, didSelect: tabViewItem)
if let view = tabViewItem?.viewController?.view as? PreferencesTabView {
eventHandler?(.selected(view.id))
}
}
}
文件: PreferencesWindowController.swift – 首选项窗口控制器。
private class PreferencesWindowController: NSWindowController {
private(set) lazy var viewController = PreferencesViewController()
init() {
let rect = CGRect(x: 400, y: 200, width: 400, height: 300)
let window = NSWindow(contentRect: rect, styleMask: [.titled, .closable], backing: .buffered, defer: true)
super.init(window: window)
setupHandlers()
let frameSize = window.contentRect(forFrameRect: window.frame).size
viewController.view.setFrameSize(frameSize)
window.contentViewController = viewController
}
required init?(coder: NSCoder) {
fatalError()
}
// MARK: - Private
private func setupHandlers() {
viewController.eventHandler = { [weak self] in
switch $0 {
case .selected(let id):
self?.window?.title = "Preferences — " + id.title
}
}
}
}
使用方法:
public class Application: NSApplication {
private lazy var preferencesController = PreferencesWindowController()
// Called from code or via IBAction
private func showPreferences() {
preferencesController.showWindow(nil)
}
}
MainMenu.xib
中,点击应用程序名称后,您将看到一个下拉列表。将Preferences
使用Cntrl + 点击 + 拖动到您的项目的AppDelegate.h
文件中,并创建一个IBAction方法。[self.preferenceWindowController showWindow:self];
。这将为您的OS X应用程序创建一个Preferences
窗口。// AppDelegate.m
// CocoaToolBars
// Created by Debasis Das on 4/30/15.
// Copyright (c) 2015 Knowstack. All rights reserved.
#import "AppDelegate.h"
@interface AppDelegate ()
@property (weak) IBOutlet NSWindow *window;
@end
@implementation AppDelegate
- (void)applicationDidFinishLaunching:(NSNotification *)aNotification {
// Insert code here to initialize your application
_toolbarTabsArray = [self toolbarItems];
_toolbarTabsIdentifierArray = [NSMutableArray new];
for (NSDictionary *dict in _toolbarTabsArray){
[_toolbarTabsIdentifierArray addObject:dict[@"identifier"]];
}
_toolbar = [[NSToolbar alloc] initWithIdentifier:@"ScreenNameToolbarIdentifier"];
_toolbar.allowsUserCustomization = YES;
_toolbar.delegate = self;
self.window.toolbar = _toolbar;
}
-(NSArray *)toolbarItems {
NSArray *toolbarItemsArray = [NSArray arrayWithObjects:
[NSDictionary dictionaryWithObjectsAndKeys:@"Find Departments",@"title",@"Department-50",@"icon",@"DepartmentViewController",@"class",@"DepartmentViewController",@"identifier", nil],
[NSDictionary dictionaryWithObjectsAndKeys:@"Find Accounts",@"title",@"Business-50",@"icon",@"AccountViewController",@"class",@"AccountViewController",@"identifier", nil],
[NSDictionary dictionaryWithObjectsAndKeys:@"Find Employees",@"title",@"Edit User-50",@"icon",@"EmployeeViewController",@"class",@"EmployeeViewController",@"identifier", nil],
nil];
return toolbarItemsArray;
}
- (void)applicationWillTerminate:(NSNotification *)aNotification {
// Insert code here to tear down your application
}
- (NSToolbarItem *)toolbar:(NSToolbar *)toolbar
itemForItemIdentifier:(NSString *)itemIdentifier willBeInsertedIntoToolbar:(BOOL)flag {
NSDictionary *itemInfo = nil;
for (NSDictionary *dict in _toolbarTabsArray) {
if([dict[@"identifier"] isEqualToString:itemIdentifier]) {
itemInfo = dict;
break;
}
}
NSAssert(itemInfo, @"Could not find preferences item: %@", itemIdentifier);
NSImage *icon = [NSImage imageNamed:itemInfo[@"icon"]];
if(!icon) {
icon = [NSImage imageNamed:NSImageNamePreferencesGeneral];
}
NSToolbarItem *item = [[NSToolbarItem alloc] initWithItemIdentifier:itemIdentifier];
item.label = itemInfo[@"title"];
item.image = icon;
item.target = self;
item.action = @selector(viewSelected:);
return item;
}
-(void)viewSelected:(id)sender {
NSToolbarItem *item = sender;
[self loadViewWithIdentifier:item.itemIdentifier withAnimation:YES];
}
-(void)loadViewWithIdentifier:(NSString *)viewTabIdentifier
withAnimation:(BOOL)shouldAnimate {
NSLog(@"viewTabIdentifier %@",viewTabIdentifier);
if ([_currentView isEqualToString:viewTabIdentifier]) {
return;
} else {
_currentView = viewTabIdentifier;
}
//Loop through the view array and find out the class to load
NSDictionary *viewInfoDict = nil;
for (NSDictionary *dict in _toolbarTabsArray) {
if ([dict[@"identifier"] isEqualToString:viewTabIdentifier]) {
viewInfoDict = dict;
break;
}
}
NSString *class = viewInfoDict[@"class"];
if(NSClassFromString(class)) {
_currentViewController = [[NSClassFromString(class) alloc] init];
NSView *newView = _currentViewController.view;
NSRect windowRect = self.window.frame;
NSRect currentViewRect = newView.frame;
windowRect.origin.y = windowRect.origin.y + (windowRect.size.height - currentViewRect.size.height);
windowRect.size.height = currentViewRect.size.height;
windowRect.size.width = currentViewRect.size.width;
self.window.title = viewInfoDict[@"title"];
[self.window setContentView:newView];
[self.window setFrame:windowRect display:YES animate:shouldAnimate];
} else {
NSAssert(false, @"Couldn't load %@", class);
}
}
- (NSArray *)toolbarDefaultItemIdentifiers:(NSToolbar *)toolbar {
NSLog(@"%s %@",__func__,_toolbarTabsIdentifierArray);
return _toolbarTabsIdentifierArray;
}
- (NSArray *)toolbarAllowedItemIdentifiers:(NSToolbar *)toolbar {
NSLog(@"%s",__func__);
return [self toolbarDefaultItemIdentifiers:toolbar];
}
- (NSArray *)toolbarSelectableItemIdentifiers:(NSToolbar *)toolbar {
NSLog(@"%s",__func__);
return [self toolbarDefaultItemIdentifiers:toolbar];
}
- (void)toolbarWillAddItem:(NSNotification *)notification {
NSLog(@"%s",__func__);
}
- (void)toolbarDidRemoveItem:(NSNotification *)notification {
NSLog(@"%s",__func__);
}
@end