Last active
June 5, 2020 04:28
-
-
Save yoching/40d329f5a314d379edf9a8ddf414e15d to your computer and use it in GitHub Desktop.
Functional View Styling using `callAsFunction`
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 | |
struct Style<View: UIView> { | |
let apply: (View) -> View | |
// from swift 5.2 | |
func callAsFunction(_ view: View) -> View { | |
apply(view) | |
} | |
} | |
extension Style { | |
// general style composition (functional composition) | |
func with(_ another: Style<View>) -> Style<View> { | |
return .init { view -> View in | |
another(self(view)) | |
} | |
} | |
} | |
// styles for UIView (generic) | |
extension Style { | |
static func cornerRadius(_ radius: CGFloat) -> Self { | |
.init { view -> View in | |
view.layer.cornerRadius = radius | |
return view | |
} | |
} | |
static func backgroundColor(_ color: UIColor) -> Self { | |
.init { view -> View in | |
view.backgroundColor = color | |
return view | |
} | |
} | |
} | |
// styles only for UILabel | |
extension Style where View == UILabel { | |
static func font(_ font: UIFont) -> Self { | |
.init { label -> UILabel in | |
label.font = font | |
return label | |
} | |
} | |
} | |
// styles only for UIButton | |
extension Style where View == UIButton { | |
static func titleColor(_ color: UIColor, for state: UIControl.State) -> Self { | |
.init { button -> UIButton in | |
button.setTitleColor(color, for: state) | |
return button | |
} | |
} | |
} | |
// composed style | |
let labelStyle: Style<UILabel> = Style.cornerRadius(5) | |
.with(.backgroundColor(.white)) | |
.with(.font(UIFont.systemFont(ofSize: 15))) | |
let buttonStyle: Style<UIButton> = Style.cornerRadius(10) | |
.with(.backgroundColor(.black)) | |
.with(.titleColor(.white, for: .normal)) | |
// apply style to view | |
let label = UILabel() | |
labelStyle(label) | |
let button = UIButton() | |
buttonStyle(button) | |
// confirm | |
print(label.layer.cornerRadius == 5) // true | |
print(label.backgroundColor == UIColor.white) // true | |
print(label.font == UIFont.systemFont(ofSize: 15)) // true | |
print(button.layer.cornerRadius == 10) // true | |
print(button.backgroundColor == UIColor.black) // true | |
print(button.titleColor(for: .normal) == UIColor.white) // true |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment