AutoLayout 使用详解

前言


故事从一年前提及,当时因为接到一个新项目开发任务开发以前想了想之前项目UI布局方式大多数都是frame计算有的也用到masonry
frame你们都知道适配各类屏幕很是繁琐各类坐标size计算代码很冗余后期难以维护。
masonry开源给iOS开发者带来福音简化了AutoLayout使用方式,可是我以为masonry还不足够快捷方便(有的api不知道什么意思学习成本比较高),尤为是动态布局masonry更新约束至关不方便,后来就决定本身开发AutoLayout库也就是今天WHC_AutoLayoutKitjavascript

在阅读以前能够先看看例子项目:github.com/netyouli/WH… java

简介


  • API采用链式调用(快捷方便)一行代码搞定布局
  • 提供【Objective-C】【Swift2.3】【Swift3.0】三种语言版本库
  • 包含一行代码计算UITableViewCell高度模块带缓存高度
  • 包含WHC_StackView模块(目的替代系统UIStackView)
  • 隐式更新约束技术(核心后面重点介绍)

链式调用


view.whc_Left(10)      //view与父视图左边距10
    .whc_Right(10)     //view与父视图右边距10
    .whc_Height(40)    //view自身高度40
    .whc_Top(64)       //view与父视图顶边距64复制代码

一行代码计算Cell高度


func tableView(tableView: UITableView, heightForRowAtIndexPath indexPath: NSIndexPath) -> CGFloat {
    return UITableViewCell.whc_CellHeightForIndexPath(indexPath, tableView: tableView)
}复制代码

隐式更新约束


什么叫隐式更新,顾名思义就是在你添加同类型约束(可能会产生冲突约束)会自动删除前面添加可能产生冲突的约束(更新约束)看下面例子:git

override func viewDidLoad() {
    super.viewDidLoad()
    let view = UIView()
    self.view.addSubview(view)

    view.whc_Left(10)       //view与父视图左边距10
        .whc_Right(10)      //view与父视图右边距10
        .whc_HeightAuto()   //view高度自动
        .whc_Top(64)        //view与父视图顶边距64
}复制代码

有时候程序执行的过程当中根据需求须要动态调整UI布局假如点击按钮上面view高度调整固定64代码以下:github

// 单独更新height约束
private func clickButton(sender: UIButton) {
    view.whc_Height(64)   // 只须要执行这一行代码便可更新view高度为64
}复制代码

上面这个代码执行作了什么事情呢?
他会检查view高度方向是否有同类型可能冲突约束若是检查到那么会删除上面添加的HeightAuto约束而后添加新Height固定约束64。
默认状况固定高度约束优先级比自动高度约束高因此即便不删除上面HeightAuto也不要紧,可是有时候会由于约束冲突程序崩溃。再好比点击按钮以下修改:swift

// 单独更新top约束
private func clickButton(sender: UIButton) {
    view.whc_Top(10, toView: otherView)   //viwe 顶部间隙到otherView底部为10
}复制代码

一样上面的代码执行以前会检查y方向是否有同类型约束(可能冲突的约束),显然view.whc_Top(10)view.whc_Top(10, toView: otherView)确定是冲突的,因此在执行上面代码WHC_AutoLayout会先删除viewwhc_Top(10)约束而后再添加whc_Top(10, toView: otherView)约束。
上面解释就是隐式更新约束技术而不须要像masonry从新重写view全部约束那么麻烦。api

UIView高度自动


override func viewDidLoad() {
    super.viewDidLoad()
    let view = UIView()
    self.view.addSubview(view)

    let label = UILabel()
    self.view.addSubview(label)
    label.text = "xxxxxxxxxxxxxxxxxxxxx"
    label.whc_Left(10)      //label左到view左边距10
         .whc_Right(10)     //label右到view右边距10
         .whc_Top(10)       //label顶到view顶边距10
         .whc_HeightAuto()  //label高度自动
         .whc_Bottom(10, keepHeightConstraint: true) //label底到view底边距10,而且保留label高度

    view.whc_Left(10)       //view与父视图左边距10
        .whc_Right(10)      //view与父视图右边距10
        .whc_Top(64)        //view与父视图顶边距64
        .whc_HeightAuto()   //view高度自动
}复制代码

效果以下:
缓存


下面对上面代码作解释:
为何label须要5个约束?那是由于 view高度须要自动根据 label高度自动调整,而 label高度自己是自动的若是不添加 labelview的底边距 whc_Bottom关系约束 view没法根据 label高度变化而变化。 那可能又有人疑问? whc_Bottom(10, keepHeightConstraint: true)里的 keepHeightConstraint是什么意思?前面介绍了 WHC_AutoLayout是隐式更新约束技术然而很显然 labelwhc_HeightAuto通常状况和 whc_Bottom是同类型约束(冲突约束)因此这两个通常状况只能存在一个约束,可是iOS有一种特殊状况须要 Height约束和 Bottom约束同时存在那就是在 view自动高度的时候( bottom为了撑开父视图由于父视图是自动高度因此须要一个自动高度参照约束)或者 view底边距对齐(不采用 top对齐)的时候如:

label.whc_Left(10)      //label左到view左边距10
     .whc_Right(10)     //label右到view右边距10
     .whc_HeightAuto()  //label高度自动
     .whc_Bottom(10, keepHeightConstraint: true) //label底部间隙和父视图底部10复制代码

上面label就是一种从下往上布局。iview

总结


从上面的例子与介绍能够咱们能够对WHC_AutoLayout得出以下结论:ide

  • 一个控件在不使用带keep的约束API时候无论后面添加多少约束永远只会存在4个
  • 一个控件同方向约束无论后面添加多少约束永远只会保留最后添加的同类型约束自动删除前面其余同类型约束
  • 一个view须要高度或者宽度自动适应时候其view上最后一个控件须要用到5个约束(这个时候须要用到带keep的API,一样从下或者从右开始布局有时候也须要)
  • 关于WHC_StackView后面会有专门的文章详细介绍

    附件


1.x方向同类型约束(不会对宽度产生影响):
Left,Leading,Trailing,CenterX(包含ToView...)
注意WHC_AutoLayoutLeadingTrailing特殊处理理论上他们是能够成对使用的为了统一性把他们归为同类约束Leading左对齐Trailing又对齐
2.y方向同类型约束(不会对宽度产生影响):
Top,BaseLineSpace,CenterY(包含ToView...)
3.宽度方向同类型约束(对宽度产生影响):
Width,Right(包含ToView,自动宽度...)
4.高度方向同类型约束(对高度产生影响):
Height,Bottom(包含ToView,自动高度...)布局


WHC_AutoLayout开源地址github.com/netyouli/WH…
本人其余优秀开源项目:github.com/netyouli/

致敬

谢谢你的耐心阅读

掘金征文: gold.xitu.io/post/58522d…

相关文章
相关标签/搜索