Xibファイルでレイアウトを定義したUIViewControllerで*LayoutGuideを使う
XIBファイルで開発を進めているけど UIViewController のサブビューが UINavigationBar にめり込んでつらいという話をされたので対策を考えた。
XIBファイルベースで開発するUIViewControllerサブクラスは FromNibViewController のサブクラスとして実装することを前提として。
class FromNibViewController: UIViewController {
// MARK: -- Statics
static var kTopLayoutConstraint: String { return "TopLayoutConstraint" }
static var kBottomLayoutConstraint: String { return "BottomLayoutConstraint" }
// MARK: -- Properties
var topLayoutConstraint: NSLayoutConstraint!
var bottomLayoutConstraint: NSLayoutConstraint!
// MARK: -- View lifecycles
func scanLayoutConstraint() {
for constraint: NSLayoutConstraint in self.view.constraints {
if (constraint.identifier == FromNibViewController.kTopLayoutConstraint) {
self.topLayoutConstraint = constraint
}
else if constraint.identifier == FromNibViewController.kBottomLayoutConstraint {
self.bottomLayoutConstraint = constraint
}
}
}
override func viewDidLoad() {
super.viewDidLoad()
self.scanLayoutConstraint()
}
override func viewWillLayoutSubviews() {
// do something
self.topLayoutConstraint.constant = self.topLayoutGuide.length
self.bottomLayoutConstraint.constant = self.bottomLayoutGuide.length
super.viewWillLayoutSubviews()
}
}
あとはXIBファイル側では、基本的には UIViewController を作成したときの Also create XIB file のままAutoLayoutを指定していく。
最後に TopLayoutGuide と BottomLayoutGuide を当てたい NSLayoutConstraint の Identifier に TopLayoutConstraint と BottomLayoutConstraint を指定してあげる。
元のレイアウトはこんな感じで上下左右余白0

TopのNSLayoutConstraintにIdentifierを設定する

BottomのNSLayoutConstraintにIdentifierを設定する

こうすれば変にイニシャライザをいじったり func loadView() を書く必要もないです。
self.view がピンクで、 subview が青い画面のとき。

余談ですが、この2行を viewWillLayoutSubviews() 以外の、 updateViewConstraints() などで実行するとレイアウトが最適化されていない状態で画面遷移が行われたりするので気をつけて下さい。
self.topLayoutConstraint.constant = self.topLayoutGuide.length
self.bottomLayoutConstraint.constant = self.bottomLayoutGuide.length