博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
SnapKit 源码解读(三):Maker
阅读量:6637 次
发布时间:2019-06-25

本文共 17008 字,大约阅读时间需要 56 分钟。

MakerSnapKit 中最核心的概念,所有关于约束的操作都是通过 Maker 来进行管理和操作的。

ConstraintMaker

ConstraintMaker 是施加、更新和重置约束三个功能的核心类,与之对应的也实现了相关的类方法。同时其还声明了很多计算属性,用来配置约束使用。

初始化方法

ConstraintMaker 是通过 LayoutConstraintItem 类型的 item 参数进行初始化的,LayoutConstraintItem 是一个模型类,保存了所有的约束。

private let item: LayoutConstraintItem    internal init(item: LayoutConstraintItem) {    self.item = item    self.item.prepare()}复制代码

计算属性

ConstraintMaker 内部有很多的计算属性,用以辅助描述约束。

public var left: ConstraintMakerExtendable {    return self.makeExtendableWithAttributes(.left)}    public var top: ConstraintMakerExtendable {    return self.makeExtendableWithAttributes(.top)}    public var bottom: ConstraintMakerExtendable {    return self.makeExtendableWithAttributes(.bottom)}    public var right: ConstraintMakerExtendable {    return self.makeExtendableWithAttributes(.right)}    public var leading: ConstraintMakerExtendable {    return self.makeExtendableWithAttributes(.leading)}    public var trailing: ConstraintMakerExtendable {    return self.makeExtendableWithAttributes(.trailing)}    public var width: ConstraintMakerExtendable {    return self.makeExtendableWithAttributes(.width)}    public var height: ConstraintMakerExtendable {    return self.makeExtendableWithAttributes(.height)}  public var centerX: ConstraintMakerExtendable {    return self.makeExtendableWithAttributes(.centerX)}   public var centerY: ConstraintMakerExtendable {    return self.makeExtendableWithAttributes(.centerY)}  @available(*, deprecated:3.0, message:"Use lastBaseline instead")public var baseline: ConstraintMakerExtendable {    return self.makeExtendableWithAttributes(.lastBaseline)}    public var lastBaseline: ConstraintMakerExtendable {    return self.makeExtendableWithAttributes(.lastBaseline)}    @available(iOS 8.0, OSX 10.11, *)public var firstBaseline: ConstraintMakerExtendable {    return self.makeExtendableWithAttributes(.firstBaseline)}    @available(iOS 8.0, *)public var leftMargin: ConstraintMakerExtendable {    return self.makeExtendableWithAttributes(.leftMargin)}    @available(iOS 8.0, *)public var rightMargin: ConstraintMakerExtendable {    return self.makeExtendableWithAttributes(.rightMargin)}    @available(iOS 8.0, *)public var topMargin: ConstraintMakerExtendable {    return self.makeExtendableWithAttributes(.topMargin)}    @available(iOS 8.0, *)public var bottomMargin: ConstraintMakerExtendable {    return self.makeExtendableWithAttributes(.bottomMargin)}    @available(iOS 8.0, *)public var leadingMargin: ConstraintMakerExtendable {    return self.makeExtendableWithAttributes(.leadingMargin)}    @available(iOS 8.0, *)public var trailingMargin: ConstraintMakerExtendable {    return self.makeExtendableWithAttributes(.trailingMargin)}    @available(iOS 8.0, *)public var centerXWithinMargins: ConstraintMakerExtendable {    return self.makeExtendableWithAttributes(.centerXWithinMargins)}    @available(iOS 8.0, *)public var centerYWithinMargins: ConstraintMakerExtendable {    return self.makeExtendableWithAttributes(.centerYWithinMargins)}    public var edges: ConstraintMakerExtendable {    return self.makeExtendableWithAttributes(.edges)}public var size: ConstraintMakerExtendable {    return self.makeExtendableWithAttributes(.size)}public var center: ConstraintMakerExtendable {    return self.makeExtendableWithAttributes(.center)}    @available(iOS 8.0, *)public var margins: ConstraintMakerExtendable {    return self.makeExtendableWithAttributes(.margins)}    @available(iOS 8.0, *)public var centerWithinMargins: ConstraintMakerExtendable {    return self.makeExtendableWithAttributes(.centerWithinMargins)}复制代码

所有的这些计算属性都会通过内部的一个 makeExtendableWithAttributes 方法初始化一个 ConstraintMakerExtendable 类型的对象,并返回之,makeExtendableWithAttributes 方法如下所示:

private var descriptions = [ConstraintDescription]()internal func makeExtendableWithAttributes(_ attributes: ConstraintAttributes) -> ConstraintMakerExtendable {    let description = ConstraintDescription(item: self.item, attributes: attributes)    self.descriptions.append(description)    return ConstraintMakerExtendable(description)}复制代码

