iOS9 Programming - Autolayout (I)

校对:Ray_Xia

今天和大家来唠一唠关于 Autolayout 的那点事,若大家在阅读过程中发现错误请及时指正,共同进步哈!😄

Autolayout

一个 view 通常有三种 autolayout 的方式:

  • 代码中为 view 添加 autolayout 约束,那么这个 view 将会使用 autolayout 来添加 constraint
  • 在加载nib文件的时候,系统会检查是否勾选了 “Use Auto Layout” 选项, 如果勾选了则 xib 中的控件将会使用 autolayout
  • 在你自定义的view中,如果它在类方法requiresConstraintBasedLayout 中返回 true,则这个 view 会使用 autolayout 。 autolayout 存在这种方法的原因是由于你可能需要打开 autolayout 以便在代码中添加约束。
    在代码中添加约束的一个通常的地方是 updateConstraint 这个方法。然而,如果 autolayout 没有打开,updateConstraint 这个方法不会被调用。所以 requiresConstraintBasedLayout 是打开 autolayout 的一种方法。
    当一组相同层级的视图使用了 autolayout 则另外一组不可以使用,当 superview 使用了 autolayout 则它的 subviews 则不可以使用。autolayout 是通过 superview 链实现的,因此如果一个 view 使用了 autolayout 则它的 superview 也会自动的使用。如果这些 view 中有一个是 viewcontroller 中的 main view 则这个viewcontroller 会接收到相关 autolayout 的事件,否则将不会接受到事件。

注意
你不能在nib中关闭掉 autolayout ,所有的 nib 中的 view 需要使用 autolayout 或者 autoresizing。 如果你的 nib 中一部分使用 autoresizing 另外一部分使用 autolayout, 最好是将它们分别开来到不同的 nib 中 然后在 runtime 的时候将它们加载并结合。有兴趣的同学可以试一下,我一般不会将这两种方式结合使用。

Constraints

Autolayout 的 constraints 和 一般的 contraints 其实都是 NSLayoutContraint 的实例对象,它表明了一个 view 的高和宽,或者来描述两个view之间的属性关系,对于后者来讲,属性不一定要一样,两个view 之间并不必须是兄弟关系(即两个view拥有同一个superview)或者父子关系(superview和subview)。唯一的要求就是它们拥有一个相同的祖先(也就是说在view的层级中有一个最终的superview)
两个 view 的的属性都会有它们各自的 constraint, 如果 constraint 表明了一个 view 的长和宽,那另外一个 view 将会是 nil 其属性为 .NotAnAttribute,如果你不理解的话,不要着急,一会儿会有代码演示。其他的属性还有:

  • .Top, .Bottom
  • .Left, .Right, .Leading, .Trailing
  • .Eidth, .Height
  • .CenterX, CenterY
  • .FirstBaseline, .LastBaseline

.FirstBaseline 主要适用于多行标签,从标签顶部向下一定的距离;.LastBaseline 是从标签的底部向上一定距离。
值得一提的是 .leadingtrailing 整两个属性,其实就是 “左” 和 “右”的意思。在 iOS9 中,整个界面将会自动翻转,只有你使用 leadingtrailing 约束时,界面才不会乱。

multiplier,constant

这两个数字会应用到第二个属性来决定第一个属性的值。multiplier会乘上第二个属性的值,然后加上constant的值就是第一个属性的值。
基本上可以用这个公式来解释:a1 = ma2+c,a1和a2是两个属性,m和c分别是乘数和常数。因此,要使第一个属性的值等于
第二个属性的值,那么 multiplier 设为1,常数设为0.如果你要将一个 view 的 width 和height 设为一个绝对值,那么,乘数要为1然后将 constant 设为
width 和 height 的值。

relation

一个NSLayoutRelation用改变multiplierconstant来描述两个属性之间的关系。这就是我在前面小段在等式中放入等式标记。等式标记可能是.Equal,但也可以用非等式标记.LessThanOrEqual.GreaterThanOrEqual

priority

priority 的值在 1-1000 范围内,某些特定的标准有特定的 peiorities 与之对应。 约束可以有不同的优先级,来确定他们的顺序。

约束是属于它的 view 的,一个 view 可以有许多个约束, 每个 UIView 都含有一个 constraints 属性,以及下面的实例方法:

addConstraint:, addConstraints:
removeConstraint:, removeConstraints:

问题是所给定的约束到底属于哪个View。答案是:与这个约束相关的views中,在view层级中最近的那个view。如果可能的话,应该是views中的其中一个。 举个例子:如果一个 view 指定了 width 的宽度这个约束,这个约束就属于这个view;如果这个 view 设置了与 superview 顶部的约束,这个约束就属于这个 view 的 superview ,如果这个 view 与他的兄弟 view 对齐,那这个约束就属于他们共同的 superview 。
然而从 iOS8 开始,你可以用 NSLayoutConstraint类方法activateConstraints 来激活约束,而不是显式指定将约束给某个view。激活的约束将自动的添加到正确的 view 上面,这减少了开发者去决定到底该将约束赋给某个 view 。当然也要一个方法来去掉 view 的约束:deactivateConstraints。一个约束有一个激活的属性,你可以将一个约束设为激活或者不激活,再加上它会告诉你之前添加的一个约束是否是界面的一部分。

NSLayoutConstraints 的属性都是只读属性,除了priorityconstant ,如果你想改变已存在的约束, 你只能先将其移出然后再新添加一个constraints。

Autoresizing constraints

如果你机械的将一个视图设置为了自动布局,则其他视图也会变成自动布局,即使其他的视图之前并没有使用过自动布局。因此它们需要一种方式,当这个view变成自动布局的时候,要以自动布局的方式来决定这个view的位置和布局的约束,他们之前是通过 frameautoresizingMask 来决定的。在运行时,autolayout 会把 view 的frameautoresizing 设置到 constraints 中,其结果会生成一组隐式的约束来影响这个 view。多亏了这些隐式的约束,可以让 layout 在 view的autoreszingMask 的作用下继续工作
举个例子,假如我有一个 UILabel 它的frame设置为(20,20,42,22),并且设置它的 autoreszingMask.None。如果这个 label 使用了 autolayout, 则它的 superview 将会获取到 四个隐式的约束来设置它的长和宽以及 centerX,centerY。
刚才我们所说的都是在你把 view 的 translatesAutoresizingMaskIntoConstraints 设置为 true 的情况下,事实上如果这个 view 是从代码或者从未勾选 "Use Auto Layout" 的 nib文件中实例化出来则 translatesAutoresizingMaskIntoConstraints 的默认值都是 true。做一个猜想如果一个 view 的实例通过上面的方式得到的,你想让它的 frame 和 autoreszingMask 作为约束参与 autolayout。
需要注意的是如果你明确希望你的 view 只使用 autolayout 那你一定要记得设置 translatesAutoresizingMaskIntoConstraints 为 false。如果你忘记设置了,那么隐式约束和你设置的显式约束都会影响到 view 这样将会出现你不希望看到的结果。并且会出现约束冲突,会在控制台报警告呦!

Creating constraints in code

在代码中为一个view添加约束要采用 NSLayoutConstraint 的初始化方法 init(item:at tri bute:related By:to Item:at - tri bute: mul ti plier:con stant:) 接下来我们将上一节Layout(Autoresizing)用Autoresizing实现的view重新用constraints实现一遍:

Autolayout.png

代码如下:

let v1 = UIView(frame: CGRectMake(100,111,132,194))
        v1.backgroundColor = UIColor.magentaColor()
        
        let v2 = UIView(frame: CGRectMake(0,0,132,10))
        v2.backgroundColor = UIColor.greenColor()
        
        let v3 = UIView(frame: CGRectMake(v1.bounds.width-20, v1.bounds.height-20,20,20))
        v3.backgroundColor = UIColor.blueColor()
        
        self.view.addSubview(v1)
        v1.addSubview(v2)
        v1.addSubview(v3)
        
        v2.translatesAutoresizingMaskIntoConstraints = false
        v3.translatesAutoresizingMaskIntoConstraints = false
        
        v1.addConstraint(
            NSLayoutConstraint(item: v2,
                attribute: .Leading,
                relatedBy: .Equal,
                toItem: v1,
                attribute: .Leading,
                multiplier: 1,
                constant: 0))
        
        v1.addConstraint(
            NSLayoutConstraint(item: v2,
                attribute: .Trailing,
                relatedBy: .Equal,
                toItem: v1,
                attribute: .Trailing,
                multiplier: 1,
                constant: 0))
        
        v1.addConstraint(
            NSLayoutConstraint(item: v2,
                attribute: .Top,
                relatedBy: .Equal,
                toItem: v1,
                attribute:.Top,
                multiplier:1,
                constant: 0))
        
        v2.addConstraint(
            NSLayoutConstraint(item:v2 ,
                attribute: .Height,
                relatedBy: .Equal,
                toItem: nil,
                attribute: .NotAnAttribute,
                multiplier: 1,
                constant: 10))
        
        v3.addConstraint(NSLayoutConstraint(item: v3,
            attribute: .Width,
            relatedBy: .Equal,
            toItem: nil,
            attribute: .NotAnAttribute,
            multiplier: 1,
            constant: 20))
        
        v3.addConstraint(NSLayoutConstraint(item: v3,
            attribute: .Height,
            relatedBy: .Equal,
            toItem: nil,
            attribute: .NotAnAttribute,
            multiplier: 1,
            constant: 20))
        
        v1.addConstraint(NSLayoutConstraint(item: v3,
            attribute: .Trailing,
            relatedBy: .Equal,
            toItem: v1,
            attribute: .Trailing,
            multiplier: 1,
            constant: 0))
        
        v1.addConstraint(NSLayoutConstraint(item: v3,
            attribute: .Bottom,
            relatedBy: .Equal,
            toItem: v1,
            attribute: .Bottom,
            multiplier: 1, constant:0))

贴出了这么一大块代码,可能你看上去觉得很复杂,并且很冗余,如果你是初学者希望你耐下性子看下去,你会发现 autolayout 真的要比 autoresizing 简单易懂,并且表述出来的意思也要比 autoresizing 更加清晰。并且 autolayout 能够表述出 autoresizing 不能做的事情,比如,我们现在设置v2的高度是v1高度的十分之一,并且无论v1的高度怎么变v2的高度都是v1的十分之一,如果不用autolayout做的话,则必须在代码中实现 layoutSubviews方法。那么工作量又提高了一个重量级。

ok,以上就是前三天学习到的关于Autolayout方面的知识点,以前只晓得用但并不了解其中的原理和更深层的含义。经过这几天的学习真的是受益匪浅,关于layou方面的知识将会不断更新,敬请期待呦!

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

推荐阅读更多精彩内容