Redbeard Theme Reference V1.0

Redbeard Theming

Components in Redbeard can be themed using the Redbeard theming engine. Themed components include standard iOS views too. The Redbeard theming engine reads JSON files from the bundle - resembling CSS in their nature - and provides automatic and manual theming to components.

Types of Theme File

There are two types of theme file:

  1. Include files - these reference other theme files to build a sequence in which to load files.
  2. Theme files - these contain the actual themes that are used to theme UI components at runtime.

Root Theme File

To use JSON themes an include file with the name theme.inc.json must be provided. It is important that the name be theme.inc.json or one of the variants described later that allow version, device and language specific root themes to be used.

This file (alongside any other theme and include files) must reside within the application bundle. It is expected to be present if you are using themes. This file will include other include files and themes as required.

The root theme file allows for device, language and iOS specific variants and attempts are made to locate the most specific root theme file while degrading gracefully until simply theme.inc.json is searched for if specific variants are not found.

Root Theme Variant Structure

The root theme file can be expressed using the following form (square brackets are used here to denote optional regions):

theme[_device][_version][_language].inc.json
  • device - The device type. Supported values are phone, pad.
  • version - The iOS version number e.g. 9.3.1, 9.3, 9.0. If version 9.3.1 is provided and a file is not found with that version number a search is made for files with version numbers and 9.0 and 9 i.e it degrades to the major iOS version ONLY
  • language - The language locale (all lowercase) e.g. en_gb, en_us, fr-fr, de-ch. Specifically [ISO 639-1]_[ISO 3166-1].

The theme name and optional parameters must be lower case

Examples

Root theme file for iPhone, iOS version 9.3, the english language and with region Great Britain.

theme_phone_9.3_en_gb.inc.json

Root theme file for iOS version 9.3.

theme_phone_9.3_en_gb.inc.json

Root theme file for iPad and US english.

theme_pad_en_us.inc.json

Redbeard will attempt to search for the most specific root theme file available, it will do so using by using the devices device type, iOS version and locale, degrading gracefully until theme.inc.json alone remains.

Include Files

Include files take the extension .inc.json. They have a dictionary at their root and provide the following two keys:

  • include - an ordered array of the filenames of other include files that should be loaded prior to this file.
  • themes - an ordered array of the filenames of theme files to be loaded.

Here's an example include file:

{
    "include":
    [
        "default.inc.json"
    ],

    "themes":
    [
        "MainViewController.theme.json"
    ]
}

This example includes another include file named default.inc.json - which includes various default themes and a single theme file named MainViewController.theme.json.

Comments

Include files may contain comments. Comments are strings beginning comment:. Any such strings are ignored and are not loaded into memory.

Here's an example with comments:

{
    "include":
    [
        "default.inc.json",
        "comment: Add any additional files here"
    ],

    "themes":
    [
        "MainViewController.theme.json",
        "comment: Add any additional theme files here"
    ]
}

Theme Files

Theme files are listed in include files typically however they take the extension .json. A theme file must contain a dictionary at it's root. Theme files contain assignments of the following form that define themes:

{
    "<ID>": <theme assignments>,
    "<ID>": <theme assignments>
    ...
}

The ID can be any identifier of your choosing. Importantly if the identifier matches a class name e.g. UILabel then UILabel's will be automatically themed with the values described without requiring further input. This is an important concept within the theming capabilities of Redbeard.

Partial Definitions in Multiple Locations

If a theme with the same name is defined in multiple files the theme values are merged together much like CSS.

An Example Theme

Here's an example theme file:

{
    "RBTextField":
    {
        "borderWidth": 1,
        "borderColor": "ref://palette-grey-500",
        "backgroundColor": "ref://color-background",

        "textMargin": [ 5, 10, 5, 10 ],

        "font": "ref://standard-body-font",
        "textColor": "ref://color-text-dark",
        "placeholderTextColor": "ref://palette-grey-500",
    }
}

The above file contains a single theme definition (you may include multiple within a file if you choose). The identifer is a class name of an iOS component included with Redbeard RBTextField - this makes this theme a base theme. Base themes are automatically applied to the corresponding component when the didMoveToSuperView event occurs (see the Lifecycle section for more on this). The theme contains references to fonts and colors that are located elsewhere it does this by using the ref://<ID> operator.

Using References

References to defined theme values defined elsewhere are of the form:

ref://<ID>

References are used extensively to bring uniform theming to an application. For example colors and fonts maybe defined in files to be used globally. Similarly references to button themes form themes etc can be defined and used.

Example theme values:

{
    "color-text-dark": "ref://palette-black",
    "color-text-light": "ref://palette-white",
    "color-text-pale": "#888888",

    "standard-headline-font":
    {
        "style": "headline",
        "name": "HelveticaNeue-Bold"
    }
}

In use:

{
    "toolbar-toggle-button":
    {
        "inherits": "ref://base-toolbar-button",

        "font": "ref://standard-headline-font",
        "titleColor": "ref://color-text-dark",

        "highlighted":
        {
            "titleColor": "ref://color-text-light"
        },

        "selected":
        {
            "titleColor": "ref://color-text-light"
        }
    }
}

Inheriting themes

Any theme may inherit values from another theme and then provide additional theming properties of it's own or override existing ones. This done via the inherits keyword.

Here's an example:

{
    "title-label:
    {
        "inherits": "ref://UILabel",
        "textColor": "#00FF00"
    }
}

Here we have created a custom theme for a UILabel that inherits the values from the UILabel base theme. It however modifies the text color to use the color green instead.

Removing inherited themes.

