SnapKit源码阅读(一)

在自动布局的博客中学习了系统如何设置,在Swift中SnapKit是应用比较广泛的布局库,今天对此进行学习。

SnapKit使用
class MyViewController: UIViewController {
    lazy var box = UIView()
    override func viewDidLoad() {
        super.viewDidLoad()
        // 添加需要约束页面
        self.view.addSubview(box)
        box.snp.makeConstraints { (make) -> Void in
           make.width.height.equalTo(50)
           make.center.equalTo(self.view)
        }
    }

}

如上代码所示,在使用的时候我们优先调用添加约束的方法,在闭包中设置约束。

首先,重新命名几个系统类别:

// 设置约束视图ConstraintView
public typealias ConstraintView = UIView
// 布局关系
typealias LayoutRelation = NSLayoutConstraint.Relation
// 布局属性
typealias LayoutAttribute = NSLayoutConstraint.Attribute 
// 布局优先级
typealias LayoutPriority = NSLayoutConstraint.Priority
 // 边距值
 public typealias ConstraintInsets = UIEdgeInsets
 // 布局引导
 public typealias ConstraintLayoutGuide = UILayoutGuide
 // 视图方向
 public typealias ConstraintInterfaceLayoutDirection = UIUserInterfaceLayoutDirection
 // 约束布局支持
 public typealias ConstraintLayoutSupport = UILayoutSupport

在ConstraintView中只有一个snp属性,获取ConstraintViewDSL对象

  // 使用snp返回ConstraintViewDSL的实例对象,创建
    public var snp: ConstraintViewDSL {
        return ConstraintViewDSL(view: self)
    }

ConstraintViewDSL

ConstraintViewDSL结构体,实现ConstraintAttributesDSL协议,实现target 返回当前视图。
持有视图view,设置视图的拉伸优先级和压缩优先级,同时生成约束集合的准备、生成、重置、更新和移除功能。

     /// 创建约束
    public func makeConstraints(_ closure: (_ make: ConstraintMaker) -> Void) {
     // 调用ConstraintMaker方法
        ConstraintMaker.makeConstraints(item: self.view, closure: closure)
    }
  • ConstraintAttributesDSL
    继承自ConstraintBasicAttributesDSL协议,约束的扩展属性,返回ConstraintItem对象。
  • ConstraintBasicAttributesDSL
    继承自ConstraintDSL协议,约束的基础属性,返回ConstraintItem对象。
    约束属性ConstraintItem构建如下,持有当前协议的目标对象:
  public var left: ConstraintItem {
        return ConstraintItem(target: self.target, attributes: ConstraintAttributes.left)
    }
  • ConstraintDSL
    ConstraintDSL协议中约定属性target 和两个方法:func setLabel(_ value: String?)func label() -> String?,扩展中默认实现。
extension ConstraintDSL {
    public func setLabel(_ value: String?) {
        // 设置标签
        objc_setAssociatedObject(self.target as Any, &labelKey, value, .OBJC_ASSOCIATION_COPY_NONATOMIC)
    }
    public func label() -> String? {
        // 返回标签
        return objc_getAssociatedObject(self.target as Any, &labelKey) as? String
    } 
}

ConstraintViewDSL类图


ConstraintItem

约束元素,持有target 目标和attributes 约束属性集合。

  internal init(target: AnyObject?, attributes: ConstraintAttributes) {
        self.target = target
        self.attributes = attributes
    }
  // 布局元素
    internal var layoutConstraintItem: LayoutConstraintItem? {
        return self.target as? LayoutConstraintItem
    }
LayoutConstraintItem

布局约束元素协议,没有必须实现的协议方法和属性。
ConstraintLayoutGuideConstraintView 皆实现此协议。
这里写图片描述

私有属性constraintsSet:constraints属性,add和remove方法都是操作constraintsSet集合:

// 私有约束key值
private var constraintsKey: UInt8 = 0

 /// 私有属性约束集合,动态添加。使用集合保证添加无重复约束 
    private var constraintsSet: NSMutableSet {
        let constraintsSet: NSMutableSet
        // 存在constraintsSet属性,直接赋值;不存在constraintsSet属性,添加属性
        if let existing = objc_getAssociatedObject(self, &constraintsKey) as? NSMutableSet { 
            constraintsSet = existing
        } else { 
            constraintsSet = NSMutableSet()
            objc_setAssociatedObject(self, &constraintsKey, constraintsSet, .OBJC_ASSOCIATION_RETAIN_NONATOMIC)
        }
        return constraintsSet  
    }
