Follow installation instructions and import framework as below
import Doric
Colors are one of important building block along with Typography & Layout. Colors are everywhere in product and gives meaningful identity. So defining a color palette and keeping consistency is most important part while designing interface.
Color palette MainColorPalette
supports 3 color set, a Grayscale color set and a Semantic color set, however it can be further extended if required.
Best practice would be define limited number of color sets, i.e. primary color, secondary color and supplementary color along with grayscale and colors for messaging would be sufficient in most of the cases.
To create a color palette implement ColorPalette
with base
color.
For example as below creates 'Astronaut Blue' as base color. It will have 2 lighter and darker colors with default implemention by ColorPalette
.
public struct BrandPrimaryColor: ColorPalette {
/// 'Astronaut Blue' color, HEX #013e62, RGB (1,62,98)
public static let base = UIColor("#013e62")
}
Define additional secondary and supplementary colors and compose them into AppColorPalette
:
// Define color palette
struct AppColorPalette: MainColorPalette {
static let primary: ColorPalette.Type = BrandPrimaryColor.self
static let secondary: ColorPalette.Type = BrandSecondaryColor.self
static let supplementary: ColorPalette.Type = SupplimantoryColor.self
static let semantic: SemanticColorPalette.Type = DefaultSemanticColorPalette.self
static let grayscale: LargerColorPalette.Type = DefaultGrayScalePalette.self
}
// Design System
struct DesignSystem {
// Define color palette
static let colorPalette: MainColorPalette.Type = AppColorPalette.self
}
// Access primary color as below
DesignSystem.colorPalette.primary.base
In color theory, a tint reduces darkness, while a shade increases darkness.
Lighter and darker colors are produced by adjusting UIColor
's brightness and saturations.
By default ColorPalette
will generate two darker and lighter colors based on defined base
color.
But optionally can be defined as below :
public struct BrandPrimaryColor1: ColorPalette {
// more lighter shade of base
public static let lighten2 = UIColor("#668ba0")
// lighter shade of base
public static let lighten1 = UIColor("#336481")
// base color
public static let base = UIColor("#013e62")
// darker color of base
public static let darken1 = UIColor("#00314e")
// more darker color of base
public static let darken2 = UIColor("#00253a")
}
With primary and secondary colors an application also needs few grayscale colors too. Grayscale colors are used for text, lines, borders and view backgrounds.
Framework has built-in grayscale color palette with 9 shades and tints of gray. Use DefaultGrayScalePalette
or if required specific gray colors then implement color palette protocol same as above.
static let grayscale: LargerColorPalette.Type = DefaultGrayScalePalette.self
App also needs colors for messaging. So there is need of colors that can be used for success, warning, danger, error, information etc. Semantic color sets are unique and different then brand primary, secondary colors.
By default framework provides SemanticColorPalette which has color set for error, warning, success, info.
static let semantic: SemanticColorPalette.Type = DefaultSemanticColorPalette.self
Implement SemanticColorPalette
protocol in case if you need different set of semantic colors.
GradientColor
protocol provides gradient definition with start & end colors and start & end points. It is just and helper to create gradient using CAGradientLayer
.
// Left-to-Right gradient color can be defined as below
struct CardGradientColor: GradientColor {
let startColor = UIColor("#1e3c72")
let endColor = UIColor("#2a5298")
}
// Single color with darker/light shade gradient color can be defined as below.
//`endColor` will be darker or lighter of `startColor`
struct ShadedGradientColor: GradientColor {
let startColor = UIColor("#1e3c72")
}
This can be used to create GradientView
instance. UIColor
also implements GradientColor
protocol, so it can be used directly to create gradients wherever GradientColor
definations are passed.
Since color palettes are based on protocols, you can define as many as unique colors using ColorPalette
& LargerColorPalette
protocols same like primary color declared as above.
Typography is one of the core element of design system. Typography is a collection of individual styles used across an app. To create an appropriate visual hierarchy on each screen, we will need to define a number of different font sizes. Also it may change according to users preferred content category.
Doric
ensures that typographic systems can stand up to change at scale. It supports fixed sized and dynamic sized scalable fonts. Also it provides both built-in text styles and custom text style, however use built-in text styles whenever possible.
iOS includes the following text styles:
- Large Title
- Title 1
- Title 2
- Title 3
- Headline
- Body
- Callout
- Subhead
- Footnote
- Caption 1
- Caption 2
See Typography
Doric
has default implemented SystemTypography
which supports all Text Styles with System Font.
San Francisco (SF) is the system typeface in iOS.
Example usage as below -
import Doric
// Global Design System
struct DesignSystem {
// Define Typography
static let typography: SystemTypography.Type = SystemTypography.self
}
Get body
font as below
let bodyLabel : UILabel
.....
.....
// Get preferred body fonts
bodyLabel.font = DesignSystem.typography.preferredFont(forTextStyle: .body)
Doric
supports all UIFontTextStyle
, it is preferred to use built-in text styles. Below will give body
fonts.
// Get body fonts which is 17.0 by default.
bodyLabel.font = DesignSystem.typography.font(forTextStyle: .body)
See UIFontTextStyle for more details
When you need scalable fonts as per user's preferred content size category use below method.
bodyLabel.font = DesignSystem.typography.preferredFont(forTextStyle: .body)
See UIContentSizeCategory for more details
It is best practice to use built-in font style (similar to UIFontTextStyle
), but you can still define your custom Font Style.
Example Custom Font Style - 4 styles contentHeading, contentBody, contentInstruction, brand
enum OpenSansStyle: String {
case contentHeading
case contentBody
case contentInstruction
case brand
}
See Typography+OpenSans.swift
example in demo.
Alignment & White spaces are other fundamental parts of interface composition. So spaces between buttons, labels, views and other margins matters most and it is expected to be consistence in most of the cases.
For iOS views are arranged using auto layouts and/or manual frame manipulation.
Doric provides NSLayoutAnchor
based tiny constraint creation utility to add constraints with consistence space. Because it is statically typed it helps to avoid common mistakes. Instead of adding hardcoded margins and constants, it supports creating constraints via programmatically with predefined value sets.
For example use Space
enum with set of few predefined space values.
// Container
let containerView = UIView()
// Child
let childView = UIView()
containerView.addSubview(childView)
// Create constraint to keep child view left aligned to containerView
childView.anchorLeft(containerView)
// OR
// Create constraint to keep child view left aligned to containerView
// with leading Space.p2 margin which is 16.0,
// this ensures spacing is limited to defined sets.
childView.anchorLeft(containerView, constant: .equalTo(Space.p2))
// Keep childView in centre of containerView
childView.anchorCenter(containerView)
// Set predefined button sizes
let button = UIButton()
....
button.anchorButtonHeight(.medium)
Space
enum provides predefined values, however if needed you can define custom spaces as below, auto layout wrapper takes any type which implements LayoutValueRepresentable
.
It would be good practice if space sets are predefined and limited.
// Example to create custom space
enum CustomSpace: CGFloat, LayoutValueRepresentable {
case p1 = 3.0
case p2 = 6.0
case p3 = 9.0
case p4 = 12.0
}
childView.anchorLeft(containerView, constant: .equalTo(CustomSpace.p2))
Framework provides built-in set of various size charts. For example borders, corner radius, button sizes, icon sizes etc.
Use Scale
or FullScale
protocols to define custom size charts.
Use predefined sets of corner radius and borders as below
static let cornerRadius: CornerRadiusSize = CornerRadius.self
static let border: BorderSize = Border.self
Currently frameworks supports to create template icons with tinted color, future plan is expand this framework for icon fonts and various image processing utilities.
Example template image can created with primary color as below :
let image1 = UIImage.template(named: demoImageName, tintColor: primaryColor)
Framework provides a small utility tool to help and debug views.
For example show grid/graph on top of current interface as below
Doric.shared.isHidden = false
To show guide on text label as below.
let guidelines: UIView.Guideline = .all
textLabel?.showGuide(guideline: guidelines)
It just adds views equant to target view's edges, dimensions and base lines.