[Swift]AutoLayout简单封装

[Swift]AutoLayout简单封装_第1张图片
简单演示

一、前言

说到Swift中对AutoLayout的封装王者无疑是SnapKit,它简单方便的调用无疑深得人心。笔者今天要讲的是利用Swift的特性对AutoLayout进行简单的封装。相比较SnapKit而言,它的使用不能说更简单方便,但实现可以说是一目了然,也算是对AutoLayout的介绍。下面将会讲封装的思路以及使用介绍。

二、JYAutoLayout的封装思路

如上面演示图的所示,所有橙色 和 白色的View的布局均相对于灰色的大View 而每个view的布局只需要短短的一行代码:

       UIedgeView(htrBtn).left(centerBtn,c:8).alignTop(centerBtn).size(btnSize).end()

2.1NSLayoutConstraint约束创建

 convenience init(item view1: AnyObject, attribute attr1: NSLayoutAttribute, relatedBy relation: NSLayoutRelation, toItem view2: AnyObject?, attribute attr2: NSLayoutAttribute, multiplier: CGFloat, constant c: CGFloat)
   这是一条约束的创建,它的约束关系是 view1.attr1 < = > view2.attr2 * multiplier + c
    所以我们可以看到决定一个View1的某条约束所需的参数有:
var View2    : UIView?                    相对于哪个view 即view2
var Attribute1 : NSLayoutAttribute?     view1  的NSLayoutAttribute
var Attribute2 : NSLayoutAttribute?     view2  的NSLayoutAttribute
var Multiplier : CGFloat?                   比例系数
var Equal = NSLayoutRelation.Equal        大于 等于 小于
var offset : CGFloat                      偏移 
var priority : UILayoutPriority           当然还有当前约束的优先级

2.2NSLayoutAttribute 包含有

case Left                          //左侧
case Right                        //右侧
case Top                          //上方
case Bottom                       //下方
case Leading                      //首部
case Trailing                     //尾部
case Width                        //宽度
case Height                       //高度
case CenterX                      //X轴中心
case CenterY                      //Y轴中心
case Baseline                     //文本底标线
case NotAnAttribute               //没有属性
在iOS8.0下又多了 一些边界属性
case LeftMargin
case RightMargin
case TopMargin
case BottomMargin
case LeadingMargin
case TrailingMargin
case CenterXWithinMargins
case CenterYWithinMargins

注:Left/Right 和 Leading/Trailing的区别是Left/Right永远是指左右,而Leading/Trailing在某些从右至左习惯的地区会变成,leading是右边,trailing是左边。

2.3简化封装

以view的上边为例我们可以提供下面一个方法来表示一条约束参数

private func top(v:UIView! , c : CGFloat , a : NSLayoutAttribute = NSLayoutAttribute.Bottom , m : CGFloat = 1.0 , e : NSLayoutRelation = NSLayoutRelation.Equal, p : UILayoutPriority = UILayoutPriorityDefaultHigh) -> UIedgeView {
   
}

view的top 与 v 的 a * m + c 当然还有优先级
swift有个非常好的地方,那就是只要设置了默认参数就可以不用传该参数,而在我们实际使用中 一般都是 等于 而比例细数也基本 是1.0,所以通常 只要设置 v(view)c (偏移) a(对应的边)即可,而优先级也基本不使用。

又考虑到 top 对 top 与 top 对 Bottom 是极为常见的所以又以方法名来区分 以 alignTop方法来表示 top 对 top关系 而 top方法默认表示 top 对 Bottom关系 当然top方法仍可以传入NSLayoutAttribute参数,这样%90的情况下我们只需要设置两个参数 view 与 c 就可以描述一条参数。如: htrBtn.left(centerBtn,c:8)
同理对 Bottom Right Left Width Height CenterX CenterY做了处理。

2.4链式编程的实现

swift的方法调用都是点语法,再也不像OC那样需要[],我们只需要在一个方法结束时返回self 就可以无限调用

 @discardableResult  func top(_ v: UIView! , c: CGFloat = 0 , a: NSLayoutAttribute = NSLayoutAttribute.bottom , m: CGFloat = 1.0 , e: NSLayoutRelation = NSLayoutRelation.equal, p: UILayoutPriority = UILayoutPriorityDefaultHigh) -> UIedgeView {
    
    let layout = JYlayout(v: v, c: c, a1:NSLayoutAttribute.top , a2: a, m: m, e: e, p: p)
    dict .setValue(layout, forKey: ffTop)
    return self
}

