Created
November 2, 2018 14:04
-
-
Save cjndubisi/f78d1104f136a437c0c09a5ebbde10e1 to your computer and use it in GitHub Desktop.
UIViewStyling from Anatoli
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| import UIKit | |
| import Foundation | |
| /// An abstraction if `UIView` styling. | |
| struct UIViewStyle<T: UIResponder> { | |
| /// The styling function that takes a `UIView` instance | |
| /// and performs side-effects on it. | |
| public let styling: (T) -> Void | |
| /// A factory method that composes multiple styles. | |
| /// | |
| /// - Parameter styles: The styles to compose. | |
| /// - Returns: A new `UIViewStyle` that will call the input styles' | |
| /// `styling` method in succession. | |
| static func compose(_ styles: UIViewStyle<T>...) -> UIViewStyle<T> { | |
| return UIViewStyle { view in | |
| for style in styles { | |
| style.styling(view) | |
| } | |
| } | |
| } | |
| /// Compose this style with another. | |
| /// | |
| /// - Parameter other: Other style to compose this style with. | |
| /// - Returns: A new `UIViewStyle` which will call this style's `styling`, | |
| /// and then the `other` style's `styling`. | |
| func composing(with other: UIViewStyle<T>) -> UIViewStyle<T> { | |
| return UIViewStyle { view in | |
| self.styling(view) | |
| other.styling(view) | |
| } | |
| } | |
| /// Compose this style with another styling function. | |
| /// | |
| /// - Parameter otherStyling: The function to compose this style with. | |
| /// - Returns: A new `UIViewStyle` which will call this style's `styling`, | |
| /// and then the input `styling`. | |
| func composing(with otherStyling: @escaping (T) -> Void) -> UIViewStyle<T> { | |
| return composing(with: UIViewStyle(styling: otherStyling)) | |
| } | |
| /// Apply this style to a UIView. | |
| /// | |
| /// - Parameter view: the view to style | |
| func apply(to view: T) { | |
| styling(view) | |
| } | |
| /// Apply this style to multiple views. | |
| /// | |
| /// - Parameter views: the views to style | |
| func apply(to views: T...) { | |
| for view in views { | |
| styling(view) | |
| } | |
| } | |
| } | |
| //extension Reactive where Base: UIResponder { | |
| // var style: Binder<UIViewStyle<UIResponder>> { | |
| // return Binder(base) { control, style in | |
| // style.apply(to: control) | |
| // } | |
| // } | |
| //} | |
| protocol DesignableView: class { | |
| var textColor: UIColor! { get set } | |
| var font: UIFont! { get set } | |
| var backgroundColor: UIColor? { set get } | |
| static var configuration: DesignableConfiguration { get } | |
| } | |
| protocol DesignableConfiguration { | |
| var big: CGFloat { get } | |
| var base: CGFloat { get } | |
| var small: CGFloat { get } | |
| var semiBold: CGFloat { get } | |
| var baseBold: CGFloat { get } | |
| } | |
| // the idea is to change it in one place and it changed every where | |
| // with this you can change for only specific elements | |
| extension DesignableConfiguration { | |
| var big: CGFloat { | |
| return 30 // alternative might be FontPalatte.title() | |
| } | |
| var base: CGFloat { | |
| return 16 // alternative might be FontPalatte.body() | |
| } | |
| var small: CGFloat { | |
| return 14 // etc | |
| } | |
| var semiBold: CGFloat { | |
| return 16 | |
| } | |
| var baseBold: CGFloat { | |
| return 16 | |
| } | |
| } | |
| typealias DesignableViewUIResponder = DesignableView | |
| extension UIViewStyle where T: DesignableViewUIResponder { | |
| static func base(with size: CGFloat) -> UIViewStyle<T> { | |
| return UIViewStyle(styling: { (d) in | |
| d.backgroundColor = .white | |
| }) | |
| } | |
| /* | |
| DO NO expose ad-hoc possibities | |
| */ | |
| private static func baseSemibold(with size: CGFloat) -> UIViewStyle<T> { | |
| return UIViewStyle { textfield in | |
| textfield.backgroundColor = UIColor.white | |
| // textfield.font = Font.semibold(size) | |
| } | |
| } | |
| private static func baseBold(with size: CGFloat) -> UIViewStyle<T> { | |
| return UIViewStyle { textfield in | |
| textfield.backgroundColor = UIColor.white | |
| // textfield.font = Font.bold(size) | |
| } | |
| } | |
| static var big: UIViewStyle<T> { | |
| return base(with: T.configuration.big) | |
| } | |
| static var bigSemibold: UIViewStyle<T> { | |
| return baseSemibold(with: T.configuration.big) | |
| } | |
| static var bigBold: UIViewStyle<T> { | |
| return baseBold(with: T.configuration.big) | |
| } | |
| static var base: UIViewStyle<T> { return base(with: T.configuration.base) } | |
| static var baseSemibold: UIViewStyle<T> { return baseSemibold(with: T.configuration.semiBold) } | |
| static var baseBold: UIViewStyle<T> { return baseBold(with: T.configuration.baseBold) } | |
| static var small: UIViewStyle<T> { return base(with: T.configuration.small) } | |
| static var smallSemibold: UIViewStyle<T> { return baseSemibold(with: T.configuration.small) } | |
| static var smallBold: UIViewStyle<T> { return baseBold(with: T.configuration.small) } | |
| static var blue: UIViewStyle<T> { | |
| return UIViewStyle { label in | |
| label.textColor = .blue | |
| } | |
| } | |
| static var darkGrey: UIViewStyle<T> { | |
| return UIViewStyle { label in | |
| label.textColor = .darkGray | |
| } | |
| } | |
| static var grey: UIViewStyle<T> { | |
| return UIViewStyle { label in | |
| label.textColor = .gray | |
| } | |
| } | |
| static var black: UIViewStyle<T>{ | |
| return UIViewStyle { label in | |
| label.textColor = .black | |
| } | |
| } | |
| static var white: UIViewStyle<T> { | |
| return UIViewStyle { label in | |
| label.textColor = .white | |
| } | |
| } | |
| } | |
| struct BaseUIConfiguation: DesignableConfiguration {} | |
| struct UILabelConfiguation: DesignableConfiguration {} | |
| struct UIButtonConfiguation: DesignableConfiguration {} | |
| struct UITextFieldConfiguation: DesignableConfiguration {} | |
| extension UILabel: DesignableView { | |
| static var configuration: DesignableConfiguration { | |
| return UILabelConfiguation() | |
| } | |
| } | |
| extension UIButton: DesignableView { | |
| var textColor: UIColor! { | |
| get { | |
| return titleColor(for: .normal) | |
| } | |
| set { | |
| setTitleColor(newValue, for: .normal) | |
| } | |
| } | |
| var font: UIFont! { | |
| get { | |
| return titleLabel?.font | |
| } | |
| set { | |
| titleLabel?.font = newValue | |
| } | |
| } | |
| static var configuration: DesignableConfiguration { | |
| return BaseUIConfiguation() | |
| } | |
| } | |
| // Use typealias for duplicated code style | |
| typealias LabelStyle = UIViewStyle<UILabel> | |
| typealias ButtonStyle = UIViewStyle<UIButton> | |
| typealias UITextFieldStyle = UIViewStyle<UITextField> | |
| LabelStyle.baseSemibold.apply(to: UILabel()) | |
| ButtonStyle.baseSemibold.apply(to: UIButton()) | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment