[Android開發學iOS系列] Auto Layout

[Android開發學iOS系列] Auto Layout內容:

  • 介紹什么是Auto Layout.
  • 基本使用方法
    • 在代碼中寫約束的方法
  • Auto Layout的原理
  • 尺寸和優先級
  • Auto Layout的使用細則
    • 重要的屬性
    • StackView
    • Layout Guide
  • Performance
  • Debugging
What is Auto LayoutAuto Layout會根據constraints(約束)動態計算出view hierarchy中所有View的位置和大小.
對于Android開發者來說, Auto Layout很容易上手, 它非常像ConstraintLayoutRelativeLayout: 給View規定它上下左右和誰對齊, 決定UI的位置和大小.
Auto Layout的約束更寬泛一些, 不僅僅是兩個View之間的關系, 還有寬高, 比率等設置, 并且可以有一些大于小于等的范圍設置.
Auto Layout不是一個View開始學Auto Layout我還以為它是一個叫AutoLayout的View, 把其他子View包進去然后設置一些放置規則, 就類似于Android的ConstraintLayout或者RelativeLayout.
但是其實不是, AutoLayout不是一個具體的View, 它代表的是一種計算引擎. 因為在代碼里你從來不需要寫AutoLayout這個關鍵字, 寫的從來都是Constraints.
開發者為View設置足夠多的約束, 規定和這個View位置和大小相關的因素, 這個引擎就可以為我們計算出View的位置和大小.
AutoLayout為了解決什么問題不同屏幕適配; 可以合理應對變化的responsive UI.
改變布局有內外兩種因素, 除了屏幕尺寸, 屏幕旋轉, 窗口大小改變等外部因素.
內部因素還包含了內容的動態變化, 國際化的支持, 字體的調整等.
和Auto Layout平行的解決方案是什么擺放UI有三種主要的方法:
  • 在程序里給每個View設置frame.
  • 設置frame, 結合使用autoresizing masks來應對外部變化. (autoresizing mask定義了一個view的frame在它的superview frame變化時應該如何變化.)
  • 使用Auto Layout.
可以看出第二種只是在基于frame的方式上做出了一點改進, 所能應對的也僅僅是外部變化, 有一定的局限性. 所以可以把前兩種歸類為一種.
這也正是Auto Layout出現之前的解決方案, 即基于frame的布局方式.
Auto Layout的思考點不再著眼于view frame, 而是view的relationship.
如何使用Auto Layout寫iOS的UI有多種方式, Auto Layout屬于UIKit, 在寫的時候, 可以用storyboard, 也可以直接在代碼中寫約束.
在storyboard里面有一些好處, 比如所見即所得, 而且ide會給出一些warnings, 比如控件在storyboard上的位置與約束不一致, 會提示, 并且可以選擇方式修復.在storyboard里面寫約束確實是不容易出錯的一種方式, xcode的操作也很直觀, 這里不做演示了.
之前我們也討論過, 用storyboard寫UI存在閱讀性差, 代碼版本管理和團隊合作都有問題等.所以具體使用需要看實際情況.
關于約束, location和size的約束不能混著用, 這個也是從邏輯上就可以理解的.比如讓某個view的top和parent的top對齊(或者再offset個常量)是可以的, 但是讓top等于某個size就不能理解了.
在代碼中創建約束如果不用Interface Builder, 而是選擇在代碼中創建約束, 那么仍然有多種選擇:
  • 使用layout anchor.
  • 使用NSLayoutConstraint類.
  • 使用Visual Format Language.
我們在改變約束的時候通常不會add/remove constraints, 而是active/deactivate.
使用Layout anchor這個方法可能是最直觀的一種方法.
// Get the superview's layoutlet margins = view.layoutMarginsGuide// Pin the leading edge of myView to the margin's leading edgemyView.leadingAnchor.constraint(equalTo: margins.leadingAnchor).isActive = true// Pin the trailing edge of myView to the margin's trailing edgemyView.trailingAnchor.constraint(equalTo: margins.trailingAnchor).isActive = true// Give myView a 1:2 aspect ratiomyView.heightAnchor.constraint(equalTo: myView.widthAnchor, multiplier: 2.0).isActive = true這里我們把每一條約束設置了isActive = true.
也可以直接放在一個數組里一起activate, 會有性能優勢:
NSLayoutConstraint.activate([myView.leadingAnchor.constraint(equalTo: margins.leadingAnchor),myView.trailingAnchor.constraint(equalTo: margins.trailingAnchor),myView.heightAnchor.constraint(equalTo: myView.widthAnchor, multiplier: 2.0)])使用NSLayoutConstraint使用NSLayoutConstraint寫起來比較啰嗦, 必須給每個參數都指定值:
NSLayoutConstraint(item: myView, attribute: .leading, relatedBy: .equal, toItem: view, attribute: .leadingMargin, multiplier: 1.0, constant: 0.0).isActive = trueNSLayoutConstraint(item: myView, attribute: .trailing, relatedBy: .equal, toItem: view, attribute: .trailingMargin, multiplier: 1.0, constant: 0.0).isActive = trueNSLayoutConstraint(item: myView, attribute: .height, relatedBy: .equal, toItem: myView, attribute:.width, multiplier: 2.0, constant:0.0).isActive = true

推薦閱讀