Layout

用程式做 layout 有以下方式

  1. NSLayoutAnchor (iOS 9) -> 如果沒有相容性問題,用這種方式
  2. NSLayoutConstraint (iOS 6)
  3. Visual Format Langue (iOS 6)
  4. third party freamework : SnapKit

Layout Constraint (NSLayoutAnchor)

紅色view.前面 = 1.0 倍 * 藍色view.後面 + 8 個points

紅色的view的前面,緊接在藍色view的後面8個points的位置

反過來說也成立:

藍色的view後面points的位置緊接著紅色的view

下面這個是設定讓 title label跟他的supper view一樣大,滿直覺的寫法跟用Interface Buider拉的效果一致性很高

        let margin = self.layoutMarginsGuide
        
        titleLabel.topAnchor.constraintEqualToAnchor(margin.topAnchor).active = true
        titleLabel.bottomAnchor.constraintEqualToAnchor(margin.bottomAnchor).active = true
        titleLabel.leftAnchor.constraintEqualToAnchor(margin.leftAnchor).active = true
        titleLabel.rightAnchor.constraintEqualToAnchor(margin.rightAnchor).active=true

layout guide and layout margin

content hugging and compression resistance (CHCR) priorities

  • content hugging -> 內容不想被延展時用這個控制, priority越高越不會被延展
  • content compression resistance -> 內容不想被縮小時用這個控制, priority越高越不會被壓縮
|---- supper view (priority = 500) ----|

# hugging priority > 500,button 變成緊實(compact)
[A Button]
# hugging  priority < 500,button 被延展到跟supper view一樣大
[                A Button              ]

# compression resistance priority > 500, 內容沒被壓縮
[A Button]
# compression resistance priority < 500, 內容被壓縮
[A But..]
# content hugging priorities
|-------------|-------------|
  250             250       
[Label]          [Text]     

   251            249       
[Label][Text               ]
   250            251       
[Label               ][Text]

# content compression resistance priorities
        750            750
[      Image      ][ Label ]  # 預設
        750            750
[      Image      ][LongLab]  # label內容過長被壓縮了
        750            751
[    Image    ][ LongLabel ]  # 要求放不下時優先壓縮 Image 大小,而不是Label

Tips

  • 儘可能的用stack view,然後有需時再用 constraint (stackview 的一堆屬性是無效的,ex: backgroundColor)
  • 不要 add/remove constraint,改用 activate / deactivate
  • 絕對不要 deactivate self.view.constraints
  • table view 的 size 可以自動計算,但 constraint 要設好 : see also Mysteries of Auto Layout Part1
  • 加入 layout identity 對 debuging layout 問題很有幫助
  • layout的效果不如預期的原因是 constraints 不足或是 priority 衝突
  • call UIView.hasAmbiguosLayout to diagnosis

Stack View

Aligment

Distribution

Tips

  • 部份元件會自動推算大小(intrinsic size), 所以在設定大小可以不用設定大小的 constraint
  • 儘量用相對與其他 view 的方式決定位置, 然後由元件的 intrinsic size 決定大小
  • 橘色的”I-bar” 表示 constraints 設定把完整,無法計算出 view 的位置及大小,需要再加入其他的 constraint (missing constraints),讓”T-bar”直至成為藍色為止
  • 設定多個 constraints 的方式是按住 constraint 後多選數個 views 加入 constraint
  • 部份元件,在沒有加入任何 constraint 前, layout 不會跑掉是因為 auto layout constraint
  • 先處理 sub view 間的 constraints 關係,讓它 “群組化”後再設定與 super view 會比較容易
  • 如果要設定subview小於super view的一定比例以下,可在subview 與 super view 間拉 Equal Heights ConstraintEqual Widths Constraint, 然後設定 RelationLess Than or Equal (可能需先對調 First Item, Second Item)
  • 先弄出可以適用於所有 devices 的通用 layout, 在針對特定的layout調整, 如果能不用到 size class 就不要用
  • font 的設定是全局的, 一旦設定就會影響到 base layout,如果要為特定的layout 設定專用的font, 必須為該layout新增一特定的font
  • constraint 跟其他的 UI 元件一樣,也是可以透過 @IBOutelet 用程式控制

Resources