2.5约束的添加 end() remake() update()

对于这么一个布局 htrBtn.left(centerBtn,c:8).alignTop(centerBtn).size(btnSize) 都是约束的准备只是将约束所需要的参数保存到了UIedgeView这么一个对象中
而 end() remake() update() 才是添加相应的约束
end() 什么都不管只管添加约束
remake() 会将之前的约束全部删除,重新添加
update() 会根据当前代码所设计到的约束,而删除对应约束,比如 btn.centerX(self).size(100, h: 100).update() 它涉及到了 centerX Width Height 的约束那么它会将之前添加的关于 centerX Width Height 的所有约束删除然后添加。

注意:1.remake() update() 删除约束使用的是以下方法:
public func removeConstraint(constraint: NSLayoutConstraint) // This method will be deprecated in a future release and should be avoided. Instead set NSLayoutConstraint's active property to NO.
这个方法将会在将来的版本中被弃用,应该避免。苹果也不太建议删除约束再添加,如果有约束改变应当记录约束直接修改,可以参考Demo中的AnimDemoView1,或者添加多个约束使用修改优先级来达到改变的目的,可以参考Demo中的AnimDemoView2

2.不要使用 btn.centerX(self).centerX(view2).end() 这种写法是错误的,有效约束只会是centerX(view2)。如有需要应当如下:

   btn.makeConstraint { (make) in
        make.centerX(reference1,p:priorityMedium).end()
        make.centerX(reference2,p:priorityHigh).end()
   }

7.提供的方法说明

top                 默认 top 对 bottom
alignTop            top 对 top
left                默认 left 对 right
alignLeft           left 对 left
bottom              默认 bottom 对 top
alignBottom         bottom 对 bottom
right               默认 right 对 left
alignRight          right 对 right
centerX             默认 centerX 对 centerX    
centerY             默认 centerY 对 centerY    
center              默认 centerX 对 centerX centerY 对 centerY
height              有对view 的 height 也有提供 数字 50
width               有对view 的 width 也有提供  数字 50
size                有对view 的 width height 也有提供 CGsize

方法的参数描述
@discardableResult  func top(_ v: UIView! , c: CGFloat = 0 , a: NSLayoutAttribute = NSLayoutAttribute.bottom , m: CGFloat = 1.0 , e: NSLayoutRelation = NSLayoutRelation.equal, p: UILayoutPriority = UILayoutPriorityDefaultHigh) -> UIedgeView {
    
    let layout = JYlayout(v: v, c: c, a1:NSLayoutAttribute.top , a2: a, m: m, e: e, p: p)
    dict .setValue(layout, forKey: ffTop)
    return self
}

v :参照的view
c : 偏移
m : 比例系数
a : 参照view的NSLayoutAttribute
e : NSLayoutRelation.Equal 大于 等于 小于
p : 优先级

关于优先级定义:
public let  priorityHighTop = (UILayoutPriority)(UILayoutPriorityDefaultHigh + 1); 
public let  priorityHigh = UILayoutPriorityDefaultHigh;
public let  priorityMedium = (UILayoutPriority)(500);
public let  priorityLow = UILayoutPriorityDefaultLow;
public let  priorityRequired = UILayoutPriorityRequired;
public let  priorityFittingSizeLevel = UILayoutPriorityFittingSizeLevel;

如果还需要 Baseline 等相关关系可自行封装,都是体力活

三、结尾

JYAutoLayout是笔者在Swift2 时代的一个练手产物,利用了Swift点语法调用以及参数可预设的特性对AutoLayout的封装,使用也是简单方便。SnapKit虽然使用简单,但在我看来它封装的过于复杂了,带来的收益(简单调用)完全可以用更方便的方式封装。相信大家在升级到Xcode8时看到SnapKit爆红时有多么萌比,我们也只能等待作者更新。与其依赖别人,不如依赖自己,JYAutoLayout的封装相当简单相信一个对AutoLayout有所了解的同学在看完笔者的简单说明后自己就可以写出来了,在之上扩展优化更不在话下。

如果我的文章对你有帮助或者给了你一些启发,希望你能在github给个小星星,如果你在使用过程中遇到了Bug请留言反馈,我会及时解决。欢迎转载(在文章开头标明来源即可)。

你可能感兴趣的:([Swift]AutoLayout简单封装)