再看SnapKit

连续两个多月高强度的工作,每天几乎加班到8点才下班,项目在今天上午终于是提交到 App Store 了。整个人瞬时如释重负,但却有种空虚感,不知道做什么了。再看下SnapKit吧。发现之前一直认为就那么用来设置约束即可,没留意到的地方还挺多。下面分别概述下。

一、inset 和 offset

相信大部分小伙伴们都是使用 offset 来控制边距的吧。

cciView.snp.makeConstraints { (make) in
    make.top.equalTo(researchView.snp.bottom).offset(kHeight.d10)
    make.left.equalTo(10)
    make.right.equalTo(-10)
    make.bottom.equalTo(bottomView.snp.bottom)
}

其实 offset 使用的是绝对值,尤其是设置右、下约束的时候,子控件相对于父控件都需要加-号。这一点使用久了,和苹果的 xib 比起来,或多或少觉得有点不太合理。其实该框架是有 inset 来抽象控制的。下面贴下框架的源码:

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
    }
    
}

使用 inset,之前的代码就可以简化成这样(只是举例):

   make.top.equalTo(researchView.snp.bottom).offset(kHeight.d10)
        make.left.equalTo(10)
        make.right.equalToSuperview().inset(10)
        make.bottom.equalTo(bottomView.snp.bottom)
    }

总结下来就是:在描述 view 与 superview 关系时,应该使用 inset,而描述 view 与同一层级的其它 view 时,应该使用 offset。

二、ConstraintConstantTarget

在布局 view 的时候,一般来说设计师都会给 content 一个统一的边距,类似于 html 中的 padding,在构建约束时我们经常会把这个 padding 分散到各处。但事实上,将 padding 分散去处理是一件很糟糕的事情,代码不美观是其次,最重要的是后期维护起来费时费力,更好的方式是使用已有的抽象 UIEdgeInsets。

在调用 equalTo, offset 或者 inset 传入数值时,我们会发现传入的参数类型实际上只有 ConstraintConstantTarget,这是一个协议,SnapKit 把它作为一个类簇在使用,通过一个方法将它转化为 CGFloat 来作为 constraint 的 constant。

UIEdgeInsets 也遵循了这个协议,所以我们可以更加优雅地去处理边距:

//  如果视觉稿中所有的页面的左右边距都遵循左右距离相同,该属性可以改为全局属性。
let containerInsets = UIEdgeInsets(top: 5, left: 15, bottom: 5, right:15)

container.addSubview(a)
container.addSubview(b)

a.snp.makeConstraints {
    $0.top.left.right.equalToSuperview().inset(containerInsets)
}

b.snp.makeConstraints {
    $0.top.equalTo(a.snp.bottom).offset(5)
    $0.left.bottom.right.equalToSuperview().inset(containerInsets)
}

这样,后期修改起来会很容易,代码也简洁了很多。另外 CGPoint 和 CGSize 也遵循了这个协议,大家可以去研究下更多有趣的用法,例如 size.equalTo(20)。

三、修改约束尽量用 updateConstraints

如果要更新布局约束,小弟之前的做法是仿照苹果,用局部变量来引用,然后更新。如下:

// 局部变量保存约束属性
private var bottomViewConsT: Constraint?

// 展示 view 时更新底部约束
bottomViewConsT?.update(offset: -tmpBottomConsH)
UIView.animate(withDuration: kTime.duration, animations: {[weak self] in
        self?.layoutIfNeeded()
}) {  (_) in
}

// 设置约束
bottomView.snp.makeConstraints { (make) in
    make.left.right.equalTo(self).offset(0)
    make.height.equalTo(frame.height * 0.35)
    bottomViewConsT = make.top.equalTo(self.snp.bottom).offset(0).constraint
    }

// 隐藏 view 时更新底部约束
bottomViewConsT?.update(offset: 0)
  UIView.animate(withDuration: 0.1, animations: { [weak self] in
    self?.layoutIfNeeded()
}) { [weak self] (_) in
    self?.removeFromSuperview()
}

其实可以改为:

// 展示 view 时更新底部约束
bottomView.snp.updateConstraints { (make) in
    make.top.equalTo(self.snp.bottom).inset(0)
}

// 设置约束
bottomView.snp.makeConstraints { (make) in
    make.left.right.equalTo(self).offset(0)
    make.height.equalTo(frame.height * 0.35)
    bottomViewConsT = make.top.equalTo(self.snp.bottom).offset(0).constraint
}
// ……

这么做的好处就是语法更简洁一致,让约束表现得更像是 view 的属性。但缺点也很明显,只能更新 constant。

暂时就这些吧(^_^)~~~

你可能感兴趣的:(再看SnapKit)