Localization

Some strings, e.g. the title of the preference pane is localizable. Preferences.framework can localize these strings by looking for the corresponding key in localizationTable.strings in bundle. If you are writing a PreferenceBundles, the localizationTable is the name of the specifier plist and bundle is of course the PreferenceBundle itself.

For example, if the plist is named MySettings.plist, then the corresponding strings file should be named MySettings.strings.

Specifier Entries

You can use any keys that your controller recognizes in the plist for further customization. This table lists the internal ones:

where the type of "something" depends on the type of specifier, e.g. for a text field it should be an NSString, while for a switch it should be an NSNumber with boolean.

Of course, you can ignore extra parameters, e.g. -(void)specifierPerformedAction is a valid signature too.

Editing cells

These keys are specific to editing cells.

key

type

meaning

depends

autoCaps

string

{"sentences", "words", "all"}

Autocapitalization type for cells that requires a keyboard.

-

keyboard

string

{"numbers", "phone"}

Type of keyboard.

-

prompt

string

localizable string

Setup prompt.

cell ∈ {"PSEditTextCell", "PSSecureEditTextCell"}

okTitle

string

localizable string

Title for OK button in setup prompt.

prompt ≠ nil

cancelTitle

string

localizable string

Title for cancel button in setup prompt.

prompt ≠ nil

placeholder

string

localizable string

Placeholder.

cell ∈ {"PSEditTextCell", "PSSecureEditTextCell"}

suffix

string

localizable string

Suffix.

cell ∈ {"PSEditTextCell", "PSSecureEditTextCell"}

isIP

boolean

Input field intended for entering IP address (Use Numbers keyboard).

-

isURL

boolean

Input field intended for entering URL (Use URL keyboard).

-

isNumeric

boolean

Input field intended for entering numbers (Use NumberPad keyboard).

-

isEmail

boolean

Input field intended for entering e-mail (Use EmailAddress keyboard).

-

isEmailAddressing

boolean

?

-

bestGuess

string

selector

Initial value of text field.

cell ∈ {"PSEditTextCell", "PSSecureEditTextCell"}

noAutoCorrect

boolean

Disable auto-correction.

cell ∈ {"PSEditTextCell", "PSSecureEditTextCell"}

List cells

These keys are specific to list cells.

key

type

meaning

depends

validValues

array

...of strings

List of values to choose from.

cell ∈ {"PSLinkListCell", "PSSegmentCell"}

validTitles

array

...of localizable strings

Titles corresponding to the list of values.

cell ∈ {"PSLinkListCell", "PSSegmentCell"}

shortTitles

array

...of localizable strings

Short titles.

cell ∈ {"PSLinkListCell", "PSSegmentCell"}

valuesDataSource

string

selector

Selector to call to get the list of values dynamically.

cell ∈ {"PSLinkListCell", "PSSegmentCell"} andvalidValues = nil

titlesDataSource

string

selector

Selector to call to get the list of titles dynamically.

cell ∈ {"PSLinkListCell", "PSSegmentCell"} andvalidTitles = nil

staticTextMessage

string

localizable string

Static text message (?).

cell = "PSLinkListCell"

valuesDataSource and titlesDataSource are performed on the target sent from -[PSListController loadSpecifiersFromPlistName:target:]. They must return an NSArray containing the values and (localized) titles respectively. Their signatures should be

-(NSArray*)dataFromTarget:(id)target;

Slider and switch cells

These keys are specific to slider and switch cells.

key

type

meaning

depends

rightImage

string

filename

Image displayed next to the slider on the right.

cell = "PSSliderCell"

leftImage

string

filename

Image displayed next to the slider on the left.

cell = "PSSliderCell"

min

float

Minimum value of slider.

cell = "PSSliderCell"

max

float

Maximum value of slider.

cell = "PSSliderCell"

showValue

boolean

Show the value.

cell = "PSSliderCell"

alternateColors

boolean

Use an orange switch instead of blue.

cell = "PSSwitchCell"

Miscellaneous control cells

These keys are specific to other control cells.

key

type

meaning

depends

alignment

integer

Text alignment. 1 = center.

