【UIKit】【AutoLayout】PriorityとisActiveの違いについて


#### はじめに
UIKitでiOSのアプリ開発をしていくなかで必要不可欠な存在であるAuto Layout。
その中でも、制約の`Priority`と`isActive`は、ビューの配置を制御するための重要なプロパティです。  
しかし、この2つの違いを理解して使い分けることは意外と難しいかもしれません。

本記事では、`Priority`と`isActive`の役割と使い方について解説します。

---

#### 1. Auto Layoutにおける制約の基本

Auto Layoutは、ビューの位置やサイズを相対的に定義するためのシステムです。
デバイスのサイズや画面の向きに応じてビューを柔軟に配置することができる優れものです。

- **制約 (Constraints)**： ビューの位置やサイズを定義するルール。画面サイズやデバイスの向きが変わっても、ビューの配置の整合性を保持してくれる
- **制約の優先度 (Priority)**： 制約がどれほど重要かを示す数値（1〜1000）
- **isActiveプロパティ**： 制約が現在有効かどうかを示すBool値

---

#### 2. Priorityの役割

制約の優先度 (`Priority`) は、複数の制約が同時に適用された場合に、どの制約が優先されるかを決定します。  
通常、`Priority`はデフォルトで1000（必須）に設定されていますが、複数の制約が競合する場合には`Priority`を調整することで制約の強さを変更できます。

- **1000 (必須)**： 常に適用される制約。デフォルトで最も高い優先度
- **1〜999 (任意)**： 必要に応じて無視される可能性のある制約

`Priority`の値が1000の場合、その制約は必ず満たされなければならない必須制約となります。それ以下の値では、他の制約に置き換わる可能性のある任意の制約として扱われます。

**例：**`view1`の先頭が`view2`の先頭と一致するように制約を設定し、優先度を999に設定

```swift
let constraint = view1.leadingAnchor.constraint(equalTo: view2.leadingAnchor)
constraint.priority = UILayoutPriority(999) // 優先度を999に設定
```


---

#### 3. isActiveの役割

`isActive`プロパティは、制約が現在有効かどうかを制御します。`isActive = true`で制約が有効になり、`false`で制約が無効になります。  
このプロパティを使うことで、動的に制約を有効化または無効化することが可能です。

- **`true`**： 制約が有効
- **`false`**：制約が無効

`isActive`を動的に切り替えるときは、レイアウト更新が必要です。一般的に、制約の変更が即座に反映されるように`layoutIfNeeded`等のView更新処理を呼び出すことが多いです。

**例**：`view1`の先頭が`view2`の先頭と一致するように制約を設定し、制約を有効にする
```swift
let constraint = view1.leadingAnchor.constraint(equalTo: view2.leadingAnchor)
constraint.isActive = false  // 制約を無効化
view.layoutIfNeeded() // レイアウトを更新
```


---

#### 4. PriorityとisActiveの違い


- **Priority**：制約が競合する際の優先度を示し、制約の「重要度」を設定する 　　
- **isActive**：制約が現在有効かどうかを示し、制約の「有効/無効」を制御する

**補足**
Priorityを使うときに注意することは、**低い優先度の制約が破棄される可能性がある**という点です。
例えば、異なるビューに対して競合する制約を持つ場合、Auto Layoutは低い優先度の制約を無視することがあります。

---

#### 5. 実例で学ぶ: PriorityとisActiveの使い分け

**Priority を使うべき場面**

1. **複数の制約が競合する場合の調整**  
   同じビューに対して複数の制約が存在し、それらが互いに競合する可能性がある場合に、どの制約を優先するかを設定する

  **例：** ビューのサイズを固定したいが、親ビューのサイズが変わる場合にはそのサイズに合わせて伸縮させたい場合
   ```swift
let constraint = view.widthAnchor.constraint(equalToConstant: 100)
constraint.priority = UILayoutPriority(750) // 優先度を750に設定
   ```

　　
2. **レイアウトの優先順位を調整したいとき**  
   一部の制約が他の制約よりも重要である場合に、その制約の優先度を設定して、レイアウトエンジンにどの制約を優先すべきかを指示する

  **例：**  ビューの端にマージンを持たせたいが、画面サイズが小さい場合にはマージンを縮小してでも内容を表示させたい場合

   ```swift
let marginConstraint = view.leadingAnchor.constraint(equalTo: superview.leadingAnchor, constant: 20)
marginConstraint.priority = UILayoutPriority(500) // 優先度を500に設定
   ```
　　
3. **制約の重要度を細かく調整したいとき**  
   ビューのレイアウトを細かく調整するために、制約の優先度を設定して柔軟にレイアウトを制御する

   **例：**  コンテンツの高さや幅を一定範囲内で変動させたい場合

   ```swift
let flexibleHeightConstraint = view.heightAnchor.constraint(equalToConstant: 200)
flexibleHeightConstraint.priority = UILayoutPriority(250) // 優先度を250に設定
   ```
　　

**isActive を使うべき場面**

1. **動的に制約を切り替えたいとき**
ユーザーの操作やアプリの状態に応じて、特定の制約を有効/無効にする必要がある場合
**例：** ボタンをタップしたときにビューの位置やサイズを変更し、特定の条件でビューを表示/非表示を切り替えたい場合

   ```swift
   @objc func toggleView() {
       constraint.isActive.toggle()
       view.layoutIfNeeded()
   }
   ```
   　　
2. **一時的なレイアウト変更が必要なとき**
 一時的にビューの配置を変更したい場合や、アニメーションの間だけ異なるレイアウトを適用したい場合
**例：** メニューを開いた際のコンテンツレイアウトを変更したい場合

   ```swift
   UIView.animate(withDuration: 0.3) {
       self.menuConstraint.isActive = !self.menuConstraint.isActive
       self.view.layoutIfNeeded()
   }
   ```

### 使い分けのポイント

- **Priority：** 制約が有効であるときの重要度を設定する。複数の制約が同時に適用される場合や、柔軟なレイアウトを実現したい場合に使用する
- **isActive：** 制約を完全に有効化/無効化する場合に使用する。ユーザーインターフェースの動的な変更やアニメーションに適している

---

#### まとめ

`Priority`と`isActive`は、それぞれ異なる目的で使用される重要なプロパティです。  
`Priority`を調整することで制約の競合を管理し、`isActive`を使用して制約を動的に有効化または無効化できます。  
プロパティを適切に使い分けることで、柔軟で堅牢なレイアウトを実現していきましょう。

---

#### 参考文献

- [NSLayoutConstraint - Apple Developer Documentation](https://developer.apple.com/documentation/uikit/nslayoutconstraint)
- [UILayoutPriority - Apple Developer Documentation](https://developer.apple.com/documentation/uikit/uilayoutpriority)
-  [layoutIfNeeded() - Apple Developer Documentation](https://developer.apple.com/documentation/uikit/uiview/1622507-layoutifneeded)