Skip to content

Instantly share code, notes, and snippets.

@Anatoli-Petrosyants
Last active February 7, 2021 15:28
Show Gist options
  • Save Anatoli-Petrosyants/3f27eae4fab56b9a7b279c5314e3c964 to your computer and use it in GitHub Desktop.
Save Anatoli-Petrosyants/3f27eae4fab56b9a7b279c5314e3c964 to your computer and use it in GitHub Desktop.
import Foundation
import UIKit
struct BaseStyles {
static func rounded<V: UIView>(cornerRadius r: CGFloat = 5.5) -> UIViewStyle<V> {
return UIViewStyle<V>(styling: { (view: V) in
view.layer.masksToBounds = true
view.clipsToBounds = true
view.layer.cornerRadius = r
})
}
static func border<V: UIView>(width: CGFloat = 1.0, color: UIColor = .black) -> UIViewStyle<V> {
return UIViewStyle<V>(styling: { (view: V) in
view.layer.borderColor = color.cgColor
view.layer.borderWidth = width
})
}
static func rounded<V: UIView>(corners: UIRectCorner, cornerRadius: CGFloat = 8.0) -> UIViewStyle<V> {
return UIViewStyle<V>(styling: { view in
let rectShape = CAShapeLayer()
rectShape.bounds = view.frame
rectShape.position = view.center
rectShape.path = UIBezierPath(roundedRect: view.bounds,
byRoundingCorners: corners,
cornerRadii: CGSize(width: cornerRadius, height: cornerRadius)).cgPath
view.layer.mask = rectShape
view.layer.masksToBounds = true
})
}
static func circle<V: UIView>() -> UIViewStyle<V> {
return BaseStyles.rounded().composing(with: { (v) in
v.layer.cornerRadius = v.frame.size.height / 2
})
}
static let card: UIViewStyle<UIView> = rounded(cornerRadius: 5.5).composing { view in
view.layer.shadowOffset = CGSize(width: 0, height: 2.5)
shadow.styling(view)
}
static let shadow: UIViewStyle<UIView> = UIViewStyle { view in
view.layer.shadowColor = UIColor.gray.cgColor
view.layer.shadowOpacity = 0.15
view.layer.shadowRadius = 2
view.layer.masksToBounds = false
}
static let background: UIViewStyle<UIView> = UIViewStyle { view in
view.backgroundColor = .white
}
static let separator: UIViewStyle<UIView> = UIViewStyle { view in
view.backgroundColor = .lightGrey
}
static let tableView: UIViewStyle<UITableView> = UIViewStyle { tableView in
tableView.separatorStyle = .none
background.styling(tableView)
}
}
// Usage:
// BaseStyles.rounded().styling(view)
// BaseStyles.background.apply(to: view)
// BaseStyles.card.apply(to: view)
// BaseStyles.border(width: 0.5, color: .grey).styling(view)
import Foundation
import UIKit
struct ButtonStyle {
static let clear: UIViewStyle<UIButton> = rounded.composing { (button: UIButton) in
button.backgroundColor = UIColor.clear
button.setTitleColor(UIColor.white, for: .normal)
}
static let rounded: UIViewStyle<UIButton> = base(cornerRadius: 4)
static func base<V: UIButton>(cornerRadius: CGFloat = 0) -> UIViewStyle<V> {
return BaseStyles.rounded(cornerRadius: cornerRadius).composing { (button: UIButton) in
button.setTitleColor(UIColor.white, for: .normal)
button.setBackgroundColor(UIColor.anteoBlue, forState: .normal)
}
}
static func bold<V: UIButton>(ofSize: CGFloat = 22) -> UIViewStyle<V> {
return UIViewStyle { button in
guard let label = button.titleLabel else {
return
}
LabelStyle.baseBold(with: ofSize).apply(to: label)
}
}
static func regular<V: UIButton>(ofSize size: CGFloat = 18) -> UIViewStyle<V> {
return UIViewStyle { button in
guard let label = button.titleLabel else { return }
LabelStyle.base(with: size).apply(to: label)
}
}
static let darkGreyTitle: UIViewStyle<UIButton> = {
return UIViewStyle { button in
guard let label = button.titleLabel else { return }
LabelStyle.darkGrey.apply(to: label)
}
}()
}
// Usage:
// ButtonStyle.regular().apply(to: button)
// ButtonStyle.darkGreyTitle.apply(to: button)
import Foundation
import UIKit
struct LabelStyle {
static func base(with size: CGFloat) -> UIViewStyle<UILabel> {
return UIViewStyle { label in
label.font = Font.regular(size)
}
}
static func baseBold(with size: CGFloat) -> UIViewStyle<UILabel> {
return UIViewStyle { label in
label.font = Font.bold(size)
}
}
static let big: UIViewStyle<UILabel> = base(with: 30)
static let bigBold: UIViewStyle<UILabel> = baseBold(with: 30)
static let base: UIViewStyle<UILabel> = LabelStyle.base(with: 18)
static let baseBold: UIViewStyle<UILabel> = LabelStyle.baseBold(with: 18)
static let small: UIViewStyle<UILabel> = base(with: 14)
static let smallBold: UIViewStyle<UILabel> = baseBold(with: 14)
static let blue: UIViewStyle<UILabel> = UIViewStyle { label in
label.textColor = UIColor.blue
}
static let darkGrey: UIViewStyle<UILabel> = UIViewStyle { label in
label.textColor = UIColor.darkGrey
}
static let grey: UIViewStyle<UILabel> = UIViewStyle { label in
label.textColor = UIColor.grey
}
static let black: UIViewStyle<UILabel> = UIViewStyle { label in
label.textColor = UIColor.black
}
static let white: UIViewStyle<UILabel> = UIViewStyle { label in
label.textColor = UIColor.white
}
static let dialogTitle: UIViewStyle<UILabel> = UIViewStyle { label in
LabelStyle.baseBold.styling(label)
LabelStyle.blue.styling(label)
}
static let dialogText: UIViewStyle<UILabel> = UIViewStyle { label in
LabelStyle.small.styling(label)
LabelStyle.black.styling(label)
}
}
// Usage:
// LabelStyle.smallBold.apply(to: label)
// LabelStyle.darkGrey.apply(to: label)
import UIKit
import RxSwift
import RxCocoa
/// 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 self.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(self.base) { control, style in
style.apply(to: control)
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment