Edited at

親ViewにAuto Layoutで上下左右くっつけるProtocol Extension

More than 3 years have passed since last update.


 概要

こちらの記事を読んで、自分が普段やっている方法を晒してみようと思いました。結果自体は同じです。

親ビュー全体に重なる形でViewを乗っける制約を手軽に設定できるようにします。

例えば通信を伴う画面で、初回の通信中や通信失敗で画面を切り替えたいなどに使っています。


実装

例で上げたViewは、あるタイミングでは画面全体を覆いかぶさる形で表示されているという挙動が共通しています。なので、Protocol Extensionに適しているかと思います。

また、先の記事ではVisual Formatを使うと簡単に書けるとコメントがされていましたが、文字列で書くところがあまり好きではないため自分は使っていません。(短くかけるところはすごく魅力的なのですが...)

protocol ViewConstrainable {

// auto layoutを張る・表示非表示を指定する用のメソッド
func overlay(on view: UIView, hidden: Bool)
}

// プロトコルで定義したメソッドをextensionで実装する。
// 型制約でUIViewを継承しているものだけに使えるようにして、
// これに従うクラスへAutolayoutを張れるようにする
extension ViewContrainable where Self: UIView {
func overlay(on view: UIView, hidden: Bool = true) {
translatesAutoresizingMaskIntoConstraints = false
self.hidden = hidden
view.addSubview(self)
let constraints = [.Top, .Bottom, .Leading, .Trailing].map { (attr: NSLayoutAttribute) in
return NSLayoutConstraint(
item: self,
attribute: attr,
relatedBy: .Equal,
toItem: view,
attribute: attr,
multiplier: 1,
constant: 0
)
}
view.addConstraints(constraints)
}
}

// Protocol extensionを持たせる
class LoadingView: UIView, ViewContrainable {
}

// こんな感じで使います。ここでは直接初期化していますが、通常はxibを使っています。
let loadingView = LoadingView()
// 大元のviewcontrollerのviewに対して画面を覆うように貼り付ける
loadingView.overlay(on: self.view)
// 表示非表示はhiddenでコントロールしたほうが安全な気がするのでこうしています
loadingView.hidden = false

以上です。Protocol Extension化することで必要なViewでだけ扱えるようにしたのと、mapでautolayoutのコードを短くしてみました。