セクション 104
カスタムページコントロールの追加
今や、SwiftUIUIViewRepresentable ビューに包み込まれたカスタム UIPageControl をビューに追加する準備が整いました。
ステップ 1
PageControl.swift という名前の新しい SwiftUI ビューファイルを作成します。UIViewRepresentable プロトコルに準拠するように PageControl の型を更新します。
UIViewRepresentable の型と UIViewControllerRepresentable の型の寿命は同じで、メソッドは基になる UIKit の型に対応しています。
    PageControl.swift
- import SwiftUI
- import UIKit
- struct PageControl: UIViewRepresentable {
var numberOfPages: Int
@Binding var currentPage: Int
func makeUIView(context: Context) -> UIPageControl {
let control = UIPageControl()
control.numberOfPages = numberOfPages
return control
}
func updateUIView(_ uiView: UIPageControl, context: Context) {
uiView.currentPage = currentPage
}
- }
ステップ 2
テキストボックスをページコントロールに置き換え、レイアウトを VStack から ZStack に切り替えます。
ページ数と現在のページへの結束を渡しているため、ページコントロールにはすでに正しい値が表示されています。
    PageView.swift
- import SwiftUI
- struct PageView<Page: View>: View {
var pages: [Page]
@State private var currentPage = 0
var body: some View {
ZStack(alignment: .bottomTrailing) {
PageViewController(pages: pages, currentPage: $currentPage)
PageControl(numberOfPages: pages.count, currentPage: $currentPage)
.frame(width: CGFloat(pages.count * 18))
.padding(.trailing)
}
}
- }
- struct PageView_Previews: PreviewProvider {
static var previews: some View {
PageView(pages: ModelData().features.map { FeatureCard(landmark: $0) })
.aspectRatio(3 / 2, contentMode: .fit)
}
- }
プレビューその 1
次に、ページコントロールをインタラクティブにして、ユーザが片側または反対側をタップしてページ間を移動できるようにします。
ステップ 3
PageControl 内で入れ子にされた Cordinator の型を作成し、makeCoordinator() メソッドを追加して、新しいコーディネータを作成して返します。
UIPageControl のような UIControl サブクラスはデリゲートの代わりにターゲットアクションパターンを使用するため、この Coordinator は @objc メソッドを実装して現在のページの結束を更新します。
    PageControl.swift
@Binding var currentPage: Int
func makeCoordinator() -> Coordinator {
Coordinator(self)
}
func makeUIView(context: Context) -> UIPageControl {
let control = UIPageControl()
uiView.currentPage = currentPage
}
class Coordinator: NSObject {
var control: PageControl
init(_ control: PageControl) {
self.control = control
}
@objc
func updateCurrentPage(sender: UIPageControl) {
control.currentPage = sender.currentPage
}
}
- }
ステップ 4
実行するアクションとして updateCurrentPage(sender:)) メソッドを指定して、valueChanged イベントのターゲットとしてコーディネータを追加します。
    PageControl.swift
let control = UIPageControl()
control.numberOfPages = numberOfPages
control.addTarget(
context.coordinator,
action: #selector(Coordinator.updateCurrentPage(sender:)),
for: .valueChanged)
return control
プログラム全体 その 1
ステップ 5
最後に、CategoryHome 内で、プレースホルダの特徴のある画像を新しいページビューに置き換えます。
    CategoryHome.swift
- import SwiftUI
- struct CategoryHome: View {
@EnvironmentObject var modelData: ModelData
@State private var showingProfile = false
var body: some View {
NavigationView {
List {
PageView(pages: modelData.features.map { FeatureCard(landmark: $0) })
.aspectRatio(3 / 2, contentMode: .fit)
.listRowInsets(EdgeInsets())
ForEach(modelData.categories.keys.sorted(), id: \.self) { key in
CategoryRow(categoryName: key, items: modelData.categories[key]!)
}
.listRowInsets(EdgeInsets())
}
.listStyle(InsetListStyle())
.navigationTitle("Featured")
.toolbar {
Button(action: { showingProfile.toggle() }) {
Image(systemName: "person.crop.circle")
.accessibilityLabel("User Profile")
}
}
.sheet(isPresented: $showingProfile) {
ProfileHost()
.environmentObject(modelData)
}
}
}
- }
- struct CategoryHome_Previews: PreviewProvider {
static var previews: some View {
CategoryHome()
.environmentObject(ModelData())
}
- }
プレビューその 2
ステップ 6
さあ、さまざまな作用をすべて試してみましょう。PageView は、UIKit と SwiftUI のビューとコントローラがどのように連携するかを示します。
あなたの理解度をチェックしてください
質問 1
UIKit ビューコントローラを SwiftUI にブリッジするためにどのプロトコルを使用しますか?
(訳注: 原典と異なり、選択肢を選ぶとすぐ答えが表示されます)
質問 2
UIViewControllerRepresentable 型のデリゲートまたはデータソースを作成するのはどのメソッド内ですか?
次
watchOS アプリの作成
このチュートリアルでは、SwiftUI についてすでに学んだことの多くを適用し、わずかな努力で Landmarks アプリを watchOS に移行する機会を提供します。