UITableViewControllerのtableHeaderViewにSwiftUIコンテンツを挿入する方法


## 概要

iOS開発において、UIKitとSwiftUIを組み合わせて使うケースが増えています。特に、既存のUIKitベースのアプリに新しいUIを導入する際に、SwiftUIのビューを活用することが有効です。本記事では、`UITableViewController`の`tableHeaderView`にSwiftUIのビューを挿入する方法について解説します。

この方法を用いることで、既存のUITableViewに新しいデザインや機能を迅速に統合でき、SwiftUIの宣言的なUI開発の利点を既存のアプリケーションにもたらすことができます。

## メリット

-   **モダンなUIの導入**：SwiftUIを使用することで、モダンなデザインやアニメーションを簡単に導入できます。
-   **柔軟なUI更新**：SwiftUIの宣言的なスタイルにより、コードが簡潔で読みやすく、UIの更新が容易になります。
-   **既存コードの再利用**：UIKitの既存コードと共存させることで、大規模なリファクタリングをせずに新しいUIを追加できます。

## 実装方法

以下に、`UITableViewController`の`tableHeaderView`にSwiftUIのビューを挿入する方法を示します。

### ソースコード

```
override func viewDidLoad() {
    super.viewDidLoad()
    
    let hostingView = createCustomHeaderView()
    tableView.tableHeaderView = hostingView
}

private func createCustomHeaderView() -> UIView {
    // SwiftUI のビューを UIHostingController でラップ
    let swiftUIView = CustomHeaderView()
    let hostingController = UIHostingController(rootView: swiftUIView)

    // Auto Layout を使ってサイズを決めるために必要。falseにしないと制約が効かない
    hostingController.view.translatesAutoresizingMaskIntoConstraints = false

    // hostingController.view をコンテナに追加
    let containerView = UIView()
    containerView.addSubview(hostingController.view)

    // hostingController.view に制約を追加
    NSLayoutConstraint.activate([
        hostingController.view.leadingAnchor.constraint(equalTo: containerView.leadingAnchor),
        hostingController.view.trailingAnchor.constraint(equalTo: containerView.trailingAnchor),
        hostingController.view.topAnchor.constraint(equalTo: containerView.topAnchor),
        hostingController.view.bottomAnchor.constraint(equalTo: containerView.bottomAnchor),
    ])

    // ヘッダーのサイズを決定
    let headerSize = hostingController.view.systemLayoutSizeFitting(UIView.layoutFittingCompressedSize)
    hostingController.view.frame.size = headerSize

    // コンテナビューの高さを SwiftUI ビューに合わせて設定
    containerView.frame.size = headerSize

    return containerView
}
```

### コード解説

#### `viewDidLoad`

`viewDidLoad`は、ビューがメモリに読み込まれた直後に呼び出されるメソッドです。この中で`tableHeaderView`を設定することで、テーブルのヘッダー部分にカスタムビューを表示します。

-   **`createCustomHeaderView()`**：SwiftUIのビューを含む`UIView`を生成します。
-   **`tableView.tableHeaderView = hostingView`**：生成された`UIView`を`tableHeaderView`として設定します。

#### `createCustomHeaderView`

`createCustomHeaderView`は、SwiftUIのビューをUIKitの`UIView`として返すメソッドです。このメソッドでは、SwiftUIのビューを`UIHostingController`でラップし、そのビューをコンテナとなる`UIView`に追加します。

-   **`let swiftUIView = CustomHeaderView()`**：ここで`CustomHeaderView`は、SwiftUIで定義されたビューです。このビューを`UIHostingController`でラップします。
-   **`hostingController.view.translatesAutoresizingMaskIntoConstraints = false`**：`translatesAutoresizingMaskIntoConstraints`を`false`に設定することで、Auto Layoutの制約が正しく適用されるようにします。
-   **`containerView.addSubview(hostingController.view)`**：`UIHostingController`のビューをコンテナビューに追加します。
-   **`NSLayoutConstraint.activate([...])`**：ここで、`hostingController.view`に対してコンテナビューにピッタリ合うように制約を設定します。
-   **`let headerSize = hostingController.view.systemLayoutSizeFitting(UIView.layoutFittingCompressedSize)`**：`UIHostingController`のビューが自動的に最適なサイズを計算するためのメソッドです。
-   **`containerView.frame.size = headerSize`**：コンテナビューのサイズを、SwiftUIのビューのサイズに合わせて設定します。

### まとめ

この方法により、`UITableView`のヘッダーにSwiftUIのビューをスムーズに統合することができます。SwiftUIの柔軟なUI開発の恩恵を受けながら、既存のUIKitアプリにモダンな機能を追加することが可能です。