en

hi, it seems you are using microsoft internet explorer. it doesn't match web standard and causes problems browsing this site. please please please use mozilla firefox or google chrome instead. thank you!

zh

哦哦!您正在使用Internet Explorer 瀏覽器,它與我們的網頁標準並不相容,可能會導致畫面顯示不正常。
請改用 Mozilla Firefox 或者 Google Chrome 才能正常瀏覽本網站,謝謝!

10.25.2013

Auto Layout

  

Auto Layout 使用者介面自動佈局的功能很早就被廣泛運用,像是在設計網頁時為了應付不同解析度的視窗,多半都會使用相對位置取代絕對位置來佈局,Auto Layout 也有異曲同工之妙,但是它總是讓人又愛又恨,它的好處是在眾多不同解析的 iOS 裝置下,不管你的畫面是直的還是橫的,介面上的物件總是可以找到自己的位置,但討厭的是,Auto Layout 設定起來相當複雜與瑣碎,儘管如此,官方還是強烈建議應用程式都能支援 Auto Layout 的功能,尤其是那些發佈於不同 iOS 裝置平台的應用程式。

若您的應用程式想要使用 Auto Layout 使用者介面自動佈局的功能,可以從以下兩種方法來著手「使用 Storyboard 的 Auto Layout 功能」「使用 NSLayoutConstraint 動態產生 Auto Layout 的效果」,每一個 Auto Layout 的效果都半隨著一個 Constraint 限制,例如,某個 UIView 必須保持與畫面底部差距 20 個單位的高度,這 20 個單位高度就是 Auto Layout 所給予某 UIView 的限制,你會在下面看到更多相關的說明 ,有關其他 Auto Layout 的說明細節請參考官方的 Auto Layout Guide 文件。


Storyboard 的 Auto Layout 功能
在 Xcode 4.5 版本的情況中,使用 Storyboard 對介面進行佈局就會自動啟用 Auto Layout 效果,你會發現物件在畫面的位置不是絕對的, 物件的屬性內也多了幾個 Constraints 圖示,這導致與多使用者在取用或是設置物件位置的相關屬性時造成錯誤。
Constraints 限制圖示


好在,這個問題在 iOS 7 SDK 隨帶版本的 Xcode 5 得到了改善,雖然說在 Show the File Inspector 檢視器分頁中 Auto Layout 仍然屬於自動啟用狀態,但是對於每個物件要使用 Auto Layout 的功能則需要個別設定,你可以在畫面右下角找到這些設定工具。

Storyboard 畫面右下角的 Auto Layout 工具


NSLayoutConstraint 動態產生 Auto Layout 的效果
使用 NSLayoutConstraint 動態產生 Auto Layout 的效果 又可以分成兩個部分來說明,一個是使用傳統的方式替每一個物件與他的對應限制做設定,這過程相當瑣碎,而另一個則是使用較為視覺化的方式來做設定,利用文字來表示介面上的物件,減少程式碼的撰寫,但是卻相對複雜。

[NSLayoutConstraint  constraintWithItem: attribute: relatedBy: toItem: attribute: multiplier: constant:]
這是使用傳統的的方式對每一個物件的限制就加以設定,可以看到輸入的參數非常的多,而且一次只能設定一項限制。
  • constraintWithItem: attribute:
代表被限制的物件本身與被限制的屬性。
  • relatedBy:
被限制物件的屬性與它參考目標之間的關係 NSLayoutRelationLessThanOrEqual、NSLayoutRelationEqual 或是 NSLayoutRelationGreaterThanOrEqual(小於等於、等於或是大於等於)。
  •  toItem: attribute:
參考目標本身與參考的屬性
  • multiplier: constant:
倍率與偏差值,按照 NSLayoutConstraint.h 文件內的說法他們的關係為 view1.attr1 = view2.attr2 * multiplier + constant。

    下面範例如開頭圖片所示,我們給予 demoLogo 一些限制,讓它始終保持 210x20 的大小、水平置中,並且與底部保留至少 50 個像素高度
    //DEMO LOGO
    UIImageView *demoLogo = [[UIImageView alloc]initWithImage:[UIImage imageNamed:@"DEMO LOGO.png"]];
    [demoLogo setAlpha:0.88];
    [self.view addSubview:demoLogo];
    [demoLogo setTranslatesAutoresizingMaskIntoConstraints:NO];

    //與superview的底部始終差距50個單位高度(不能小於)
    NSLayoutConstraint *myConstraint;
    myConstraint = [NSLayoutConstraint constraintWithItem:demoLogo attribute:NSLayoutAttributeBottom
                    relatedBy:NSLayoutRelationGreaterThanOrEqual
                    toItem:[demoLogo superview] attribute:NSLayoutAttributeBottom
                    multiplier:1.0f constant:-50.0f];
    [self.view addConstraint:myConstraint];

    //x軸對齊superview的x軸中心點
    myConstraint = [NSLayoutConstraint constraintWithItem:demoLogo attribute:NSLayoutAttributeCenterX
                    relatedBy:NSLayoutRelationEqual
                    toItem:[demoLogo superview] attribute:NSLayoutAttributeCenterX
                    multiplier:1.0f constant:-0.0f];
    [self.view addConstraint:myConstraint];

    //寬度限制
    myConstraint = [NSLayoutConstraint constraintWithItem:demoLogo attribute:NSLayoutAttributeWidth
                    relatedBy:NSLayoutRelationEqual
                    toItem:nil attribute:NSLayoutAttributeNotAnAttribute
                    multiplier:1.0f constant:210.0f];
    [self.view addConstraint:myConstraint];

    //高度限制
    myConstraint = [NSLayoutConstraint constraintWithItem:demoLogo attribute:NSLayoutAttributeHeight
                    relatedBy:NSLayoutRelationEqual
                    toItem:nil attribute:NSLayoutAttributeNotAnAttribute
                    multiplier:1.0f constant:20.0f];
    [self.view addConstraint:myConstraint];

    [NSLayoutConstraint constraintsWithVisualFormat: options: metrics: views:]
    由於傳統的方式過於瑣碎,因此 NSLayoutConstraint 也提供另一種較為直覺的方式來設定這些限制,參考下面範例,我們將繪製兩個 UIView 來擋住我們的 demoLogo,並且給予這兩個 UIView 一些限制。
    UIView *ViewA = [[UIView alloc]init];
    ViewA.backgroundColor = [UIColor orangeColor];
    [ViewA setTranslatesAutoresizingMaskIntoConstraints:NO];
    [self.view addSubview:ViewA];

    UIView *ViewB = [[UIView alloc]init];
    ViewB.backgroundColor = [UIColor blueColor];
    [ViewB setTranslatesAutoresizingMaskIntoConstraints:NO];
    [self.view addSubview:ViewB];


    NSMutableArray *myConstraints = [NSMutableArray array];

    //從水平方向佈局
    [myConstraints addObjectsFromArray:
        [NSLayoutConstraint constraintsWithVisualFormat:@"H:|-20-[ViewA(100)]-10-[ViewB(>=100)]-|"
            options:NSLayoutFormatDirectionLeadingToTrailing
            metrics:nil
            views:NSDictionaryOfVariableBindings(ViewA,ViewB)]];


    //從垂直方向佈局
    [myConstraints addObjectsFromArray:
        [NSLayoutConstraint constraintsWithVisualFormat:@"V:[ViewA(100)]-|"
            options:NSLayoutFormatDirectionLeadingToTrailing
            metrics:nil
            views:NSDictionaryOfVariableBindings(ViewA)]];

    //從垂直方向佈局
    [myConstraints addObjectsFromArray:
        [NSLayoutConstraint constraintsWithVisualFormat:@"V:[ViewB(ViewA)]-|"
            options:NSLayoutFormatDirectionLeadingToTrailing
            metrics:nil
            views:NSDictionaryOfVariableBindings(ViewB,ViewA)]];

    [self.view addConstraints:myConstraints];

     

    在上述的程式碼中,我們把所有限制分成從水平與垂直兩方面來看,它門可以分別設定物件的寬度與高度,以及他們在水平垂直面上的限制,下面是視覺化文字背後的語意。

    • " V: " 和 " H: "
    分別代表由垂直或是水平方向來佈局。
    • " | "
    代表 Superview 的邊界。
    • " - "
    代表預設寬度或高度,如果在中間加上數字 " -20- ",則代表限制 20 個單位高度或寬度。
    • " [ ] "
    代表物件本身,括號內包含物件的變數名稱與大小限制,可以使用關係運算子(<=、>= 或 == 等)。
    • " @ "
    優先權,1 至 1000 的整數,優先權較大的條件會優先被滿足,例如 ,[ViewB(>=100@1000)],物件 ViewB 不可以小於 100 個單位長度或寬度會最優先被考慮。

    現在,我們來看看上述程式碼中所代表的語意。
    //從水平方向佈局,由畫面左側開始,間距20個單位寬度,設定100單位寬度的ViewA,間隔10個單位寬度後,再設置單位寬度不能小於100的ViewB,最右側則與畫面間據一個預設距離
    @"H:|-20-[ViewA(100)]-10-[ViewB(>=100)]-|"

    //從垂直方向佈局,設定,ViewA為100個單位高度,並且與畫面底部間格一個預設距離
    @"V:[ViewA(100)]-|"

    //從垂直方向佈局,ViewB的高度與ViewA相同,並且與畫面底部間格一個預設距離
    @"V:[ViewB(ViewA)]-|"


    ps:NSLayoutFormatDirectionLeadingToTrailing,為佈局時的順序,預設是由上而下(垂直)與由左而右(水平),你也可以使用 NSLayoutFormatDirectionLeftToRight 與 NSLayoutFormatDirectionRightToLeft 兩個參數,來改變它的預設順序。






    4 則留言:

    1. 感謝你如此詳細的教學!Auto Layout在未來一定要使用!

      回覆刪除
      回覆
      1. cg2010studio:
        謝謝您

        刪除
    2. 不好意思!我是ios的初學,想問一下Auto Layout在什麼時候會使用到啊?另外骨我沒有對旋轉做任何設定,APP的畫面會隨著使用者旋轉螢幕而跟著改變嗎?

      回覆刪除
    3. 您好:
      Auto Layout 你可以想成是動布局,他不是使用絕對座標來設定,當設定Auto Layout之後,畫面在任何情況下,所有畫面上的物件都會已相對位置自動排版。

      另外專案沒做旋轉設定的話,就不會旋轉了喔!

      回覆刪除