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