cell ∈ {"PSGroupCell", "PSStaticTextCell"

confirmation

dictionary

<confirmation>

Definitions of the confirmation sheet before action is performed.

cell ∈ {"PSSwitchCell", "PSButtonCell"

isDestructive

boolean

Whether the action to be performed is destructive. The OK button will be in red if true.

confirmation ≠ nil

max

float

Maximum value of slider.

cell = "PSSliderCell"

showValue

boolean

Show the value.

cell = "PSSliderCell"

alternateColors

boolean

Show the value.

cell = "PSSwitchCell"

isStaticText

boolean

Whether the cells in this group has static text. Used in conjunction with PSStaticTextCell.

cell = "PSGroupCell"

height

float

Height of text view.

cell = "PSTextViewCell"

dontIndentOnRemove

boolean

?

-

footerText

string

Text displayed in a small font after this specifier (or, in the case of a PSGroupCell, the last specifier in the group).

-

footerCellClass

class

The cell class using which to render the footer.

-

Here, confirmation itself is a dictionary containing the following fields:

struct<confirmation> ::

key

type

meaning

prompt

string

localizable string

Content of confirmation sheet.

cancelTitle

string

localizable string

Title of the cancel button.

okTitle

string

localizable string

Title of the OK button.

title

string

localizable string

Title of confirmation sheet.

PSSpecifier properties of plist keys

The tables above only shows the keys recognized by SpecifiersForPlist when translating the plist into an array of PSSpecifiers. They may be corresponds to the actual properties of the specifier. If you would like to generate a PSSpecifier in runtime, some actions may differ:

keys

corresponding action

cell

Use the constructor, or change the cellType ivar.

label

Use the name declared property.

get

Use the constructor, or change the getter ivar.

set

Use the constructor, or change the setter ivar.

action

Change the action ivar.

default

Use the value property.

icon

Use the iconImage as an UIImage, or -[PSSpecifier setupIconImageWithPath:]

Recipes

Using PSLinkListCell

In order to make a PSLinkListCell actually work like a list, you must supply the key-value pair

detail = "PSListItemsController";

also.

Using PSLinkCell

PSLinkCell is useful for linking to sub-preference-panes. The simplest example just needs 2 keys:

{ cell = PSLinkCell;
label = "Settings-iPhone"; }

The label is the important part. When user clicked on the link cell, iPhoneOS will use the unlocalizedlabel as the file name of the plist for the next pane. For example in above, the main settings screen will appear.

If you use just 2 keys, only plists inside Preferences can be loaded. In order to load your own plist, you must use a custom subclass of PSListController in detail:

The key thing is when you place MyListController inside your bundle, its bundle property will return your bundle which My Awesome Pane.plist can be found.

Constructing a PSLinkCell at runtime

If you want to dynamically add a specifier for a PSLinkCell linking to a bundle, do it like this:

PSSpecifier*specifier=[PSSpecifierpreferenceSpecifierNamed:@"title"target:selfset:NULLget:NULLdetail:Nilcell:PSLinkCelledit:Nil];NSBundle*bundle=[NSBundlebundleWithPath:@"/System/Library/PreferenceBundles/prefs.bundle"];[specifiersetProperty:bundleforKey:@"lazy-bundle"];specifier->action=@selector(lazyLoadBundle:);// Add specifier to the PSListController

Making a red delete button

The red delete button in VPN is in fact very easy to implement. All you need to do is add the following code:

Note that UIPreferencesDeleteTableCell no longer exists as of iOS 6.0.

Making a custom cell, header or footer

Making a custom cell, header or footer is useful because it allows you to customize the style, add an image, etc.

All you need to do is make a class that looks like:

@interfaceCustomCell : PSTableCell<PreferencesTableCustomView>{UILabel*_label;}@end@implementationCustomCell-(id)initWithSpecifier:(PSSpecifier*)specifier{self=[superinitWithStyle:UITableViewCellStyleDefaultreuseIdentifier:@"Cell"specifier:specifier];if(self){CGRectframe=[selfframe];_label=[[UILabelalloc]initWithFrame:frame];[_labelsetLineBreakMode:UILineBreakModeWordWrap];[_labelsetNumberOfLines:0];[_labelsetText:@"You can use attributed text to make this prettier."];[_labelsetBackgroundColor:[UIColorclearColor]];[_labelsetShadowColor:[UIColorwhiteColor]];[_labelsetShadowOffset:CGSizeMake(0,1)];[_labelsetTextAlignment:UITextAlignmentCenter];[selfaddSubview:_label];[_labelrelease];}returnself;}-(float)preferredHeightForWidth:(float)arg1{// Return a custom cell height.return60.f;}@end

Then, set the cellClass, headerCellClass or footerCellClass in your specifier. For example: