Cartography 📱📐

使用 Cartography,您可以使用声明式代码设置 Auto Layout 约束,而无需任何字符串类型的输入!

简而言之,它允许您将此代码替换为

addConstraint(NSLayoutConstraint(
    item: button1,
    attribute: .Right,
    relatedBy: .Equal,
    toItem: button2,
    attribute: .Left,
    multiplier: 1.0,
    constant: -12.0
))

如下代码

constrain(button1, button2) { button1, button2 in
    button1.right == button2.left - 12
}

如果您最终在生产环境中使用 Cartography,我很乐意听到您的反馈。您可以通过 Twitter电子邮件 联系我。

安装

CocoaPods

要使用 CocoaPods 将 Cartography 集成到您的 Xcode 项目中,请在您的 Podfile 中指定它

target '<Your Target Name>' do
  pod 'Cartography', '~> 3.0'
end

然后,运行以下命令

$ pod install

用法

使用您的 UIViewNSView 实例以及一个闭包调用 constrain* 函数,在闭包中声明视图不同属性之间的约束

constrain(view1, view2) { view1, view2 in
    view1.width   == (view1.superview!.width - 50) * 0.5
    view2.width   == view1.width - 50
    view1.height  == 40
    view2.height  == view1.height
    view1.centerX == view1.superview!.centerX
    view2.centerX == view1.centerX

    view1.top >= view1.superview!.top + 20
    view2.top == view1.bottom + 20
}

对于等式或不等式运算符左侧的每个视图,Cartography 将自动将其 translatesAutoresizingMaskIntoConstraints 属性设置为 false

如果视图不受您控制 - 例如,如果它属于 Apple 提供的 UIViewController - 您在声明其约束时应格外小心。



替换约束

您可以将多个约束捕获在一个组中,然后在稍后用新约束替换它们。

constrain(view) { view in
    view.width  == 100
    view.height == 100
}

let group = ConstraintGroup()

// Attach `view` to the top left corner of its superview
constrain(view, replace: group) { view in
    view.top  == view.superview!.top
    view.left == view.superview!.left
}

/* Later */

// Move the view to the bottom right corner of its superview
constrain(view, replace: group) { view in
    view.bottom == view.superview!.bottom
    view.right  == view.superview!.right
}

UIView.animate(withDuration: 0.5, animations: view.layoutIfNeeded)

为了方便起见,constrain 函数还会返回 ConstraintGroup 实例

let group = constrain(button) { button in
    button.width  == 100
    button.height == 400
}

支持的属性

Cartography 支持截至 iOS 8 和 OS X 10.9 的所有内置属性,包括:

以及 iOS 特有的

这些属性可以使用以下运算符进一步细化:*/+-

此外,它还支持方便的复合属性,允许您一次分配多个属性

constrain(view) { view in
    view.size   == view.superview!.size / 2
    view.center == view.superview!.center
}
constrain(view) { view in
    view.edges == inset(view.superview!.edges, 20, 20, 40, 20)
}

对齐多个视图

如果您需要通过公共边缘对齐多个视图,可以使用 align 函数

constrain(view1, view2, view3) { view1, view2, view3 in
    align(top: view1, view2, view3)
}

这等效于 view1.top == view2.top; view2.top == view3.toptoprightbottomleftleadingtrailingcenterXcenterYbaseline 也存在类似的变体。

均匀分布视图

对于水平或垂直分布多个视图,您可以使用 distribute 函数

constrain(view1, view2, view3) { view1, view2, view3 in
    distribute(by: 10, horizontally: view1, view2, view3)
}

这等效于 view1.trailing == view2.leading - 10; view2.trailing == view3.leading - 10

设置优先级

您可以使用 ~ 运算符设置约束的优先级

constrain(view) { view in
    view.width  >= 200 ~ UILayoutPriority(100)
    view.height >= 200 ~ .required
}

捕获约束

由于 ==>=<=~ 发出 NSLayoutConstraint 实例,如果您需要在稍后引用布局约束,则可以捕获它们的结果

var width: NSLayoutConstraint?

constrain(view) { view in
    width = (view.width == 200 ~ 100)
}

请注意,声明复合属性会一次返回多个约束

var constraints: [NSLayoutConstraint]?

constrain(view) { view in
    constraints = (view.size == view.superview!.size ~ .defaultLow)
}

文档

在此处阅读文档 here。有关更多信息,请参阅 gh-pages 分支。

* 由于 Xcode 11 和 swift 5.1,关键字 constrainCommonUISDK 使用的关键字冲突... 因此,必须使用模块名称调用该函数才能使其正常工作

例如:Cartography.constrain

如果您在 Xcode 10.3 或更早版本中使用它,您仍然可以按原样使用它,而无需在函数旁边使用模块名称。

版本控制

对于 Swift 3.x:版本 <= 1.1.0

对于 Swift 4.x:版本 >= 2.0.0

对于 Swift 5.x:版本 >= 4.0.0

支持

如果您有任何问题,请随时 提交 issue

关于 Cartography

Cartography 由 Robb Böhnke 构建,由 Orta Therox 维护,并受到 FLKAutoLayout (由 Florian Kugler 创建) 的启发。