Skip to main content

IncdTheme guide

IncdTheme enables you to change existing default theme or create a new one from scratch.

Available customizations:

  • Colors
  • Fonts
  • Buttons
  • Labels
  • Custom UI Components (such as Camera Feedback View)

Customization mapping can be found here. Assets and Strings mapping can be found here. Check IncdTheme structure tree inside Xcode for full list of customization. Check ThemeBuilder.swift for a concrete example on how to build a full custom theme.

Usage​

Change existing properties of theme​

// 1. Copy current theme
var customTheme = IncdTheme.current

// 2. Edit
customTheme.colors.accent = someAccentUIColor
customTheme.fonts.title = someUIFont
customTheme.labels.title.textColor = someTitleUIColor
customTheme.buttons.primary.states.normal.borderColor = someBorderUIColor
customTheme.buttons.primary.medium.contentInsets = someUIEdgeInsets
// etc.

// 3. Apply edited theme
IncdTheme.current = customTheme

// 4. Apply customization via JSON
let jsonTheme: String // a JSON string with theme configuration check `Omni/Resources/IncdTheme.json` for a full example.
IncdTheme.loadJsonTheme(jsonTheme)

Create a new theme​

  // 1. Build Theme
let coolTheme = buildCustomTheme()
// 2. Apply edited theme
IncdTheme.current = coolTheme

...

func buildCustomTheme() -> ThemeConfiguration {

let colorsConfig = ColorsConfiguration(accent: Colors.accent,
primary: Colors.primary,
background: Colors.background,
secondaryBackground: Colors.secondaryBackground,
success: Colors.success,
error: Colors.error,
warning: Colors.warning,
cancel: Colors.cancel)

let fontsConfig = FontsConfiguration(title: Fonts.title,
hugeTitle: Fonts.hugeTitle,
subtitle: Fonts.subtitle,
boldedSubtitle: Fonts.boldedSubtitle,
smallSubtitle: Fonts.smallSubtitle,
info: Fonts.info,
body: Fonts.body,
boldedBody: Fonts.boldedBody,
buttonBig: Fonts.buttonBig,
buttonMedium: Fonts.buttonMedium,
textFieldBig: Fonts.textFieldBig,
textFieldMedium: Fonts.textFieldMedium)

let buttonsConfig = ButtonsConfiguration(primary: primaryButton,
secondary: secondaryButton,
text: textButton,
help: helpButton)

let labelsConfig = LabelsConfiguration(title: titleLabelConfig,
secondaryTitle: secondaryTitleLabelConfig,
subtitle: subtitleLabelConfig,
secondarySubtitle: secondarySubtitleLabelConfig,
smallSubtitle: smallSubtitleLabelConfig,
info: infoLabelConfig,
secondaryInfo: secondaryInfoLabelConfig,
body: bodyLabelConfig,
secondaryBody: secondaryBodyLabelConfig,
code: codeLabelConfig)

let customComponents = CustomComponentsConfiguration(cameraFeedback: cameraFeedback,
idCaptureHelp: idCaptureHelp,
idSideLabel: idSideLabel,
separator: separator,
signature: signature,
idAutocaptureCountdownConfiguration: idAutocaptureCountdownConfiguration,
idCaptureFrame: idCaptureFrame)

return ThemeConfiguration(colors: colorsConfig,
fonts: fontsConfig,
buttons: buttonsConfig,
labels: labelsConfig,
customComponents: customComponents)
}

// MARK: - Buttons

private var primaryButton: ButtonConfiguration {
let normal = ButtonThemedState(backgroundColor: Colors.accent,
cornerRadius: 6,
shadowColor: UIColor.black.cgColor,
shadowOffset: CGSize(width: 0, height: 5),
shadowOpacity: 0.15,
shadowRadius: 9,
textColor: .white)
var highlighted = normal
highlighted.backgroundColor = Colors.primary
highlighted.textColor = Colors.accent
highlighted.transform = .init(scaleX: 0.93, y: 0.93)
highlighted.cornerRadius = 12
var disabled = normal
disabled.backgroundColor = .incdDisabled
disabled.textColor = .white

let big = ButtonSizeVariant(minWidth: UIScreen.main.bounds.width-32.0,
contentInsets: Insets.bigInsets)

let medium = ButtonSizeVariant(height: 32.0,
minWidth: (UIScreen.main.bounds.width-Margins.tutorialID)/2,
contentInsets: Insets.mediumInsets)

return ButtonConfiguration(states: .init(normal: normal, highlighted: highlighted, disabled: disabled),
big: big,
medium: medium)
}