该方法会根据 self.item 初始化一个 ConstraintDescription 对象,并将该对象存储在 descriptions 数组中,再创造一个 ConstraintMakerExtendable 类型的对象并返回之。

prepareConstraints

prepareConstraints 方法会先生成一个 ConstraintMaker 类型的对象 maker,然后将 maker 通过 closure 传递给外界做一些属性的配置,接着遍历 maker.descriptions 取出其 constraint 属性,并返回之。

internal static func prepareConstraints(item: LayoutConstraintItem, closure: (_ make: ConstraintMaker) -> Void) -> [Constraint] {    let maker = ConstraintMaker(item: item)    closure(maker)    var constraints: [Constraint] = []    for description in maker.descriptions {        guard let constraint = description.constraint else {            continue        }        constraints.append(constraint)    }    return constraints}复制代码

makeConstraints

makeConstraints 方法与 prepareConstraints 方法大同小异,区别在于,makeConstraints 方法的最后不是 return constraints,而是挨个 constraint.activateIfNeeded(updatingExisting: false)

internal static func makeConstraints(item: LayoutConstraintItem, closure: (_ make: ConstraintMaker) -> Void) {    let maker = ConstraintMaker(item: item)    closure(maker)    var constraints: [Constraint] = []    for description in maker.descriptions {        guard let constraint = description.constraint else {            continue        }        constraints.append(constraint)    }    for constraint in constraints {        constraint.activateIfNeeded(updatingExisting: false)    }}复制代码

remakeConstraints

移除约束的操作分为两步,第一步:移除现有约束,第二步:重新添加约束。

internal static func remakeConstraints(item: LayoutConstraintItem, closure: (_ make: ConstraintMaker) -> Void) {    self.removeConstraints(item: item)    self.makeConstraints(item: item, closure: closure)}复制代码

移除约束操作就是从 itemconstraints 属性里所有 constraint 挨个失效。

internal static func removeConstraints(item: LayoutConstraintItem) {    let constraints = item.constraints    for constraint in constraints {        constraint.deactivateIfNeeded()    }}复制代码

updateConstraints

更新约束的操作也分为两部分:首先会判断当前是否已经施加过约束,如果没有,则直接转入 makeConstraints 流程。其余操作与 makeConstraints 类似,区别就是 updatingExisting 参数为 true

internal static func updateConstraints(item: LayoutConstraintItem, closure: (_ make: ConstraintMaker) -> Void) {    guard item.constraints.count > 0 else {        self.makeConstraints(item: item, closure: closure)        return    }            let maker = ConstraintMaker(item: item)    closure(maker)    var constraints: [Constraint] = []    for description in maker.descriptions {        guard let constraint = description.constraint else {            continue        }        constraints.append(constraint)    }    for constraint in constraints {        constraint.activateIfNeeded(updatingExisting: true)    }}复制代码

ConstraintMakerFinalizable

ConstraintMakerFinalizable 是对 ConstraintDescription 的一层包装,并提供了一些方便方法供我们设置和获取一些值。

public class ConstraintMakerFinalizable {        internal let description: ConstraintDescription        internal init(_ description: ConstraintDescription) {        self.description = description    }        @discardableResult    public func labeled(_ label: String) -> ConstraintMakerFinalizable {        self.description.label = label        return self    }        public var constraint: Constraint {        return self.description.constraint!    }    }复制代码

其中,labeled 方法的最后 return self,是为了可以实现链式调用。

ConstraintMakerPriortizable

ConstraintMakerPriortizableConstraintMakerFinalizable 的子类,扩充了关于优先级的一些方法。

public class ConstraintMakerPriortizable: ConstraintMakerFinalizable {        @discardableResult    public func priority(_ amount: ConstraintPriority) -> ConstraintMakerFinalizable {        self.description.priority = amount.value        return self    }        @discardableResult    public func priority(_ amount: ConstraintPriorityTarget) -> ConstraintMakerFinalizable {        self.description.priority = amount        return self    }}复制代码

ConstraintMakerEditable

ConstraintMakerEditableConstraintMakerPriortizable 的子类,扩充了关于设置 multiplierconstant 的方法。

public class ConstraintMakerEditable: ConstraintMakerPriortizable {    @discardableResult    public func multipliedBy(_ amount: ConstraintMultiplierTarget) -> ConstraintMakerEditable {        self.description.multiplier = amount        return self    }        @discardableResult    public func dividedBy(_ amount: ConstraintMultiplierTarget) -> ConstraintMakerEditable {        return self.multipliedBy(1.0 / amount.constraintMultiplierTargetValue)    }        @discardableResult    public func offset(_ amount: ConstraintOffsetTarget) -> ConstraintMakerEditable {        self.description.constant = amount.constraintOffsetTargetValue        return self    }        @discardableResult    public func inset(_ amount: ConstraintInsetTarget) -> ConstraintMakerEditable {        self.description.constant = amount.constraintInsetTargetValue        return self    }    }复制代码

