セクション 101
UIPageViewController を表すビューを作成
SwiftUI で UIKit ビューとビューコントローラを表すには、UIViewRepresentable および UIViewControllerRepresentable プロトコルに準拠する型を作成して下さい。カスタムの型は、それらが表す UIKit 型を作成および構成し、SwiftUI はそれらのライフサイクルを管理し、必要に応じて更新します。
ステップ 1
プロジェクトの Views フォルダに PageView グループを作成し、PageViewController.swift という名前の新しい Swift ファイルを追加します。 PageViewController 型が UIViewControllerRepresentable に準拠していると宣言します。
ページビューコントローラは、Page インスタンスの配列を格納しますが、これは View の型でなければなりません。これらは、ランドマーク間をスクロールするために使用するページです。
    PageViewController.swift
- import SwiftUI
- import UIKit
- struct PageViewController<Page: View>: UIViewControllerRepresentable {
var pages: [Page]
- }
次に、UIViewControllerRepresentable プロトコルの 2 つの要件を追加します。
ステップ 2
目的とする構成で UIPageViewController を作成する makeUIViewController(context:) メソッドを追加します。
SwiftUI は、ビューを表示する準備ができたときにこのメソッドを 1 回呼び出し、その後ビューコントローラーのライフサイクルを管理します。
    PageViewController.swift
var pages: [Page]
func makeUIViewController(context: Context) -> UIPageViewController {
let pageViewController = UIPageViewController(
transitionStyle: .scroll,
navigationOrientation: .horizontal)
return pageViewController
}
- }
ステップ 3
setViewControllers(_:direction:animated:) を呼び出す updateUIViewController(_:context:) メソッドを追加して、表示用のビューコントローラを提供します。
今のところ、更新のたびに SwiftUI ビューのページをホストする UIHostingController を作成して下さい。後で、ページビューコントローラの寿命中にコントローラを 1 回だけ初期化することで、これをより効率的にできます。
    PageViewController.swift
return pageViewController
}
func updateUIViewController(_ pageViewController: UIPageViewController, context: Context) {
pageViewController.setViewControllers(
[UIHostingController(rootView: pages[0])], direction: .forward, animated: true)
}
- }
続ける前に、ページとして使用する、特徴のあるカードを準備します。
ステップ 4
ダウンロードしたプロジェクトファイルの Resources ディレクトリにある画像をアプリの Asset(アセット) カタログにドラッグします。
ランドマークの特徴のある画像が存在する場合、通常の画像とは異なるサイズになります。
ステップ 5
特徴のある画像が存在する場合は、それを返す Landmark 構造体に計算されたプロパティを追加します。
    Landmark.swift
- import Foundation
- import SwiftUI
- import CoreLocation
- struct Landmark: Hashable, Codable, Identifiable {
var id: Int
var name: String
var park: String
var state: String
var description: String
var isFavorite: Bool
var isFeatured: Bool
var category: Category
enum Category: String, CaseIterable, Codable, Hashable {
case lakes = "Lakes"
case rivers = "Rivers"
case mountains = "Mountains"
}
private var imageName: String
var image: Image {
Image(imageName)
}
var featureImage: Image? {
isFeatured ? Image(imageName + "_feature") : nil
}
private var coordinates: Coordinates
var locationCoordinate: CLLocationCoordinate2D {
CLLocationCoordinate2D(
latitude: coordinates.latitude,
longitude: coordinates.longitude)
}
struct Coordinates: Hashable, Codable {
var latitude: Double
var longitude: Double
}
- }
ステップ 6
ランドマークの特徴ある画像を表示する FeatureCard.swift という名前の新しい SwiftUI ビューファイルを追加します。
    FeatureCard.swift
- import SwiftUI
- struct FeatureCard: View {
var landmark: Landmark
var body: some View {
landmark.featureImage?
.resizable()
.aspectRatio(3 / 2, contentMode: .fit)
}
- }
- struct FeatureCard_Previews: PreviewProvider {
static var previews: some View {
FeatureCard(landmark: ModelData().features[0])
}
- }
プレビューその 1
ステップ 7
ランドマークに関するテキスト情報を画像に重ね合わせます。
    FeatureCard.swift
.resizable()
.aspectRatio(3 / 2, contentMode: .fit)
.overlay(TextOverlay(landmark: landmark))
}
- }
- struct TextOverlay: View {
var landmark:
Landmark
var gradient: LinearGradient {
LinearGradient(
gradient: Gradient(
colors: [Color.black.opacity(0.6), Color.black.opacity(0)]),
startPoint: .bottom,
endPoint: .center)
}
var body: some View {
ZStack(alignment: .bottomLeading) {
Rectangle().fill(gradient)
VStack(alignment: .leading) {
Text(landmark.name)
.font(.title)
.bold()
Text(landmark.park)
}
.padding()
}
.foregroundColor(.white)
}
- }
- struct FeatureCard_Previews: PreviewProvider {
static var previews: some View {
FeatureCard(landmark: ModelData().features[0])
}
- }
プレビューその 2
次に、UIViewControllerRepresentable ビューを表示するカスタムビューを作成します。
ステップ 8
PageView.swift という名前の新しい SwiftUI ビューファイルを作成し、PageView の型を更新して、PageViewController を子ビューとして宣言します。
Xcode が Page の型を推測できないため、プレビューは失敗します。
    PageView.swift
- import SwiftUI
- struct PageView<Page: View>: View {
var pages: [Page]
var body: some View {
PageViewController(pages: pages)
}
- }
- struct PageView_Previews: PreviewProvider {
static var previews: some View {
PageView()
}
- }
ステップ 9
プレビュープロバイダーを更新して、必要なビューの配列を渡すと、プレビューが機能し始めます。
    PageView.swift
- struct PageView_Previews: PreviewProvider {
static var previews: some View {
PageView(pages: ModelData().features.map { FeatureCard(landmark: $0) })
.aspectRatio(3 / 2, contentMode: .fit)
}
- }
プレビューその 3