...

private var helpButton: ButtonConfiguration {
let normal = ButtonThemedState(alpha: 1.0,
backgroundColor: .incdBackground,
borderColor: .incdPrimary,
borderWidth: 1.0,
textColor: .incdPrimary,
iconImageName: "incdOnboarding.help.clipped",
iconTintColor: .incdPrimary,
iconPosition: .right,
iconPadding: 8)
return ButtonConfiguration(states: .init(normal: normal))
}

...


// MARK: - Labels

private var titleLabelConfig: LabelConfiguration {
LabelConfiguration(textColor: Colors.primaryText)
}

...

// MARK: - Camera Feedback

private var cameraFeedbackConfig: CameraFeedbackConfiguration {
CameraFeedbackConfiguration(alpha: 0.75,
backgroundColor: Colors.secondaryBackground,
cornerRadius: 6,
textBackgroundColor: .black.withAlphaComponent(0.3),
textColor: Colors.secondaryText)
}

private var idCaptureHelp: IDCaptureHelpConfiguration {
IDCaptureHelpConfiguration(commonIssueLayoutOrientation: .horizontal)
}

private var idSideLabel: IDSideLabelConfiguration {
IDSideLabelConfiguration(alpha: 0.8, backgroundColor: Colors.secondaryBackground, borderColor: Colors.accent, borderWidth: 1.0, cornerRadius: 16)
}

private var separatorConfig: SeparatorConfiguration {
SeparatorConfiguration(alpha: CGFloat = 0.0,
color: UIColor = .incdSecondaryBackground,
cornerRadius: CGFloat = 0.5,
padding: CGFloat = 16,
thickness: CGFloat = 1)
}

...

// Where:

private struct Insets {
static var bigInsets = some UIEdgeInsets
...
}

private struct Margins {
static var tutorialID = some CGFloat
...
}

private struct Colors {
static var accent = some UIColor
...
}

private struct Fonts {
static var title = some UIFont
...
}

Create a theme by JSON​

Loading a JSON file for the theme can be done the following way:

  guard let path = Bundle.main.path(forResource: "Incode", ofType: "json"),
let data = try? String(contentsOfFile: path, encoding: String.Encoding.utf8) else {
fatalError("Bad JSON or not found")
}
IncdTheme.loadJsonTheme(data)

Example of JSON contents of a theme file.