ConstraintAttributes

约束属性集合结构体,是一个OptionSet选项集合。属性layoutAttributes:[LayoutAttribute] 持有LayoutAttribute的数组

/// 求并集
internal func + (left: ConstraintAttributes, right: ConstraintAttributes) -> ConstraintAttributes {
    return left.union(right)
}
/// 并集,同时赋值给左边的值
internal func +=(left: inout ConstraintAttributes, right: ConstraintAttributes) {
    left.formUnion(right)
}
/// 求差集
internal func -=(left: inout ConstraintAttributes, right: ConstraintAttributes) {
    left.subtract(right)
}
/// 判断是否相等
internal func ==(left: ConstraintAttributes, right: ConstraintAttributes) -> Bool {
    return left.rawValue == right.rawValue
}

这里写图片描述


ConstraintMaker

约束制造器,持有视图item,属性descriptions, 同时实现约束的准备、生成、重置、更新和移除功能。
ConstraintMaker类图

根据LayoutConstraintItem协议实例,初始化ConstraintMaker:

 internal init(item: LayoutConstraintItem) {
        self.item = item
        self.item.prepare() // 调用prepare方法
    } 

在ConstraintViewDSL调用ConstraintMaker相同方法,创建,更新,充值方法都调用makeConstraints 方法。

创建约束方法:

  internal static func makeConstraints(item: LayoutConstraintItem, closure: (_ make: ConstraintMaker) -> Void) {
        let constraints = prepareConstraints(item: item, closure: closure)
        for constraint in constraints { // 获取每一条约束,并激活
            constraint.activateIfNeeded(updatingExisting: false)
        }
    }

准备约束方法,从描述中获取约束:

 internal static func prepareConstraints(item: LayoutConstraintItem, closure: (_ make: ConstraintMaker) -> Void) -> [Constraint] {
        let maker = ConstraintMaker(item: item) // 创建maker
        closure(maker)  // 实现闭包方法
        var constraints: [Constraint] = []
        for description in maker.descriptions {     // 获取每条description的描述信息的约束
            guard let constraint = description.constraint else {continue }
            constraints.append(constraint)
        }
        return constraints
    }
Constraint

约束类, 生成LayoutConstraint,并激活约束,更新常量和优先级等操作。

约束类类图

  • ConstraintRelation
    约束之间的关系的枚举,分为等于,大于等于,小于等于。属性layoutRelation 返回系统的LayoutRelation。

  • ConstraintMultiplierTarget
    约束倍数 Int ,UInt,Float,Double,CGFloat都实现此协议,实现协议属性constraintMultiplierTargetValue(强制转换)

  • ConstraintConstantTarget
    约束常量协议,CGPoint,CGSize,ConstraintInsets实现协议。实现协议方法constraintConstantTargetValueFor(layoutAttribute: LayoutAttribute 返回CGFloat的值。

  • ConstraintInsetTarget
    内边距协议, Int , UInt , Float,Double,CGFloat,ConstraintInsets都实现协议,继承自ConstraintConstantTarget协议。默认实现constraintInsetTargetValue: ConstraintInsets 属性,类型为ConstraintInsets。

  • ConstraintOffsetTarget
    偏移量协议, Int , UInt , Float,Double,CGFloat都实现协议,继承ConstraintConstantTarget协议。默认实现constraintOffsetTargetValue 属性。

  • ConstraintPriorityTarget
    约束优先目标协议,Int,UInt,Float,Double,CGFloat,UILayoutPriority都实现此协议,实现协议属性constraintPriorityTargetValue Float值

ConstraintDescription

约束描述类,持有LayoutConstraintItem和ConstraintAttributes约束属性集合,描述约束的各种属性,包括约束,约束属性,优先级,常量等。

    internal lazy var constraint: Constraint? = {
        guard let relation = self.relation,let related = self.related,let sourceLocation = self.sourceLocation else {return nil}
        // 来源组件
        let from = ConstraintItem(target: self.item, attributes: self.attributes)
        // 生成并返回最终约束
        return Constraint(from: from, to: related, relation: relation,sourceLocation: sourceLocation,label: self.label,multiplier: self.multiplier,constant: self.constant,priority: self.priority
        )
    }()

约束描述类图

猜你喜欢

转载自blog.csdn.net/m0_38055718/article/details/81112372