ConstraintMakerRelatable

ConstraintMakerRelatable 是对 ConstraintDescription 的一层包装,作用是为 ConstraintDescription 设置 relation 提供方便方法。有 equalToequalToSuperviewlessThanOrEqualTolessThanOrEqualToSuperviewgreaterThanOrEqualTogreaterThanOrEqualToSuperview 等一系列方法:

@discardableResultpublic func equalTo(_ other: ConstraintRelatableTarget, _ file: String = #file, _ line: UInt = #line) -> ConstraintMakerEditable {
return self.relatedTo(other, relation: .equal, file: file, line: line)} @discardableResultpublic func equalToSuperview(_ file: String = #file, _ line: UInt = #line) -> ConstraintMakerEditable {
guard let other = self.description.item.superview else { fatalError("Expected superview but found nil when attempting make constraint `equalToSuperview`.") } return self.relatedTo(other, relation: .equal, file: file, line: line)} @discardableResultpublic func lessThanOrEqualTo(_ other: ConstraintRelatableTarget, _ file: String = #file, _ line: UInt = #line) -> ConstraintMakerEditable {
return self.relatedTo(other, relation: .lessThanOrEqual, file: file, line: line)} @discardableResultpublic func lessThanOrEqualToSuperview(_ file: String = #file, _ line: UInt = #line) -> ConstraintMakerEditable {
guard let other = self.description.item.superview else { fatalError("Expected superview but found nil when attempting make constraint `lessThanOrEqualToSuperview`.") } return self.relatedTo(other, relation: .lessThanOrEqual, file: file, line: line)} @discardableResultpublic func greaterThanOrEqualTo(_ other: ConstraintRelatableTarget, _ file: String = #file, line: UInt = #line) -> ConstraintMakerEditable {
return self.relatedTo(other, relation: .greaterThanOrEqual, file: file, line: line)} @discardableResultpublic func greaterThanOrEqualToSuperview(_ file: String = #file, line: UInt = #line) -> ConstraintMakerEditable {
guard let other = self.description.item.superview else { fatalError("Expected superview but found nil when attempting make constraint `greaterThanOrEqualToSuperview`.") } return self.relatedTo(other, relation: .greaterThanOrEqual, file: file, line: line)}复制代码

其中有两个点值得学习。

#file 和 #line

Swift 为我们提供了设置方法参数默认值的方法,就是在方法声明处直接为参数赋值:

..._ file: String = #file, _ line: UInt = #line...复制代码

#file#line 则是系统为我们提供的编译符号,供我们获取文件名和行号,更多细节可以参考这篇博客:

fatalError()

有的时候,该崩还是得崩,fatalError() 助你一崩到底,还能添加附加信息,哈啤。

除了以上两点,所有这些方法均调用了内部的 relatedTo 方法:

internal func relatedTo(_ other: ConstraintRelatableTarget, relation: ConstraintRelation, file: String, line: UInt) -> ConstraintMakerEditable {    let related: ConstraintItem    let constant: ConstraintConstantTarget            if let other = other as? ConstraintItem {        guard other.attributes == ConstraintAttributes.none ||                other.attributes.layoutAttributes.count <= 1 ||                other.attributes.layoutAttributes == self.description.attributes.layoutAttributes ||                other.attributes == .edges && self.description.attributes == .margins ||                other.attributes == .margins && self.description.attributes == .edges else {            fatalError("Cannot constraint to multiple non identical attributes. (\(file), \(line))");        }                    related = other        constant = 0.0    } else if let other = other as? ConstraintView {        related = ConstraintItem(target: other, attributes: ConstraintAttributes.none)        constant = 0.0    } else if let other = other as? ConstraintConstantTarget {        related = ConstraintItem(target: nil, attributes: ConstraintAttributes.none)        constant = other    } else if #available(iOS 9.0, OSX 10.11, *), let other = other as? ConstraintLayoutGuide {
related = ConstraintItem(target: other, attributes: ConstraintAttributes.none) constant = 0.0 } else { fatalError("Invalid constraint. (\(file), \(line))") } let editable = ConstraintMakerEditable(self.description) editable.description.sourceLocation = (file, line) editable.description.relation = relation editable.description.related = related editable.description.constant = constant return editable}复制代码