{
"colors": {
"accent": "#00B2FD",
"primary": "#20263D",
"background": "#FFFFFF",
"secondaryBackground": "#E9E9EB",
"success": "#0CD5A2",
"error": "#FF5C6F",
"cancel": "#20263D",
"cancelDark": "#E9E9EB",
"warning": "#F3AB3C",
"cancel": "#20263D",
"primaryDark": "#E9E9EB"
},
"fonts": {
"buttonBig": {
"name": "CircularXXTT-Black",
"size": "20"
},
"buttonMedium": {
"name": "CircularXXTT-Black",
"size": "16"
},
"buttonSmall": {
"name": "CircularXXTT-Black",
"size": "12"
},
"title": {
"name": "CircularXXTT-Black",
"size": "25"
},
"hugeTitle": {
"name": "CircularXXTT-Black",
"size": "40"
},
"subtitle": {
"name": "CircularXXTT-Black",
"size": "18"
},
"boldedSubtitle": {
"name": "CircularXXTT-Bold",
"size": "18"
},
"smallSubtitle": {
"name": "CircularXXTT-Black",
"size": "14"
},
"info": {
"name": "CircularXXTT-Black",
"size": "16"
},
"body": {
"name": "CircularXXTT-Medium",
"size": "14"
},
"boldedBody": {
"name": "CircularXXTT-Bold",
"size": "14"
},
"textFieldBig": {
"name": "CircularXXTT-Black",
"size": "20"
},
"textFieldMedium": {
"name": "CircularXXTT-Black",
"size": "15"
},
"additionalTextHeight": [{
"name": "CircularXXTT-Bold",
"size": "14",
"height": 0
}],
"feedbackSmall": {
"name": "CircularXXTT-Bold",
"size": "18"
},
"feedbackLarge": {
"name": "CircularXXTT-Bold",
"size": "24"
}
},
"buttons": {
"primary": {
"states": {
"normal": {
"animateStateChange": true,
"alpha": 1,
"backgroundColor": "#00B2FD",
"borderColor": "",
"borderWidth": 0,
"cornerRadius": 32,
"shadowColor": "#000000",
"shadowOffset": [0,5],
"shadowOpacity": 0.15,
"shadowRadius": 9,
"textColor": "#FFFFFF",
"transform": {
"a": 1,
"b": 0,
"c": 0,
"d": 1,
"tx": 0,
"ty": 0
}
},
"highlighted": {
"animateStateChange": true,
"alpha": 1,
"backgroundColor": "#20263D",
"borderColor": "",
"borderWidth": 0,
"cornerRadius": 32,
"shadowColor": "#000000",
"shadowOffset": [0,5],
"shadowOpacity": 0.15,
"shadowRadius": 9,
"textColor": "#00B2FD",
"transform": {
"a": 1,
"b": 0,
"c": 0,
"d": 1,
"tx": 0,
"ty": 0
}
},
"disabled": {
"animateStateChange": true,
"alpha": 1,
"backgroundColor": "#E9E9EB",
"borderColor": "",
"borderWidth": 0,
"cornerRadius": 32,
"shadowColor": "#000000",
"shadowOffset": [0,5],
"shadowOpacity": 0,
"shadowRadius": 9,
"textColor": "#FFFFFF",
"transform": {
"a": 1,
"b": 0,
"c": 0,
"d": 1,
"tx": 0,
"ty": 0
}
}
},
"big": {
"height": 64,
"minWidth": 200,
"contentInsets": {
"top": 19,
"left": 32,
"bottom": 19,
"right": 32
},
"kerning": 0
},
"medium": {
"height": 46,
"minWidth": 0,
"contentInsets": {
"top": 12,
"left": 24,
"bottom": 12,
"right": 24
},
"kerning": 0
}
},
"secondary": {
"states": {
"normal": {
"animateStateChange": true,
"alpha": 1,
"backgroundColor": "#FFFFFF",
"borderColor": "#20263D",
"borderWidth": 1,
"cornerRadius": 32,
"shadowColor": "",
"shadowOffset": [0,0],
"shadowOpacity": 0,
"shadowRadius": 0,
"textColor": "#20263D",
"transform": {
"a": 1,
"b": 0,
"c": 0,
"d": 1,
"tx": 0,
"ty": 0
}
},
"highlighted": {
"animateStateChange": true,
"alpha": 1,
"backgroundColor": "#20263D",
"borderColor": "#20263D",
"borderWidth": 1,
"cornerRadius": 32,
"shadowColor": "",
"shadowOffset": [0,0],
"shadowOpacity": 0,
"shadowRadius": 0,
"textColor": "#00B2FD",
"transform": {
"a": 1,
"b": 0,
"c": 0,
"d": 1,
"tx": 0,
"ty": 0
}
},
"disabled": {
"animateStateChange": true,
"alpha": 1,
"backgroundColor": "#FFFFFF",
"borderColor": "#E9E9EB",
"borderWidth": 1,
"cornerRadius": 32,
"shadowColor": "",
"shadowOffset": [0,0],
"shadowOpacity": 0,
"shadowRadius": 0,
"textColor": "#E9E9EB",
"transform": {
"a": 1,
"b": 0,
"c": 0,
"d": 1,
"tx": 0,
"ty": 0
}
}
},
"big": {
"height": 64,
"minWidth": 200,
"contentInsets": {
"top": 19,
"left": 32,
"bottom": 19,
"right": 32
},
"kerning": 0
},
"medium": {
"height": 46,
"minWidth": 0,
"contentInsets": {
"top": 12,
"left": 24,
"bottom": 12,
"right": 24
},
"kerning": 0
}
},
"text": {
"states": {
"normal": {
"animateStateChange": true,
"alpha": 1,
"backgroundColor": "",
"borderColor": "",
"borderWidth": 0,
"cornerRadius": 0,
"shadowColor": "",
"shadowOffset": [0,0],
"shadowOpacity": 0,
"shadowRadius": 0,
"textColor": "#20263D",
"transform": {
"a": 1,
"b": 0,
"c": 0,
"d": 1,
"tx": 0,
"ty": 0
}
},
"highlighted": {
"animateStateChange": true,
"alpha": 1,
"backgroundColor": "",
"borderColor": "",
"borderWidth": 0,
"cornerRadius": 0,
"shadowColor": "",
"shadowOffset": [0,0],
"shadowOpacity": 0,
"shadowRadius": 0,
"textColor": "#00B2FD",
"transform": {
"a": 1,
"b": 0,
"c": 0,
"d": 1,
"tx": 0,
"ty": 0
}
},
"disabled": {
"animateStateChange": true,
"alpha": 1,
"backgroundColor": "",
"borderColor": "",
"borderWidth": 0,
"cornerRadius": 0,
"shadowColor": "",
"shadowOffset": [0,0],
"shadowOpacity": 0,
"shadowRadius": 0,
"textColor": "#E9E9EB",
"transform": {
"a": 1,
"b": 0,
"c": 0,
"d": 1,
"tx": 0,
"ty": 0
}
}
},
"big": {
"height": 40,
"minWidth": 200,
"contentInsets": {
"top": 8,
"left": 16,
"bottom": 8,
"right": 16
},
"kerning": 0
},
"medium": {
"height": 30,
"minWidth": 0,
"contentInsets": {
"top": 12,
"left": 24,
"bottom": 12,
"right": 24
},
"kerning": 0
}
},
"help": {
"states": {
"normal": {
"animateStateChange": true,
"alpha": 1,
"backgroundColor": "#00B2FD",
"borderColor": "",
"borderWidth": 0,
"cornerRadius": 32,
"shadowColor": "#000000",
"shadowOffset": [0,5],
"shadowOpacity": 0.15,
"shadowRadius": 9,
"textColor": "#FFFFFF",
"transform": {
"a": 1,
"b": 0,
"c": 0,
"d": 1,
"tx": 0,
"ty": 0
}
},
"highlighted": {
"animateStateChange": true,
"alpha": 1,
"backgroundColor": "#20263D",
"borderColor": "",
"borderWidth": 0,
"cornerRadius": 32,
"shadowColor": "#000000",
"shadowOffset": [0,5],
"shadowOpacity": 0.15,
"shadowRadius": 9,
"textColor": "#00B2FD",
"transform": {
"a": 1,
"b": 0,
"c": 0,
"d": 1,
"tx": 0,
"ty": 0
}
},
"disabled": {
"animateStateChange": true,
"alpha": 1,
"backgroundColor": "#E9E9EB",
"borderColor": "",
"borderWidth": 0,
"cornerRadius": 32,
"shadowColor": "#000000",
"shadowOffset": [0,5],
"shadowOpacity": 0,
"shadowRadius": 9,
"textColor": "#FFFFFF",
"transform": {
"a": 1,
"b": 0,
"c": 0,
"d": 1,
"tx": 0,
"ty": 0
}
}
},
"big": {
"height": 64,
"minWidth": 200,
"contentInsets": {
"top": 19,
"left": 32,
"bottom": 19,
"right": 32
},
"kerning": 0
},
"medium": {
"height": 46,
"minWidth": 0,
"contentInsets": {
"top": 12,
"left": 24,
"bottom": 12,
"right": 24
},
"kerning": 0
}
},
"chooser": {
"states": {
"normal": {
"animateStateChange": true,
"alpha": 1,
"backgroundColor": "#20263D",
"borderColor": "",
"borderWidth": 0,
"cornerRadius": 15,
"shadowColor": "#000000",
"shadowOffset": [0,5],
"shadowOpacity": 0.15,
"shadowRadius": 9,
"textColor": "#010101",
"transform": {
"a": 1,
"b": 0,
"c": 0,
"d": 1,
"tx": 0,
"ty": 0
}
},
"highlighted": {
"animateStateChange": true,
"alpha": 1,
"backgroundColor": "#00B2FD",
"borderColor": "",
"borderWidth": 0,
"cornerRadius": 15,
"shadowColor": "#000000",
"shadowOffset": [0,5],
"shadowOpacity": 0.15,
"shadowRadius": 9,
"textColor": "#010101",
"transform": {
"a": 1,
"b": 0,
"c": 0,
"d": 1,
"tx": 0,
"ty": 0
}
},
"disabled": {
"animateStateChange": true,
"alpha": 1,
"backgroundColor": "#E9E9EB",
"borderColor": "",
"borderWidth": 0,
"cornerRadius": 15,
"shadowColor": "#000000",
"shadowOffset": [0,5],
"shadowOpacity": 0,
"shadowRadius": 9,
"textColor": "#010101",
"transform": {
"a": 1,
"b": 0,
"c": 0,
"d": 1,
"tx": 0,
"ty": 0
}
}
},
"big": {
"height": 64,
"minWidth": 200,
"contentInsets": {
"top": 19,
"left": 32,
"bottom": 19,
"right": 32
},
"kerning": 0
},
"medium": {
"height": 46,
"minWidth": 0,
"contentInsets": {
"top": 12,
"left": 24,
"bottom": 12,
"right": 24
},
"kerning": 0
}
}
},
"labels": {
"title": {
"textAlignment": "center",
"textColor": "#20263D",
"kerning": 0
},
"secondaryTitle": {
"textAlignment": "center",
"textColor": "#FFFFFF",
"kerning": 0
},
"subtitle": {
"textAlignment": "center",
"textColor": "#20263D",
"kerning": 0
},
"secondarySubtitle": {
"textAlignment": "center",
"textColor": "#FFFFFF",
"kerning": 0
},
"smallSubtitle": {
"textAlignment": "center",
"textColor": "#20263D",
"kerning": 0
},
"info": {
"textAlignment": "center",
"textColor": "#636670",
"kerning": 0
},
"secondaryInfo": {
"textAlignment": "center",
"textColor": "#FFFFFF",
"kerning": 0
},
"body": {
"textAlignment": "center",
"textColor": "#20263D",
"kerning": 0
},
"secondaryBody": {
"textAlignment": "center",
"textColor": "#FFFFFF",
"kerning": 0
},
"code": {
"textAlignment": "center",
"textColor": "#20263D",
"kerning": 16
}
},
"customComponents": {
"cameraFeedback": {
"alpha": 0.8,
"backgroundColor": "#000000",
"cornerRadius": 20,
"textBackgroundColor": "",
"textColor": "#FFFFFF"
},
"idCaptureHelp": {
"commonIssueLayoutOrientation": "horizontal"
},
"idSideLabel": {
"alpha": 1,
"backgroundColor": "#FFFFFF",
"borderColor": "",
"borderWidth": 0,
"cornerRadius": 5
},
"separator": {
"alpha": 1.0,
"color": "#20263D",
"cornerRadius": 0,
"padding": 24,
"thickness": 1
},
"signature": {
"signatureColor": "#04bd19",
"canvasBorderColor": "#ec03fc",
"canvasBackgroundColor": "#FFFFFF"
},
"idAutocaptureCountdown": {
"backgroundColor": "#00B2FD",
"numberColor": "#FFFFFF"
},
"idCaptureFrame": {
"overlayColor": "#000000",
"overlayAlpha": 0.44
},
"videoSelfie": {
"overlayColor": "#000000",
"overlayAlpha": 0.44,
"progressBarColor": "#FFFFFF7F",
"progressBarSelectedColor": "#FFFFFF"
}
}
}