NRIネットコム Blog

NRIネットコム社員が様々な視点で、日々の気づきやナレッジを発信するメディアです

【SwiftUI】UIKitで作成したUIViewControllerやUIViewをSwiftUI側で表示する方法

概要

UIKitで作成したUIViewControllerやUIViewをUIViewControllerRepresentableやUIViewRepresentableを使用してSwiftUI側で表示する方法をご紹介します。

環境

この記事は以下のバージョン環境のもと作成されたものです。
【Xcode】14.0.1
【iOS】16.0.2
【macOS】Monterey バージョン 12.5

UIViewControllerRepresentableとUIViewRepresentable

UIViewControllerRepresentableについてのドキュメントは以下です。
https://developer.apple.com/documentation/swiftui/uiviewcontrollerrepresentable
UIViewRepresentableについてのドキュメントは以下です。
https://developer.apple.com/documentation/swiftui/uiviewrepresentable
簡単に説明すると

  • UIViewControllerRepresentableはUIViewControllerをSwiftUIで使用する時に使用
  • UIViewRepresentableはUIViewをSwiftUIで使用する時に使用

となりますので適時使い分けていただければと思います。
また今回はUIViewControllerRepresentableを主にサンプルで使用して解説していきますが、基本的には同じように使用できるのでUIViewRepresentableを使用したい方は読み換えていただければ幸いです。

UIKit側の実装

まずサンプルの画面としてUIKitで以下作成します。

class MyViewController: UIViewController {
    override func viewDidLoad() {
        super.viewDidLoad()
        addMyLabel()
        addMySecondLabel()
    }

    lazy var myLabel: UILabel = {
        let label:UILabel = UILabel()
        label.frame = CGRect(x: 0, y: 0, width: 200, height: 50)
        label.text = "Open VC"
        label.textColor = .black
        return label
    }()

    private func addMyLabel() {
        myLabel.translatesAutoresizingMaskIntoConstraints = false
        view.addSubview(myLabel)
        NSLayoutConstraint.activate([
        myLabel.centerXAnchor.constraint(equalTo: view.centerXAnchor),
        myLabel.topAnchor.constraint(equalTo: view.topAnchor, constant: 100)
        ])
    }

    lazy var mySecondLabel: UILabel = {
        let label:UILabel = UILabel()
        label.frame = CGRect(x: 0, y: 0, width: 200, height: 50)
        label.text = "この画面はUIViewControllerによって生成されています"
        label.font = .systemFont(ofSize: 14)
        label.textColor = .black
        return label
    }()

    private func addMySecondLabel() {
        mySecondLabel.translatesAutoresizingMaskIntoConstraints = false
        myLabel.addSubview(mySecondLabel)
        NSLayoutConstraint.activate([
        mySecondLabel.topAnchor.constraint(equalTo: myLabel.bottomAnchor, constant: 10),
        mySecondLabel.centerXAnchor.constraint(equalTo: view.centerXAnchor),
        ])
    }
}

上記のようにStoryboardを使用せずレイアウトを設定する方法については別の記事で解説を行っていますのでそちらを参照ください。

tech.nri-net.com

今回はこの画面をSwiftUI側から呼び出して表示させます。

SwiftUI側の実装

今回はfullScreenCoverを使用してSwiftUI側のViewからUIKit側のViewControllerを呼び出します。
まず以下のようなViewを作成します。

struct MySwiftUIView: View {
    @State private var showVC = false
    var body: some View {
        VStack {
            Button {
                showVC = true
            } label: {
                Text("VCを開く")
            }
        }
        .fullScreenCover(isPresented: $showVC) {
            NavigationStack {
                Text("ここにVCの画面を表示させたい")
                    .toolbar {
                        ToolbarItem(placement: .navigationBarLeading) {
                            Button(
                                action: {
                                    showVC = false
                                }, label: {
                                    Image(systemName: "xmark")
                                }
                            ).tint(Color.gray)
                        }
                    }
            }
        }
    }
}

UIViewControllerRepresentableを使用して呼び出す

UIViewControllerRepresentableを使用して上記で作成したMyViewControllerをSwiftUIで使用できるように変換していきます。

struct MyViewControllerRepresentable : UIViewControllerRepresentable {
    func makeUIViewController(context: Context) -> MyViewController {
        return MyViewController()
    }
    //SwiftUI → UIkit
    func updateUIViewController(_ uiViewController: MyViewController, context: Context) {

    }
    //UIKit → SwiftUI
    func makeCoordinator() -> Coordinator {
        Coordinator()
    }

    class Coordinator {

    }
}

SwiftUI側で呼び出す事ができます。
Text("ここにVCの画面を表示させたい")の部分をMyViewControllerRepresentable()に置き換えます。

今回は使用しませんでしたが、updateUIViewControllerではSwiftUIからの更新でViewControllerの状態を更新し、makeCoordinatorではViewControllerからSwiftUIに変更を伝えるために使用します。
以下それぞれドキュメントのリンク貼っておくので興味のある方は参照ください。
updateUIViewController:https://developer.apple.com/documentation/swiftui/uiviewcontrollerrepresentable/updateuiviewcontroller(_:context:)
makeCoordinator:https://developer.apple.com/documentation/swiftui/uiviewcontrollerrepresentable/makecoordinator()-32trb

まとめ

以上UIKitで作成したUIViewControllerやUIViewをUIViewControllerRepresentableやUIViewRepresentableを使用してSwiftUI側で表示する方法でした。

執筆者岡優志

iOSエンジニア
iOSを専門とし、モバイルアプリの開発を行なっています。

Twitter