Created
September 22, 2016 19:04
-
-
Save zhigang1992/e353744e226615cb2ac458c97db24f87 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
import UIKit | |
precedencegroup PipingPrecedence { | |
associativity: left | |
higherThan: LogicalConjunctionPrecedence | |
} | |
infix operator |> : PipingPrecedence | |
func |><A,B>(a:A, function: (A)->B) -> B { | |
return function(a) | |
} | |
precedencegroup ComposePrecedence { | |
associativity: left | |
higherThan: PipingPrecedence | |
} | |
infix operator • : ComposePrecedence | |
func •<A,B,C>(f:@escaping (A) -> B, g:@escaping (B)->C) -> (A) -> C { | |
return { g(f($0)) } | |
} | |
func sideEffect<A>(function: @escaping (A) -> Void) -> (A) -> A { | |
return { a in | |
function(a) | |
return a | |
} | |
} | |
typealias ConstraintConfig = (NSLayoutConstraint) -> NSLayoutConstraint | |
func identity<T>(input:T) -> T { | |
return input | |
} | |
func make<T: AnyObject>(_ relation: NSLayoutRelation) -> (NSLayoutAnchor<T>, NSLayoutAnchor<T>) -> NSLayoutConstraint { | |
return { a, b in | |
switch relation { | |
case .greaterThanOrEqual: | |
return a.constraint(greaterThanOrEqualTo: b) | |
case .lessThanOrEqual: | |
return a.constraint(lessThanOrEqualTo: b) | |
case .equal: | |
return a.constraint(equalTo: b) | |
} | |
} | |
} | |
func make(_ relation: NSLayoutRelation) -> (NSLayoutDimension) -> NSLayoutConstraint { | |
return { anchor in | |
switch relation { | |
case .equal: | |
return anchor.constraint(equalToConstant: 0) | |
case .greaterThanOrEqual: | |
return anchor.constraint(greaterThanOrEqualToConstant: 0) | |
case .lessThanOrEqual: | |
return anchor.constraint(lessThanOrEqualToConstant: 0) | |
} | |
} | |
} | |
func make(priority: UILayoutPriority) -> ConstraintConfig { | |
return sideEffect() { | |
$0.priority = priority | |
} | |
} | |
func make(constant: CGFloat) -> ConstraintConfig { | |
return sideEffect() { | |
$0.constant = constant | |
} | |
} | |
func make(activate: Bool) -> ConstraintConfig { | |
return sideEffect() { | |
$0.isActive = activate | |
} | |
} | |
struct Edge { | |
static let top: (UIView) -> NSLayoutYAxisAnchor = { $0.topAnchor } | |
static let bottom: (UIView) -> NSLayoutYAxisAnchor = { $0.bottomAnchor } | |
static let leading: (UIView) -> NSLayoutXAxisAnchor = { $0.leadingAnchor } | |
static let trailing: (UIView) -> NSLayoutXAxisAnchor = { $0.trailingAnchor } | |
static let centerX: (UIView) -> NSLayoutXAxisAnchor = { $0.centerXAnchor } | |
static let centerY: (UIView) -> NSLayoutYAxisAnchor = { $0.centerYAnchor } | |
static let topGuide: (UIViewController) -> NSLayoutYAxisAnchor = { | |
$0.topLayoutGuide.bottomAnchor | |
} | |
static let width: (UIView) -> NSLayoutDimension = { $0.widthAnchor } | |
static let height: (UIView) -> NSLayoutDimension = { $0.heightAnchor } | |
} | |
enum EdgeToPin { | |
typealias Horizontal = (NSLayoutAnchor<NSLayoutXAxisAnchor>, NSLayoutAnchor<NSLayoutXAxisAnchor>) -> NSLayoutConstraint | |
typealias Vertical = (NSLayoutAnchor<NSLayoutYAxisAnchor>, NSLayoutAnchor<NSLayoutYAxisAnchor>) -> NSLayoutConstraint | |
case leading(Horizontal) | |
case trailing(Horizontal) | |
case top(Vertical) | |
case bottom(Vertical) | |
static let all:[EdgeToPin] = [ | |
.leading(make(.equal)), | |
.trailing(make(.equal)), | |
.top(make(.equal)), | |
.bottom(make(.equal)) | |
] | |
} | |
struct AnchorMan { | |
static func pin<U, V, T: AnyObject>( | |
anchor: (U) -> NSLayoutAnchor<T>, | |
ofItem item: U, | |
toAnchor: (V) -> NSLayoutAnchor<T>, | |
ofOtherItem otherItem: V, | |
config: (NSLayoutAnchor<T>, NSLayoutAnchor<T>) -> NSLayoutConstraint | |
) -> NSLayoutConstraint { | |
return config(anchor(item), toAnchor(otherItem)) | |
} | |
static func pin<U>( | |
anchor: (U) -> NSLayoutDimension, | |
ofItem item: U, | |
config: (NSLayoutDimension) -> NSLayoutConstraint | |
) -> NSLayoutConstraint { | |
return item |> anchor |> config | |
} | |
} | |
extension UIView { | |
func pin<U, T>(anchor: (UIView) -> NSLayoutAnchor<T>, toAnchor: (U) -> NSLayoutAnchor<T>, ofItem: U, config: (NSLayoutAnchor<T>, NSLayoutAnchor<T>) -> NSLayoutConstraint = make(.equal)) -> NSLayoutConstraint { | |
return AnchorMan.pin(anchor: anchor, ofItem: self, toAnchor: toAnchor, ofOtherItem: ofItem, config: config) | |
} | |
func pin<T>(anchor: (UIView) -> NSLayoutAnchor<T>, togetherWithView: UIView, config: (NSLayoutAnchor<T>, NSLayoutAnchor<T>) -> NSLayoutConstraint = make(.equal)) -> NSLayoutConstraint { | |
return self.pin(anchor: anchor, toAnchor: anchor, ofItem: togetherWithView, config: config) | |
} | |
func pinToView(view: UIView, edges: [EdgeToPin] = EdgeToPin.all) -> [NSLayoutConstraint] { | |
return edges.map({ | |
switch $0 { | |
case .top(let config): | |
return self.pin(anchor: Edge.top, togetherWithView: view, config: config) | |
case .leading(let config): | |
return self.pin(anchor: Edge.leading, togetherWithView: view, config: config) | |
case .trailing(let config): | |
return self.pin(anchor: Edge.trailing, togetherWithView: view, config: config) | |
case .bottom(let config): | |
return self.pin(anchor: Edge.bottom, togetherWithView: view, config: config) | |
} | |
}) | |
} | |
func pinToSuperView(edges: [EdgeToPin] = EdgeToPin.all) -> [NSLayoutConstraint] { | |
guard let superview = self.superview else { | |
fatalError("Sholud have superview") | |
} | |
return self.pinToView(view: superview, edges: edges) | |
} | |
func setSize(width: ((NSLayoutDimension) -> NSLayoutConstraint)? = nil, height: ((NSLayoutDimension) -> NSLayoutConstraint)? = nil) -> [NSLayoutConstraint] { | |
return [ | |
width.map({ self.widthAnchor |> $0 }), | |
height.map({ self.heightAnchor |> $0 }) | |
].flatMap({$0}) | |
} | |
} | |
let viewController = UIViewController() | |
let view = viewController.view! | |
let subview = UIView() | |
view.addSubview(subview) | |
subview.pinToSuperView() | |
let subviewB = UIView() | |
view.addSubview(subviewB) | |
subviewB.pinToView(view: subview, edges: [ | |
.leading(make(.equal) • make(constant: 10)), | |
.top(make(.greaterThanOrEqual) • make(priority: 100)) | |
]) | |
subview.setSize( | |
width: make(.equal) • make(constant: 100), | |
height: make(.greaterThanOrEqual) • make(constant: 10) | |
) | |
let subviewC = UIView() | |
view.addSubview(subviewC) | |
//Bind to viewController | |
subviewC.pin(anchor: Edge.top, toAnchor: Edge.topGuide, ofItem: viewController) | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment