Last active
February 13, 2019 06:00
-
-
Save RoshanNindrai/860d13cb93233ef7cb84a10ae0e69eb9 to your computer and use it in GitHub Desktop.
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
//: A UIKit based Playground for presenting user interface | |
import UIKit | |
import PlaygroundSupport | |
public struct Renderable { | |
private let handle: () -> Void | |
public init(_ handle: @escaping () -> Void) { | |
self.handle = handle | |
} | |
func render() { | |
handle() | |
} | |
} | |
public typealias Configuration = [String: Any] | |
public protocol JSONRepresentable { | |
var identifier: String { get } | |
func render(with configuration: Configuration) -> Renderable | |
} | |
extension JSONRepresentable where Self: NSObject { | |
public var identifier: String { | |
return String(describing: Self.classForCoder()) | |
} | |
public func render(with configuration: Configuration) -> Renderable { | |
return Renderable { | |
let myReflection = Mirror(reflecting: self) | |
configuration.forEach { [myReflection] key, configuration in | |
// if we can configure the property using KVC else use mirroring | |
if Self.instancesRespond(to: Selector(key)) { | |
// For not straight forward keys like layer we need to perform it's render pass | |
if let element = self.value(forKey: key) as? JSONRepresentable, | |
let elementConfiguration = configuration as? Configuration { | |
element.render(with: elementConfiguration).render() | |
} else { | |
self.setValue(configuration, forKeyPath: key) | |
} | |
} else { | |
// There can't be two properties with same name, so taking the first one | |
if let property = myReflection.children.filter({ $0.label == key }).first { | |
if let renderable = property.value as? JSONRepresentable, | |
let elementConfiguration = configuration as? Configuration { | |
renderable.render(with: elementConfiguration).render() | |
} | |
} else { | |
print("Invalid '\(key)' key found while rendering \(self.identifier)") | |
} | |
} | |
} | |
} | |
} | |
} | |
extension CALayer: JSONRepresentable {} | |
extension UILabel: JSONRepresentable {} | |
class TestView: UIView, JSONRepresentable { | |
var titleLabel = UILabel() | |
var subtitleLabel = UILabel() | |
override init(frame: CGRect) { | |
super.init(frame: frame) | |
addSubview(titleLabel) | |
addSubview(subtitleLabel) | |
} | |
override func layoutSubviews() { | |
super.layoutSubviews() | |
titleLabel.frame = CGRect(origin: .zero, size: .init(width: 144, height: 44)) | |
subtitleLabel.frame = CGRect(origin: .init(x: 0, y: 46), size: .init(width: 144, height: 44)) | |
} | |
required init?(coder aDecoder: NSCoder) { | |
return nil | |
} | |
} | |
let view = TestView(frame: .init(origin: .zero, size: .init(width: 144, height: 144))) | |
view.backgroundColor = .red | |
let testViewRenderable = view.render(with: [ | |
"backgroundColor": UIColor.darkGray, | |
"titleLabel": [ | |
"text": "Hello", | |
"textAlignment": NSTextAlignment.center.rawValue, | |
"numberOfLines": 1, | |
"textColor": UIColor.white, | |
"layer": [ | |
"borderColor": UIColor.blue.cgColor, | |
"borderWidth": 2 | |
] | |
], | |
"subtitleLabel": [ | |
"text": "World", | |
"textAlignment": NSTextAlignment.center.rawValue, | |
"numberOfLines": 1, | |
"textColor": UIColor.white, | |
"layer": [ | |
"borderColor": UIColor.blue.cgColor, | |
"borderWidth": 2 | |
] | |
], | |
"layer": [ | |
"cornerRadius": 5, | |
"borderWidth": 1, | |
"borderColor": UIColor.red.cgColor | |
] | |
]) | |
PlaygroundPage.current.liveView = view | |
testViewRenderable.render() | |
PlaygroundPage.current.needsIndefiniteExecution = true | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment