Skip to content
This repository has been archived by the owner on Jul 2, 2024. It is now read-only.

inloop/Styles

Repository files navigation

alt text Artwork: Josef Čapek - 7. Povídání o pejskovi a kočičce (7/43)

Styles

Styling framework that works
A declarative and type-safe framework for beautiful applications.

Table of Contents

Features

  • declarative: You describe the style, framework will do the rest
  • type-safe: Type system will help you describe your style
  • plays nice with UIAppearance: In fact its designed for it.
  • usable as settable property: Not only works as UIAppearance proxy, but also as settable property
  • supports UIControl states and UITextField editing: You're gonna ❤︎ it.
  • saves you from the NSAttributedString1: Just work with Strings.
  • text, color and layer properties: Custom line height, letter spacing, corners? Me gusta.
  • supports Styles updating: Design base style for you app and update it on the fly as needed.
  • Zeplin extension: Just copy styles over to your project. Super easy. Check out: https://github.com/inloop/styles-zeplin-extension

1: In some cases.

Requirements

  • iOS 10.0+
  • Xcode 9.2+
  • Swift 4.1+

Examples

For full set of feature examples refer to our wiki page.

TextStyle

let h1 = TextStyle(
    .font(.preferredFont(forTextStyle: .largeTitle)),
    .foregroundColor(.black),
    .backgroundColor(.yellow),
    .letterSpacing(1.5),
    .paragraphStyle([
        .alignment(.natural),
        .lineSpacing(2.5)
    ]),
    .strikethrought(TextDecoration(
        style: .thick,
        pattern: .dash
    )),
    .underline(TextDecoration(
        style: .single,
        pattern: .dashDotDot,
        byWord: true,
        color: .red
    ))
)

UILabel.appearance().textStyle = h1
UIButton.appearance().setTextStyle(h1, for: .normal)
let h1 = TextStyle(
    .font(.preferredFont(forTextStyle: .largeTitle)),
    .foregroundColor(.black),
    .backgroundColor(.yellow)
)

myLabel.textStyle = h1

Updating TextStyle

let footnote = TextStyle(
    .font(.preferredFont(forTextStyle: .footnote))
)

let blueFootnote = footnote.updating(.foregroundColor(.blue))

myLabel.textStyle = blueFootnote
let blueFootnote = TextStyle(
    .font(.preferredFont(forTextStyle: .footnote))
    .foregroundColor(.blue)
)

let redFootnote = blueFootnote.updating(.foregroundColor(.red))

myLabel.textStyle = redFootnote

Combining TextStyle

let blueFootnote = TextStyle(
    .font(.preferredFont(forTextStyle: .footnote))
    .foregroundColor(.blue)
)

let yellowBackground = TextStyle(
    .backgroundColor(.yellow)
)

myLabel.textStyle = blueFootnote + yellowBackground
let h1 = TextStyle(
    .font(.preferredFont(forTextStyle: .largeTitle)),
    .letterSpacing(1.5),
    .paragraphStyle([
        .alignment(.natural),
        .lineSpacing(2.5)
    ]),
    .strikethrought(TextDecoration(
        style: .thick,
        pattern: .dash
    )),
    .underline(TextDecoration(
        style: .single,
        pattern: .dashDotDot,
        byWord: true,
        color: .red
    ))
)

let blue = TextStyle(
    .foregroundColor(.blue)
)

let yellowBackground = TextStyle(
    .backgroundColor(.yellow)
)

let secret = TextStyle(
    .writingDirectionOverrides([
        .rightToLeftOverride
    ])
)

let title = h1 + blue + yellowBackground

myLabel.textStyle = title
secretMessageLabel.textStyle = h1 + secret

TextEffects

let bigRed: TextStyle = ...
let bigGreen: TextStyle = ...
let smallCyan: TextStyle = ...

let bigRedFirstWord = TextEffect(
    style: bigRed,
    matching: First(occurenceOf: "Styles")
)

let bigGreenLastWord = TextEffect(
    style: bigGreen,
    matching: Block { $0.range(of: "awesome") }
)

let everyOtherTildaCyan = TextEffect(
    style: smallCyan,
    matching: Regex("~.*?(~)")
)

let tint = TextStyle(
    .foregroundColor(.red)
)

let logo: UIImage = ...
let logoBeforeCompanyName = TextEffect(image: logo, style: tint, matching: First(occurenceOf: "INLOOPX"))

let styleWithEffects = TextStyle(
    .font(.preferredFont(forTextStyle: .body)),
    .backgroundColor(.yellow),
    effects: [
        bigRedFirstWord,
        bigGreenLastWord,
        everyOtherTildaCyan,
        logoBeforeCompanyName
    ]
)

