Created
September 29, 2020 18:08
-
-
Save janodev/b62188b55fd576eaf5f1490472259313 to your computer and use it in GitHub Desktop.
VFL example
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 | |
final class SomeView: LayoutView | |
{ | |
let view1 = UIView() | |
let view2 = UIView() | |
let view3 = UIView() | |
override func layout() { | |
super.layout() | |
autoLayout.applyVisualFormatLanguage([ | |
"|-(30)-[view1]-(30)-[view2]-(30)-[view3]" | |
]) | |
} | |
} | |
class LayoutView: UIView | |
{ | |
override init(frame: CGRect) { | |
super.init(frame: frame) | |
layout() | |
} | |
@available(*, unavailable) | |
required init?(coder aDecoder: NSCoder) { | |
super.init(coder: aDecoder) | |
layout() | |
} | |
func layout() { | |
autoLayout.enumerateSubViews().values.forEach { addSubview($0) } | |
} | |
} | |
public extension UIView { | |
var autoLayout: AutoLayout { | |
AutoLayout(self) | |
} | |
} | |
public struct AutoLayout { | |
public let base: UIView | |
public init(_ base: UIView) { | |
self.base = base | |
} | |
public func applyVisualFormatLanguage(_ constraints: [String], | |
options: NSLayoutConstraint.FormatOptions = [], | |
metrics: [String: Any]? = nil) { | |
base.translatesAutoresizingMaskIntoConstraints = false | |
var views = enumerateSubViews() | |
views["baseView"] = base | |
views.values.forEach { $0.translatesAutoresizingMaskIntoConstraints = false } | |
constraints.forEach { | |
base.addConstraints(NSLayoutConstraint.constraints(withVisualFormat: $0, options: options, metrics: metrics, views: views)) | |
} | |
} | |
/// Returns every non nil instance UIView variable in the given view, indexed by its variable name. | |
public func enumerateSubViews() -> [String: UIView] { | |
var views = [String: UIView]() | |
let mirror = Mirror(reflecting: base) | |
let addToViewsClosure: ((Mirror.Child) -> Void) = { child in | |
child.label.flatMap { label in | |
// lazy var has $__lazy_storage_$_ (swift 5.1+) and .storage (swift 5-) in `label` property. | |
#if swift(>=5.1) | |
let key = label.replacingOccurrences(of: "$__lazy_storage_$_", with: "") | |
#else | |
let key = label.replacingOccurrences(of: ".storage", with: "") | |
#endif | |
views[key] = child.value as? UIView | |
} | |
} | |
mirror.children.forEach(addToViewsClosure) | |
mirror.superclassMirror?.children.forEach(addToViewsClosure) | |
return views | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment