SwiftとSwiftUIを連動する
公開日: 2024-10-13 11:10:29
更新日: 2024-10-13 11:24:04
この記事では、Swiftで作成されたプロジェクトにおいて、SwiftUIを使って特定の画面を表示し、その中でさらにSwiftで実装されたUITableViewを表示するというプロセスを整理しています。この手法は、従来のSwiftベースのプロジェクトにおける最新のiOS機能への対応を視野に入れたものであり、SwiftUIの新機能を取り入れる際に役立ちます。
背景
iOSの新機能は、今後主にSwiftUIを介して提供されることが増えており、Swiftで作成されたプロジェクトでも特定の画面や機能をSwiftUIで実装する必要が出てきます。今回の記事は、以下の流れを解説しています。
1 ViewControllerを起動(従来のSwiftプロジェクトとしての初期設定)。
2 SwiftUIを読み込む:UIHostingControllerを使い、SwiftUIのビューをUIKitベースのプロジェクトに統合。
3 SwiftUIの中でSwiftのTableViewを表示:Swiftで作成されたUITableViewをSwiftUIを通して表示。
実装の流れ
1 ViewController で UIHostingController を使用して、SwiftUIのビューを組み込みます。これは、従来のUIKitベースのプロジェクトにSwiftUIの要素を追加するための接続点となります。
2 SwiftUI内でUIViewControllerをラップ:UIViewControllerRepresentable を使って、Swiftで作成されたUITableViewをSwiftUI内で表示する。
3 Swiftで作成されたTableViewの表示:データを縦に表示するUITableViewを作成し、SwiftUI内でレンダリング。
新機能への対応
iOSの新機能の多くはSwiftUIでしかサポートされないケースが増えており、既存のSwiftプロジェクトにSwiftUIを導入することで最新機能に対応できるようになります。これにより、既存のコードベースを全てSwiftUIに置き換えなくても、部分的にSwiftUIを取り入れることができるため、開発コストを抑えながら最新技術を活用することが可能です。
結論
この記事では、SwiftベースのプロジェクトにSwiftUIを組み込む方法と、その中でSwiftで作成したUITableViewを表示する方法を解説しました。これは、将来的にiOSアプリケーションがSwiftUI中心に移行していく中で、Swiftで作成されたプロジェクトを継続的に活用しながら最新の機能を取り入れるための重要なテクニックです。
このように、Swiftで作成された既存のプロジェクトでも、部分的にSwiftUIを導入することで、最新の機能を活用しつつ、既存のコードベースを維持することができるのは大きなメリットです。
AppDelegate.swift
import UIKit
@main
class AppDelegate: UIResponder, UIApplicationDelegate {
var window: UIWindow?
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
// ViewControllerをルートビューコントローラとして設定
let viewController = ViewController()
window = UIWindow(frame: UIScreen.main.bounds)
window?.rootViewController = viewController
window?.makeKeyAndVisible()
return true
}
}
ViewController.swift
import UIKit
import SwiftUI
class ViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
// SwiftUIのViewを読み込む
let swiftUIView = TestSwiftUI()
// UIHostingControllerを使ってSwiftUIのビューを表示
let hostingController = UIHostingController(rootView: swiftUIView)
// HostingControllerを子ビューコントローラとして追加
addChild(hostingController)
hostingController.view.translatesAutoresizingMaskIntoConstraints = false
view.addSubview(hostingController.view)
// HostingControllerのビューに制約を設定
NSLayoutConstraint.activate([
hostingController.view.topAnchor.constraint(equalTo: view.topAnchor),
hostingController.view.bottomAnchor.constraint(equalTo: view.bottomAnchor),
hostingController.view.leadingAnchor.constraint(equalTo: view.leadingAnchor),
hostingController.view.trailingAnchor.constraint(equalTo: view.trailingAnchor)
])
hostingController.didMove(toParent: self)
}
}
TestSwiftTableView.swift Cellと内容
import UIKit
struct UserData {
let userID: String
let userName: String
let subject: String
let message: String
}
class TestSwiftTableView: UIViewController, UITableViewDelegate, UITableViewDataSource {
let tableView = UITableView()
let userDataList: [UserData] = [
UserData(userID: "1", userName: "John Doe", subject: "Subject 1", message: "This is the first message."),
UserData(userID: "2", userName: "Jane Smith", subject: "Subject 2", message: "This is the second message."),
UserData(userID: "3", userName: "Tom Brown", subject: "Subject 3", message: "This is the third message."),
UserData(userID: "4", userName: "Alice Green", subject: "Subject 4", message: "This is the fourth message."),
UserData(userID: "5", userName: "Bob White", subject: "Subject 5", message: "This is the fifth message.")
]
override func viewDidLoad() {
super.viewDidLoad()
// テーブルビューの設定
tableView.delegate = self
tableView.dataSource = self
tableView.register(UITableViewCell.self, forCellReuseIdentifier: "UserCell")
tableView.translatesAutoresizingMaskIntoConstraints = false
view.addSubview(tableView)
// テーブルビューの制約
NSLayoutConstraint.activate([
tableView.topAnchor.constraint(equalTo: view.topAnchor),
tableView.bottomAnchor.constraint(equalTo: view.bottomAnchor),
tableView.leadingAnchor.constraint(equalTo: view.leadingAnchor),
tableView.trailingAnchor.constraint(equalTo: view.trailingAnchor)
])
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return userDataList.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "UserCell", for: indexPath)
let userData = userDataList[indexPath.row]
cell.textLabel?.text = "UserID: \(userData.userID)\nUserName: \(userData.userName)\nSubject: \(userData.subject)\nMessage: \(userData.message)"
cell.textLabel?.numberOfLines = 0
return cell
}
}
TestSwiftTableViewRepresentable.swift SwiftUIとUIKitを接続するための橋渡し
import SwiftUI
struct TestSwiftTableViewRepresentable: UIViewControllerRepresentable {
func makeUIViewController(context: Context) -> TestSwiftTableView {
return TestSwiftTableView()
}
func updateUIViewController(_ uiViewController: TestSwiftTableView, context: Context) {
// 必要に応じて更新処理を実行
}
}
TestSwiftTableViewRepresentable は、SwiftUI と UIKit を接続するためのブリッジ(橋渡し)として機能するコンポーネントです。具体的には、UIViewControllerRepresentable プロトコルを使用して、Swiftで作成された UIViewController(ここでは TestSwiftTableView)を SwiftUI のビューとして表示できるようにします。
TestSwiftUI.swift 表示用のView (SwiftUI)
import SwiftUI
struct TestSwiftUI: View {
var body: some View {
VStack {
Text("Test SwiftUI with TableView")
.font(.largeTitle)
.padding()
TestSwiftTableViewRepresentable() // SwiftUI内にUITableViewを表示
.edgesIgnoringSafeArea(.all)
}
}
}全体の流れ
1. アプリ起動時: AppDelegateからViewControllerが呼ばれます。
2. ViewController: UIHostingControllerを使ってTestSwiftUI(SwiftUIのビュー)を表示します。
3. TestSwiftUI: TestSwiftTableViewRepresentableを使い、SwiftUI内でTestSwiftTableView(Swiftで書かれたUITableView)を表示します。
これにより、最初にViewControllerが呼び出され、そこでSwiftUIのビューを表示し、その中でSwiftで書かれたUITableViewが表示される流れになります。
実行結果