Last active
March 6, 2018 15:38
-
-
Save LinusU/a733c27de2a9df1db898e44f8e1b45da to your computer and use it in GitHub Desktop.
React like renderer concept for Swift
This file contains 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 PlaygroundSupport | |
/********************************************** | |
* Library Types * | |
**********************************************/ | |
protocol REElement { | |
func render() -> REElement? | |
func toNativeView() -> UIView? | |
} | |
class REComponent<Props>: REElement { | |
var children: [REElement] | |
var props: [Props] | |
var state: Any? | |
init(_ props: [Props], _ children: [REElement] = []) { | |
self.props = props | |
self.children = children | |
self.state = nil | |
} | |
func render() -> REElement? { return nil } | |
func toNativeView() -> UIView? { return nil } | |
} | |
/********************************************** | |
* Built-in components * | |
**********************************************/ | |
enum RELabelProps { | |
case backgroundColor(UIColor) | |
case text(String) | |
case textColor(UIColor) | |
} | |
class RELabel: REComponent<RELabelProps> { | |
override func toNativeView() -> UIView? { | |
let view = UILabel() | |
for prop in props { | |
switch prop { | |
case .backgroundColor(let value): view.backgroundColor = value | |
case .text(let value): view.text = value | |
case .textColor(let value): view.textColor = value | |
} | |
} | |
return view | |
} | |
} | |
enum REStackProps { | |
case alignment(UIStackViewAlignment) | |
case axis(UILayoutConstraintAxis) | |
case distribution(UIStackViewDistribution) | |
} | |
class REStack: REComponent<REStackProps> { | |
override func toNativeView() -> UIView? { | |
let view = UIStackView() | |
view.frame = CGRect(x: 0, y: 0, width: 200, height: 200) | |
for prop in props { | |
switch prop { | |
case .alignment(let value): view.alignment = value | |
case .axis(let value): view.axis = value | |
case .distribution(let value): view.distribution = value | |
} | |
} | |
for child in children { | |
RE_render(node: child, toTargetView: view) | |
} | |
return view | |
} | |
} | |
/********************************************** | |
* Rendering function * | |
**********************************************/ | |
func RE_render(node: REElement, toTargetView targetView: UIView) { | |
if let view = node.toNativeView() { | |
if let stackedView = targetView as? UIStackView { | |
stackedView.addArrangedSubview(view) | |
} else { | |
targetView.addSubview(view) | |
} | |
return | |
} | |
if let child = node.render() { | |
RE_render(node: child, toTargetView: targetView) | |
return | |
} | |
} | |
/********************************************** | |
* User code * | |
**********************************************/ | |
class MyViewController : UIViewController { | |
override func loadView() { | |
let view = UIView() | |
view.backgroundColor = .white | |
let tree = REStack([.alignment(.center)], [ | |
RELabel([.backgroundColor(.cyan), .text("Hello:")]), | |
RELabel([.textColor(.blue), .text("World!")]) | |
]) | |
RE_render(node: tree, toTargetView: view) | |
self.view = view | |
} | |
} | |
// Present the view controller in the Live View window | |
PlaygroundPage.current.liveView = MyViewController() |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment