iOS9 Programming - Autolayout (I)

校對(duì):Ray_Xia

今天和大家來(lái)嘮一嘮關(guān)于 Autolayout 的那點(diǎn)事,若大家在閱讀過(guò)程中發(fā)現(xiàn)錯(cuò)誤請(qǐng)及時(shí)指正,共同進(jìn)步哈!??

Autolayout

一個(gè) view 通常有三種 autolayout 的方式:

  • 代碼中為 view 添加 autolayout 約束,那么這個(gè) view 將會(huì)使用 autolayout 來(lái)添加 constraint
  • 在加載nib文件的時(shí)候,系統(tǒng)會(huì)檢查是否勾選了 “Use Auto Layout” 選項(xiàng), 如果勾選了則 xib 中的控件將會(huì)使用 autolayout
  • 在你自定義的view中,如果它在類方法requiresConstraintBasedLayout 中返回 true,則這個(gè) view 會(huì)使用 autolayout 。 autolayout 存在這種方法的原因是由于你可能需要打開(kāi) autolayout 以便在代碼中添加約束。
    在代碼中添加約束的一個(gè)通常的地方是 updateConstraint 這個(gè)方法。然而,如果 autolayout 沒(méi)有打開(kāi),updateConstraint 這個(gè)方法不會(huì)被調(diào)用。所以 requiresConstraintBasedLayout 是打開(kāi) autolayout 的一種方法。
    當(dāng)一組相同層級(jí)的視圖使用了 autolayout 則另外一組不可以使用,當(dāng) superview 使用了 autolayout 則它的 subviews 則不可以使用。autolayout 是通過(guò) superview 鏈實(shí)現(xiàn)的,因此如果一個(gè) view 使用了 autolayout 則它的 superview 也會(huì)自動(dòng)的使用。如果這些 view 中有一個(gè)是 viewcontroller 中的 main view 則這個(gè)viewcontroller 會(huì)接收到相關(guān) autolayout 的事件,否則將不會(huì)接受到事件。

注意
你不能在nib中關(guān)閉掉 autolayout ,所有的 nib 中的 view 需要使用 autolayout 或者 autoresizing。 如果你的 nib 中一部分使用 autoresizing 另外一部分使用 autolayout, 最好是將它們分別開(kāi)來(lái)到不同的 nib 中 然后在 runtime 的時(shí)候?qū)⑺鼈兗虞d并結(jié)合。有興趣的同學(xué)可以試一下,我一般不會(huì)將這兩種方式結(jié)合使用。

Constraints

Autolayout 的 constraints 和 一般的 contraints 其實(shí)都是 NSLayoutContraint 的實(shí)例對(duì)象,它表明了一個(gè) view 的高和寬,或者來(lái)描述兩個(gè)view之間的屬性關(guān)系,對(duì)于后者來(lái)講,屬性不一定要一樣,兩個(gè)view 之間并不必須是兄弟關(guān)系(即兩個(gè)view擁有同一個(gè)superview)或者父子關(guān)系(superview和subview)。唯一的要求就是它們擁有一個(gè)相同的祖先(也就是說(shuō)在view的層級(jí)中有一個(gè)最終的superview)
兩個(gè) view 的的屬性都會(huì)有它們各自的 constraint, 如果 constraint 表明了一個(gè) view 的長(zhǎng)和寬,那另外一個(gè) view 將會(huì)是 nil 其屬性為 .NotAnAttribute,如果你不理解的話,不要著急,一會(huì)兒會(huì)有代碼演示。其他的屬性還有:

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

.FirstBaseline 主要適用于多行標(biāo)簽,從標(biāo)簽頂部向下一定的距離;.LastBaseline 是從標(biāo)簽的底部向上一定距離。
值得一提的是 .leadingtrailing 整兩個(gè)屬性,其實(shí)就是 “左” 和 “右”的意思。在 iOS9 中,整個(gè)界面將會(huì)自動(dòng)翻轉(zhuǎn),只有你使用 leadingtrailing 約束時(shí),界面才不會(huì)亂。

multiplier,constant

這兩個(gè)數(shù)字會(huì)應(yīng)用到第二個(gè)屬性來(lái)決定第一個(gè)屬性的值。multiplier會(huì)乘上第二個(gè)屬性的值,然后加上constant的值就是第一個(gè)屬性的值。
基本上可以用這個(gè)公式來(lái)解釋:a1 = ma2+c,a1和a2是兩個(gè)屬性,m和c分別是乘數(shù)和常數(shù)。因此,要使第一個(gè)屬性的值等于
第二個(gè)屬性的值,那么 multiplier 設(shè)為1,常數(shù)設(shè)為0.如果你要將一個(gè) view 的 width 和height 設(shè)為一個(gè)絕對(duì)值,那么,乘數(shù)要為1然后將 constant 設(shè)為
width 和 height 的值。

relation

一個(gè)NSLayoutRelation用改變multiplierconstant來(lái)描述兩個(gè)屬性之間的關(guān)系。這就是我在前面小段在等式中放入等式標(biāo)記。等式標(biāo)記可能是.Equal,但也可以用非等式標(biāo)記.LessThanOrEqual.GreaterThanOrEqual

priority

priority 的值在 1-1000 范圍內(nèi),某些特定的標(biāo)準(zhǔn)有特定的 peiorities 與之對(duì)應(yīng)。 約束可以有不同的優(yōu)先級(jí),來(lái)確定他們的順序。

約束是屬于它的 view 的,一個(gè) view 可以有許多個(gè)約束, 每個(gè) UIView 都含有一個(gè) constraints 屬性,以及下面的實(shí)例方法:

addConstraint:, addConstraints:
removeConstraint:, removeConstraints:

問(wèn)題是所給定的約束到底屬于哪個(gè)View。答案是:與這個(gè)約束相關(guān)的views中,在view層級(jí)中最近的那個(gè)view。如果可能的話,應(yīng)該是views中的其中一個(gè)。 舉個(gè)例子:如果一個(gè) view 指定了 width 的寬度這個(gè)約束,這個(gè)約束就屬于這個(gè)view;如果這個(gè) view 設(shè)置了與 superview 頂部的約束,這個(gè)約束就屬于這個(gè) view 的 superview ,如果這個(gè) view 與他的兄弟 view 對(duì)齊,那這個(gè)約束就屬于他們共同的 superview 。
然而從 iOS8 開(kāi)始,你可以用 NSLayoutConstraint類方法activateConstraints 來(lái)激活約束,而不是顯式指定將約束給某個(gè)view。激活的約束將自動(dòng)的添加到正確的 view 上面,這減少了開(kāi)發(fā)者去決定到底該將約束賦給某個(gè) view 。當(dāng)然也要一個(gè)方法來(lái)去掉 view 的約束:deactivateConstraints。一個(gè)約束有一個(gè)激活的屬性,你可以將一個(gè)約束設(shè)為激活或者不激活,再加上它會(huì)告訴你之前添加的一個(gè)約束是否是界面的一部分。

NSLayoutConstraints 的屬性都是只讀屬性,除了priorityconstant ,如果你想改變已存在的約束, 你只能先將其移出然后再新添加一個(gè)constraints。

Autoresizing constraints

如果你機(jī)械的將一個(gè)視圖設(shè)置為了自動(dòng)布局,則其他視圖也會(huì)變成自動(dòng)布局,即使其他的視圖之前并沒(méi)有使用過(guò)自動(dòng)布局。因此它們需要一種方式,當(dāng)這個(gè)view變成自動(dòng)布局的時(shí)候,要以自動(dòng)布局的方式來(lái)決定這個(gè)view的位置和布局的約束,他們之前是通過(guò) frameautoresizingMask 來(lái)決定的。在運(yùn)行時(shí),autolayout 會(huì)把 view 的frameautoresizing 設(shè)置到 constraints 中,其結(jié)果會(huì)生成一組隱式的約束來(lái)影響這個(gè) view。多虧了這些隱式的約束,可以讓 layout 在 view的autoreszingMask 的作用下繼續(xù)工作
舉個(gè)例子,假如我有一個(gè) UILabel 它的frame設(shè)置為(20,20,42,22),并且設(shè)置它的 autoreszingMask.None。如果這個(gè) label 使用了 autolayout, 則它的 superview 將會(huì)獲取到 四個(gè)隱式的約束來(lái)設(shè)置它的長(zhǎng)和寬以及 centerX,centerY。
剛才我們所說(shuō)的都是在你把 view 的 translatesAutoresizingMaskIntoConstraints 設(shè)置為 true 的情況下,事實(shí)上如果這個(gè) view 是從代碼或者從未勾選 "Use Auto Layout" 的 nib文件中實(shí)例化出來(lái)則 translatesAutoresizingMaskIntoConstraints 的默認(rèn)值都是 true。做一個(gè)猜想如果一個(gè) view 的實(shí)例通過(guò)上面的方式得到的,你想讓它的 frame 和 autoreszingMask 作為約束參與 autolayout。
需要注意的是如果你明確希望你的 view 只使用 autolayout 那你一定要記得設(shè)置 translatesAutoresizingMaskIntoConstraints 為 false。如果你忘記設(shè)置了,那么隱式約束和你設(shè)置的顯式約束都會(huì)影響到 view 這樣將會(huì)出現(xiàn)你不希望看到的結(jié)果。并且會(huì)出現(xiàn)約束沖突,會(huì)在控制臺(tái)報(bào)警告呦!

Creating constraints in code

在代碼中為一個(gè)view添加約束要采用 NSLayoutConstraint 的初始化方法 init(item:at tri bute:related By:to Item:at - tri bute: mul ti plier:con stant:) 接下來(lái)我們將上一節(jié)Layout(Autoresizing)用Autoresizing實(shí)現(xiàn)的view重新用constraints實(shí)現(xiàn)一遍:

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

貼出了這么一大塊代碼,可能你看上去覺(jué)得很復(fù)雜,并且很冗余,如果你是初學(xué)者希望你耐下性子看下去,你會(huì)發(fā)現(xiàn) autolayout 真的要比 autoresizing 簡(jiǎn)單易懂,并且表述出來(lái)的意思也要比 autoresizing 更加清晰。并且 autolayout 能夠表述出 autoresizing 不能做的事情,比如,我們現(xiàn)在設(shè)置v2的高度是v1高度的十分之一,并且無(wú)論v1的高度怎么變v2的高度都是v1的十分之一,如果不用autolayout做的話,則必須在代碼中實(shí)現(xiàn) layoutSubviews方法。那么工作量又提高了一個(gè)重量級(jí)。

ok,以上就是前三天學(xué)習(xí)到的關(guān)于Autolayout方面的知識(shí)點(diǎn),以前只曉得用但并不了解其中的原理和更深層的含義。經(jīng)過(guò)這幾天的學(xué)習(xí)真的是受益匪淺,關(guān)于layou方面的知識(shí)將會(huì)不斷更新,敬請(qǐng)期待呦!

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容