该方法会对约束信息的合法性进行一些判断,进而生成一个 ConstraintMakerEditable 类型的对象并返回之。

ConstraintMakerExtendable

ConstraintMakerExtendableConstraintMakerRelatable 的父类,封装了一系列的计算属性,并有 side-effect 每次调用时对 description.attributes 的会有一些额外效果:

public class ConstraintMakerExtendable: ConstraintMakerRelatable {        public var left: ConstraintMakerExtendable {        self.description.attributes += .left        return self    }        public var top: ConstraintMakerExtendable {        self.description.attributes += .top        return self    }        public var bottom: ConstraintMakerExtendable {        self.description.attributes += .bottom        return self    }        public var right: ConstraintMakerExtendable {        self.description.attributes += .right        return self    }        public var leading: ConstraintMakerExtendable {        self.description.attributes += .leading        return self    }        public var trailing: ConstraintMakerExtendable {        self.description.attributes += .trailing        return self    }        public var width: ConstraintMakerExtendable {        self.description.attributes += .width        return self    }        public var height: ConstraintMakerExtendable {        self.description.attributes += .height        return self    }        public var centerX: ConstraintMakerExtendable {        self.description.attributes += .centerX        return self    }        public var centerY: ConstraintMakerExtendable {        self.description.attributes += .centerY        return self    }        @available(*, deprecated:3.0, message:"Use lastBaseline instead")    public var baseline: ConstraintMakerExtendable {        self.description.attributes += .lastBaseline        return self    }        public var lastBaseline: ConstraintMakerExtendable {        self.description.attributes += .lastBaseline        return self    }        @available(iOS 8.0, OSX 10.11, *)    public var firstBaseline: ConstraintMakerExtendable {        self.description.attributes += .firstBaseline        return self    }        @available(iOS 8.0, *)    public var leftMargin: ConstraintMakerExtendable {        self.description.attributes += .leftMargin        return self    }        @available(iOS 8.0, *)    public var rightMargin: ConstraintMakerExtendable {        self.description.attributes += .rightMargin        return self    }        @available(iOS 8.0, *)    public var topMargin: ConstraintMakerExtendable {        self.description.attributes += .topMargin        return self    }        @available(iOS 8.0, *)    public var bottomMargin: ConstraintMakerExtendable {        self.description.attributes += .bottomMargin        return self    }        @available(iOS 8.0, *)    public var leadingMargin: ConstraintMakerExtendable {        self.description.attributes += .leadingMargin        return self    }        @available(iOS 8.0, *)    public var trailingMargin: ConstraintMakerExtendable {        self.description.attributes += .trailingMargin        return self    }        @available(iOS 8.0, *)    public var centerXWithinMargins: ConstraintMakerExtendable {        self.description.attributes += .centerXWithinMargins        return self    }        @available(iOS 8.0, *)    public var centerYWithinMargins: ConstraintMakerExtendable {        self.description.attributes += .centerYWithinMargins        return self    }        public var edges: ConstraintMakerExtendable {        self.description.attributes += .edges        return self    }    public var size: ConstraintMakerExtendable {        self.description.attributes += .size        return self    }        @available(iOS 8.0, *)    public var margins: ConstraintMakerExtendable {        self.description.attributes += .margins        return self    }        @available(iOS 8.0, *)    public var centerWithinMargins: ConstraintMakerExtendable {        self.description.attributes += .centerWithinMargins        return self    }    }复制代码

如果觉得我写的还不错,请关注我的微博,最新文章即时推送~

转载地址:http://ixsvo.baihongyu.com/

你可能感兴趣的文章
c++类型转换
查看>>
Java IO编程全解(六)——4种I/O的对比与选型
查看>>
(iOS)确保设置话筒模式成功 AudioSessionSetProperty
查看>>
复习笔记:一个简单的反射工厂Demo
查看>>
Google Drive 云端硬盘 可以选择多个文件上传的前端实现
查看>>
or ||
查看>>
编辑一次性计划任务
查看>>
MAC下的mysql忘记密码该怎么办??
查看>>
matlab练习程序(立体相关块匹配)
查看>>
DOS中的CD命令详解
查看>>
你应该知道的jQuery技巧
查看>>
消息处理之performSelector
查看>>
hihoCoder 1174 拓扑排序·一
查看>>
Struts2中防止表单重复提交,global-results定义全局结果处理
查看>>
汇编语言第一章基础知识
查看>>
Java 合并两个有序链表
查看>>
ipv6到ipv4隧道6to4(GNS3)
查看>>
NetBeans数据库笔记---三层架构
查看>>
iOS获取设备型号和App版本号等信息(OC+Swift)
查看>>
纯CSS3鼠标滑过按钮动画过滤特效
查看>>