Theming works in an additive manner. Theme properties are added to only, never removed. In order to clear theming values that may exist on a UIView or UIViewController you may use the keyword clearPreviousThemingValues and a value of true in order to achieve this.

This is very useful. For example many different types of button themes maybe defined e.g. button, accent-button, toggle-button, alert-primary-button etc. These are themes applied to RBButton however RBButton has a base theme defined that sets the theme to button. If you apply a button theme within a theme file and choose to set it to something other that button e.g. alert-button the theming values of the base theme and the alert-button would be applied. In order to work around this you would do the following:

{
    "alert-button:
    {
        "clearPreviousThemingValues": true,
        "borderWidth": 1,
        "backgroundColor": "ref://color-accent",
        ...
    }
}

Note clearPreviousThemingValues can be used in JSON theme files and programmtically in dictionaries, see below on how to use theming in your code.

Device Specific Theme Suffixes.

Theming allows theme identifers to supply a suffix that indicates the device on which to use this value over the normal identifier value. Currently the suffix _iPad is supported. Suffixes allow targeting themes based on the device type.

Here's an example:

"layout-view":
{
    "positioner":
    {
        "margin": [ 10, 0, 10, 0 ],
        "margin_iPad": [ 25, 0, 25, 0 ],
        "spacing": 10,

        "dimensions": 1,
        "dimensions_iPad": 2
    }
}

In this example a 2 columm layout is adopted if the device is an iPad and the margins are increased. On an iPhone a single column is used.

Using themes in code

If the theme identifier of a theme corresponds to the name of an themeable Objective C view class, then it will be applied automatically.

However, you will wish to apply one of your custom themes programmatically, you may do this in two ways

Using theme identifiers

All UIView's have an associated theme property (of type RBThemeTracker). you may use the uiview.theme.identifier to programmatically set the theme. In this instance any existing theme including the base class theme will be removed and the theming values from theme specified by the identifier will be used.

For example if you would like to set the theme of a UILabel to the theme name 'title-label' as shown above you may do the following:

label.theme.identifier = @"title-label"

Using theme override dictionaries

You can programmtically retrieve a theme by the theme identifier using the RBTheming class:

NSDictionary *theme = [[RBTheming main] themeWithName:@"title-label"];

Then you can push the theme to your object (in this case an RBLabel):

[myLabel.theme pushChanges:theme];

You could at this stage push more changes until you're ready to commit them. You finish the process like this:

[myLabel.theme processChanges];

You will usually only need to push changes the once, in this case there is a convienence method applyChanges that calls pushChanges followed by processChanges.

[myLabel.theme applyChanges:theme];

You can also push theme values via your own dictionary e.g.

[myLabel.theme applyChanges:@{ "backgroundColor": "#FF0000"}]

Theming States

Many view components can have multiple states. A classic example is the button, it may be selected, highlighted or disabled. Theming allows for themes to be applied when state changes occur. States are specificlly named identifiers within the hierarchy of a theme. States allow any values to be themed as would apply in the normal state. The normal state is specified outside of the named state identifiers.

Here is an exmaple of a simple button theme with values for the normal state and the states highlighted and selected:

{
    "alert-button:
    {
        "clearPreviousThemingValues": true,

        "backgroundColor": "ref://color-accent",
        "titleColor": "ref://color-text-dark"

        "highlighted":
        {
            "titleColor": "ref://color-text-light"
            "backgroundColor": "ref://color-accent-lighter",
        },

        "selected":
        {
            "titleColor": "ref://color-text-light"
            "backgroundColor": "ref://color-accent-lighter",
        }
    }
}

In this example the normal background color is color-accent and the text color color-text-dark. When in the highlighted or selected states the colors are changed to color-accent-lighter and color-text-light respectively.

Please be aware that theming is additive therefore if you do not have a backgroundColor set in the normal state but have one set in the highlighted state when the button returns to the normal state it may still have it's last value i.e. highlighted backgroundColor set. Therefore you should ensure that you provide a normal state backgroundColor in this instance.

Theming Life Cycle

Theme values are automatically applied to UIView's when a UIView is moved to it's super view i.e. didMoveToSuperview occurs. This auto application will occur only the once. If you would like to disable this behaviour please amend the proprety view.theme.shouldAutoApplyOnFirstAppearance after instantiating your view.

The exception automatic theme application on didMoveToSuperview is RBLazyLayoutView. This applies theming to cell views based on the method/parameters passed to the reusableCellWithType methods.

To disable theming for a particular view please use view.theme.disableTheming.

A similar process occurs for UIViewController's. They are themed automatically when viewWillAppear occurs.

Please note because of the life cycle management theming values applied programmtically e.g. button.backgroundColor will be overridden by the theme value (if any). In order to programmtically set values that are part of the theme please use theme dictionaries programmtically as described above e.g. [button.theme applyChanges:@{ "backgroundColor": "#FF0000"}].

To set global values for all new instantited UIView's and UIViewController's you may use [RBTheming main].disableTheming and [RBTheming main].shouldAutoApplyOnFirstAppearance. Note this will NOT affect instantiated views/view controllers.

Font Awesome Glyphs

Don't forget you may use Font Awesome icons using the glyph:// syntax within your themes for example you could theme RBRatingField like so:

{
    "RBRatingField":
    {
        "orientation": "horizontal",
        "filledImage": "glyph://star/palette-yellow-700/32",
        "unfilledImage": "glyph://star/palette-grey-500/32",
    }
}

See here for a list of supported glyphs

Default Theme with Redbeard Framework

The Redbeard Framework zip comes complete with a default theme which you should add into your application and modify to suit. Also included is a theme file for Google's Material Design Color palette. You may reference colors from the material design theme file like so: ref://palette-blue-grey-500.

Types