ViewStyle

let pill = ViewStyle(
     .cornerRadius(10),
     .borderWidth(3),
     .borderColor(.red),
     .opacity(0.8)
)

UILabel.appearance().viewStyle = pill
let red = ViewStyle(
    .backgroundColor(.red),
    .tintColor(.red),
    .borderColor(.red),
    .borderWidth(0.5),
    .shadow(Shadow(
        color: .red,
        offset: UIOffset(horizontal: 0, vertical: 8),
        radius: 16
    ))
)

let blue = ViewStyle(
    .borderColor(.blue),
    .borderWidth(0.5),
    .shadow(.none)
)

UITextField.appearance().setViewStyle(red, for: .editing)
UITextField.appearance().setViewStyle(blue, for: .inactive)
UITextView.appearance().setViewStyle(red, for: .editing)
UITextView.appearance().setViewStyle(blue, for: .inactive)
let blue = ViewStyle(
    .borderColor(.blue),
    .borderWidth(0.5),
    .cornerRadius(10)
)

myButton.viewStyle = blue

Layer properties

If you set any of [.borderColor, .borderWidth, .cornerRadius, .opacity, .shadow] properties for particular states to UITextView or UITextField, the Styles will require to match properties under the hood. If you don't do so the styling becomes invalid because layer properties are not reset when state is changed. It is up to you to define the style. Below is the example which produces assertion error and second snippet is valid configuration.

let redBorder = ViewStyle(
	.borderColor(.red),
	.borderWidth(1.5)
)

let roundedCorners = ViewStyle(
	.cornerRadius(10)
)

UITextField.appearance().setViewStyle(redBorder, for: .editing)
// It throws an assertion error
// because rounded corners is missing .borderColor & .borderWidth 
UITextField.appearance().setViewStyle(roundedCorners, for: .inactive)
let redRoundedBorder = ViewStyle(
	.borderColor(.red),
	.borderWidth(1.5),
	.cornerRadius(10)
)

let redFlatBorder = ViewStyle(
	.borderColor(.red),
	.borderWidth(1.5),
	.cornerRadius(0)
)

UITextField.appearance().setViewStyle(redRoundedBorder, for: .editing)
UITextField.appearance().setViewStyle(redFlatBorder, for: .inactive)

Updating ViewStyle

let app = ViewStyle(
    .borderWidth(0.5),
    .cornerRadius(10)
)

let blue = app.updating(.borderColor(.blue))
let app = ViewStyle(
    .borderWidth(0.5),
    .cornerRadius(radius: 10)
)

let thick = app.updating(.borderWidth(3))

Combining ViewStyle

let app = ViewStyle(
    .borderWidth(0.5),
    .cornerRadius(10)
)

let semiVisible = ViewStyle(
    .opacity(0.5)
)

myLabel.viewStyle = app + semiVisible
let app = ViewStyle(
    .borderWidth(0.5),
    .cornerRadius(10)
)

let semiVisible = ViewStyle(
    .opacity(0.5)
)

let blue = ViewStyle(
    .backgroundColor(.blue)
)

let labelStyle = app + semiVisible + blue

myLabel.viewStyle = labelStyle

SwitchStyle

let prettySwitchStyle = SwitchStyle(
    .onTintColor(.red),
    .tintColor(.blue),
    .thumbTintColor(.yellow)
)

// style only one switch
mySwitch.switchStyle = prettySwitchStyle

// style all switches
UISwitch.appearance().switchStyle = prettySwitchStyle

Installation

CocoaPods

CocoaPods is a dependency manager for Cocoa projects. You can install it with the following command:

$ gem install cocoapods

CocoaPods 1.1+ is required to build Styles.

To integrate Styles into your Xcode project using CocoaPods, specify it in your Podfile:

source 'https://github.com/CocoaPods/Specs.git'
platform :ios, '10.0'
use_frameworks!

target '<Your Target Name>' do
    pod 'Styles', :git => 'https://github.com/inloop/Styles.git'
end

Then, run the following command:

$ pod install

Carthage

Carthage is a decentralized dependency manager that builds your dependencies and provides you with binary frameworks.

You can install Carthage with Homebrew using the following command:

$ brew update
$ brew install carthage

To integrate Styles into your Xcode project using Carthage, specify it in your Cartfile:

github "inloop/Styles"

Run carthage update to build the framework and drag the built Styles.framework into your Xcode project.

Contributions

ARE WELCOME! 🖖

License

Styles is available under the MIT license. See the LICENSE file for more info.

Authors

Built with ❤︎ at INLOOPX