29
21

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

AutoLayoutの制約の有効/無効化方法4つを比較する

Last updated at Posted at 2019-04-02

コードからAutoLayoutの制約の有効化/無効化を切り替える方法は以下の4つがあります。

  • UIViewadd(remove)Constraint(_:)
  • UIViewadd(remove)Constraints(_:)
  • NSLayoutConstraintisActive
  • NSLayoutConstraint(de)activate(_:)

この4つの方法の違いを解説します。

UIViewadd(remove)Constraint(_:)

この方法は非推奨です!

UIViewのインスタンスメソッドのaddConstraint(_:)removeConstraint(_:)を使う方法です。

以下のように使います。

let widthConstraint = aView.widthAnchor.constraint(equalToConstant: 100)
aView.addConstraint(widthConstraint)

簡単ですね。

では、以下のようなViewの階層を考えてみます。

image1.png

viewBとviewCはviewAのsubviewです。
ここで、「viewBとviewCの横幅が等しい」という制約を加えたいとしましょう。以下にコードを示します。

let widthEqualConstraint = viewB.widthAnchor.constraint(equalTo: viewC.widthAnchor)
viewA.addConstraint(widthEqualConstraint)

上記のコードで注意するべきことは、viewAに対してaddConstraint(_:)を呼んでいることです。
ここで間違えて、viewBやviewCに対して呼んでいたら、クラッシュするか制約が働かなくなります。つまり、

addConstraint(_:)は、制約に関連するviewに共通の親viewのうち最も階層の近いものに対して呼ばないといけません。そうしないと、クラッシュするか制約が効かなくなってしまいます。

先ほどの例だと、viewBとviewCの共通の親であるviewA対して呼ばなければいけません。ここが難しいところです。幸いなことに回避方法はあるので、後ほど紹介します。

removeConstraint(_:)について

removeConstraint(_:)は、制約を解除します。それ以外はaddConstraint(_:)と同じです。

UIViewadd(remove)Constraints(_:)

このメソッドはNSLayoutConstraintの配列を引数にとります。制約を一度に有効化/無効化することができますが、add(remove)Constraint(_:)と同じく適切なviewに対してメソッドを呼ばなければならないという問題は残っています。したがって、このメソッドはおすすめできません。

NSLayoutConstraintのisActive

NSLayoutConstraintのプロパティのisActiveを使います。例を示します。

let widthConstraint = aView.widthAnchor.constraint(equalToConstant: 100)
widthConstraint.isActive = true
// aView.widthAnchor.constraint(equalToConstant: 100).isActive = ture でもOK

ここで再び以下の画像を考えてみます。viewBとviewCはviewAのsubviewです。

image1.png

isActiveを使うとviewBとviewCの横幅が等しい制約を有効化する方法は以下のようになります。

let widthEqualConstraint = viewB.widthAnchor.constraint(equalTo: viewC.widthAnchor)
widthEqualConstraint.isActive = true
viewA.constraints.contains(widthEqualConstraint) // => true

3行目に注目してください。widthEqualConstraintがviewAに所属していることを示しています。このように、isActiveを使うとその制約がどのviewに所属するべきかを自動的に解決してくれます。制約を解除したいときはisActive = falseとしてやればOKです。非常に便利ですね。

NSLayoutConstraint(de)activate(_:)

NSLayoutConstraintのクラスメソッドです。NSLayoutConstraintの配列を引数にとり、制約の有効化/無効化を一度に設定します。
このメソッドも、与えられた制約がどのviewに所属するかを自動的に解決してくれます。

結局どれを使えばいいの?

わかりやすく表にしました。

方法 所属するviewの自動解決
add(remove)Constraint(_:)
add(remove)Constraints(_:)
isActive ⭕️
(de)activate(_:) ⭕️

上の二つは所属するviewの自動解決をしてくれないので使うのをやめましょう。もし間違ったviewに対してメソッドを呼んでしまった時のリスクが大きすぎます。
下の二つなら正直に言ってどちらでも良いのですが、NSLayoutConstraint(de)activate(_:)の方がパフォーマンスの点で有利です。これも表にしてみます。

方法 パフォーマンス
isActive ⭕️
(de)activate(_:) 💯

ドキュメントによると、

Typically, using this method is more efficient than activating each constraint individually.

と書いてあるので、NSLayoutConstraint(de)activate(_:)の方がパフォーマンスが有利だと考えて良いです。
その理由は、WWDC 2014のMysteries of Auto Layout, Part 2の5:20 ~ 5:35で言及されています。一度に複数の制約を有効化/無効化することでレイアウトのライフサイクルが無駄に回らないのが理由のようです。

結論

有効化/無効化したい制約が一つだけならisActiveあるいはNSLayoutConstraints(de)activate(_:)のどちらを使っても良いです。ただし、複数の制約がある場合はNSLayoutConstraints(de)activate(_:)がパフォーマンスの点で有利です。

29
21
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
29
21

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?