[Swift]AutoLayout简单封装

简单演示

一、前言

说到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请留言反馈,我会及时解决。欢迎转载(在文章开头标明来源即可)。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,456评论 5 477
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,370评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,337评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,583评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,596评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,572评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,936评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,595评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,850评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,601评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,685评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,371评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,951评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,934评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,167评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 43,636评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,411评论 2 342

推荐阅读更多精彩内容