Skip to content

Instantly share code, notes, and snippets.

@nunogoncalves
Created June 3, 2017 10:09
Show Gist options
  • Save nunogoncalves/5df6502b3178d0ce1d766c87ed43f7c4 to your computer and use it in GitHub Desktop.
Save nunogoncalves/5df6502b3178d0ce1d766c87ed43f7c4 to your computer and use it in GitHub Desktop.
Easily apply theme styles to any UIView!
Make the following possible!
MarvelTheme.TextStyle.CommicSans.apply(to: label)
MarvelTheme.ColorStyle.dangerColor.apply(to: label)
// ============================== StylableView protocol ==============================
// Adds a consistent styling API to any UIView.
// The example here allows for any UIView subclass to have a way of setting its font type.
protocol StylableView {
func apply(font: UIFont?)
}
extension UIView : StylableView {
//we can't really add this as a StylableView extension because
//the views are being styled as StylableView, and even if the subclasses
//override the default implementation, they won't be recognized.
func apply(font: UIFont?) {}
}
extension UILabel {
override func apply(font: UIFont?) {
self.font = font
}
}
extension UIButton {
override func apply(font: UIFont?) {
titleLabel?.font = font
}
}
//Now we have a consistent way of setting font of both labels and buttons.
struct UIViewStyle {
let styling: (StylableView) -> ()
func apply(to stylabelView: StylableView) {
styling(stylabelView)
}
static func compose(styles: UIViewStyle...) -> UIViewStyle {
return UIViewStyle {
for style in styles {
style.apply(to: $0)
}
}
}
}
// Basic example view
let whiteStyle = UIViewStyle { ($0 as? UIView)?.backgroundColor = .white } //We can improve this with a consistent API
let blueStyle = UIViewStyle { ($0 as? UIView)?.backgroundColor = .blue }
let v = UIView(frame: CGRect(x: 0, y: 0, width: 100, height: 100))
whiteStyle.apply(to: v)
v // background becomes white
blueStyle.apply(to: v)
v // background becomes blue
let h1 = UIViewStyle { $0.apply(font: UIFont(name: "ComicSansRegular", size: 10)) }
h1.apply(to: UIView()) //Does nothing because the UIView method is empty.
h1.apply(to: UILabel() //Applies the CommicSansRegular font to the label
============================== Theming ==============================
protocol ColorStylable {
static var mainColor: UIViewStyle { get }
}
protocol TextStylable {
static var mainColor: UIViewStyle { get }
}
protocol Themable {
static var ColorStyle: ColorStylable.Type { get }
static var TextStyle: TextStylable.Type { get }
}
struct MarvelColorStyle : ColorStylable {
static let mainColor = UIViewStyle { ($0 as? UIView)?.backgroundColor = .red }
}
struct MarvelTextStyle: TextStylable {}
struct MarvelTheme : Themable {
static var TextStyle: TextStylable.Type = MarvelTextStyle.self
static var ColorStyle: ColorStylable.Type = MarvelColorStyle.self
}
let theme = MarvelTheme.self
theme.ColorStyle.mainColor.apply(to: v)
v
============================================ Examples =====================================
let courierNewPSBold = UIViewStyle { $0.apply(font: UIFont(name: "CourierNewPS-BoldMT", size: 15)) }
let papyrus = UIViewStyle { $0.apply(font: UIFont(name: "Papyrus-Condensed", size: 20)) }
let blueText = UIViewStyle { $0.apply(textColor: .blue) }
let greenText = UIViewStyle { $0.apply(textColor: .green) }
let courierNewPSBoldBlue = UIViewStyle.compose(styles: courierNewPSBold, blueText)
let papyrusGreen = UIViewStyle.compose(styles: papyrus, greenText)
let label = UILabel()
v.addSubview(label)
label.text = "Some text"
label.frame = CGRect(x: 10, y: 10, width: 80, height: 80)
courierNewPSBoldBlue.apply(to: label)
v
papyrusGreen.apply(to: label)
v
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment