Almost every Mac OS X application has a special preferences window, but Apple do not provide any standard solution to build custom preferences. We have to deal with NSWindowController/NSToolbar staff every time. Not good.
IKApplicationPreferences was developed to address this problem.
Out of the box features:
- Window is automatically resized to match size of the view
- Toolbar can be configured using ASCII art! Finally it's very easy to localize preferences
- Toggling views are animated. On pre 10.8 it uses hide/show approach (like in Mail.app or Safari.app) On 10.8+ it uses Core Animation (like in About This Mac introduced in Lion)
- Default window title is localized in almost every language
- Provides methods to cyclically enumerate views. Very useful since order of preferences may depend on user's locale
- Automatic Reference Counting (a.k.a ARC)
- Support for windows restoration.
- Mac OS X 10.6+
- x86_64 (new runtime)
IKApplicationPreferences
consist of so-named Preferences Representations --- objects that adopts (formally or informally) IKPreferencesRepresentation
protocol.
Each Preferences Representation consist of:
-
view that represents preferences
-
toolbar item
-
optionally title
Therefore IKPreferencesRepresentation defines 2 required methods:
- (NSView *)view
- (void)configureToolbarItem:(NSToolbarItem *)anItem
and 1 optional method:
- (NSString *)title
Most convenient (and widely used) way to create preferences representation is to subclass NSViewController
and adopt IKPreferencesRepresentation
for each representation.
Since NSViewController already implements both -view
and -title
, the only method you have to implement is -configureToolbarItem:
.
This method receives an initialized instance of NSToolbarItem
that it's supposed to configure. The only properties you cannot change are target
and action
.
It's time to create an instance of IKApplicationPreferences. As you may already noticed IKApplicationPreferences is a subclass of NSWindowController
and it requires a nib to load the window. You may use stock IKApplicationPreferencesWindow.xib or you may create custom nib. See notes how to do this properly.
The designated initialized or IKApplicationPreferences is:
- (instancetype)initWithWindowNibName:(NSString *)aNibName
visualFormat:(NSString *)aFormat
representations:(NSDictionary *)aRepresentations
usesCoreAnimation:(BOOL)aUsesCoreAnimation;
The first parameter is a name of nib we discussed above. The second and third parameters should be familiar to you if you ever worked with NSLayoutConstraint.
-
aRepresentations is a dictionary where keys are identifiers and objects are instances of classes that adopt
IKPreferencesRepresentation
-
aFormat is a string which represents configuration of
NSToolbar
using ASCII art. It's essentially a comma-separated list of identifiers specified in aRepresentations or standard NSToolbarItem identifiers. It also supports 2 shortcuts:' '
(NSToolbarSpaceItemIdentifier) and'-'
(NSToolbarFlexibleSpaceItemIdentifier). E.g.@"general,accounts, ,audio,video,-,about"
-
aUsesCoreAnimation If set, Core Animation will be used therefore animation will be much smoother
You can also use preferencesWithWindowNibName:visualFormat:representations:
. The only difference is that it lacks aUsesCoreAnimation parameter, because it
automaticaly uses Core Animation if target version of Mac OS X is 10.8+.
Already done with that? Great. To show the preferences window simply use standard method of NSWindowController: -showWindow:
.
-
The main reason to create custom nib is add views that will be common to any preferences. E.g. custom background or Lock/Unlock view (line in System Preferences.app). Your nib must match the following requirements:
- File's Owner MUST be set to
IKApplicationPreferences
or its subclass. - You MUST set Owner's window to nib's window.
- You MUST not bind title of the window.
- You MUST add an empty view and set Owner's _representationsRootView to it.
- You SHOULD set _representationsRootView's autoresizing mask or constraints so it will be resized with window proportionally. It's not a requirement because you can provide custom layout in your subclass of IKApplicationPreferences.
- You SHOULD set class of _representationsRootView to _IKRepresentationRootView. _IKRepresentationRootView is a flipped NSView.
- You MUST add Toolbar to the window and set its delegate to Owner.
- File's Owner MUST be set to
-
Default
-titlePlaceholder
uses standard CFBundleDisplayName to obtain localized name of you application. If it fails, it uses CFBundleName