Skip to content

Instantly share code, notes, and snippets.

@zhigang1992
Created September 22, 2016 19:04
Show Gist options
  • Save zhigang1992/e353744e226615cb2ac458c97db24f87 to your computer and use it in GitHub Desktop.
Save zhigang1992/e353744e226615cb2ac458c97db24f87 to your computer and use it in GitHub Desktop.
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