PDFPageOverlayViewProviderを利用したコードにif文を使いたい

ごめんなさい。
前回の回答は不十分な内容だったみたいです。
(UIViewRepresentableは久しぶりだったので、色々忘れてしまいました・・)

OverlayCoordinatorクラスのpageToViewMapping配列が「if文」を作成すると消えてしまうようです。

SwiftUIのビューの仕組みを説明できるほど詳しくないのですが、
OverlayCoordinatorのinitが毎回動いて
pageToViewMappingが初期化されているようですね。
下のようなコードを入れてみたりすると、自分でどこに原因があるか見つけられるかもしれません。

swift

1class OverlayCoordinator : NSObject,PDFPageOverlayViewProvider {2 override init() {3 super.init()4 print("init")5 }6 // 省略7}

UIViewRepresentableを使った場合の補足説明は下に引用しておきます。

しかし、このようにstruct内にclassを保持させてやればもっとシンプルにできちゃうのになぜこんな仕組みが用意されているのでしょう?
それはSwiftUIがUIKitのようなclassベースではなくstructベースで、描画されるたびに破棄されて生成されるからです。
structにclassを保持させるパターンだと描画される度にcoordinatorも再生成されます。 makeUIViewの時点でdelegateに渡しているcoordinatorは再描画時には破棄されるので、このコードは再描画されるとdelegateは呼ばれなくなります。
UIViewRepresentableではmakeCoordinatorで生成されたCoordinatorはstructが再描画されても同じCoordinatorが参照できるような仕組みが用意されているわけです。

UIViewRepresentableのCoordinatorはなぜ必要か - The Pragmatic Ball boy

これらを踏まえて、コードを修正しました。

swift

1import SwiftUI2import PDFKit3import PencilKit4 5struct PDFUIView: View {6 @State private var isPen = true7 var body: some View {8 VStack {9 HStack{10 Button(action: {11 isPen = true12 }, label: {13 Text("ペン")14 })15 Button(action: {16 isPen = false17 }, label: {18 Text("消しゴム")19 })20 //↓問題のコード21 if isPen {22 } else {23 }24 //↑問題のコード25 }26 pdfView(isPen: $isPen)27 }28 }29}30 31struct pdfView : UIViewRepresentable {32 typealias UIViewType = PDFView33 @Binding var isPen: Bool34// let overlayProvider = OverlayCoordinator() // 削除35 func makeUIView(context: Context) -> PDFView {36 let pdfView: PDFView = PDFView()37 if let url = Bundle.main.url(forResource: "example2", withExtension: "pdf") {38 pdfView.pageOverlayViewProvider = context.coordinator // 変更39 pdfView.document = PDFDocument(url: url)40 pdfView.autoScales = true41 pdfView.isInMarkupMode = true42 }43 return pdfView 44 }45 func updateUIView(_ uiView: PDFView, context: Context) {46 if isPen {47 context.coordinator.setPen() // 変更48 } else {49 context.coordinator.setEraser() // 変更50 }51 }52 // 追加↓53 func makeCoordinator() -> OverlayCoordinator {54 return OverlayCoordinator()55 }56 // 追加↑57}58 59class OverlayCoordinator: NSObject, PDFPageOverlayViewProvider {60 var pageToViewMapping = [PDFPage: PKCanvasView]()61 func pdfView(_ view: PDFView, overlayViewFor page: PDFPage) -> UIView? {62 var resultView:PKCanvasView? = nil63 if let overlayView = pageToViewMapping[page] {64 resultView = overlayView 65 } else {66 let canvasView = PKCanvasView()67 canvasView.drawingPolicy = .anyInput 68 canvasView.tool = PKInkingTool(.pen, width: 1)69 canvasView.backgroundColor = .clear 70 pageToViewMapping[page] = canvasView 71 resultView = canvasView 72 }73 return resultView 74 }75 func setPen() {76 for i in pageToViewMapping {77 i.value.tool = PKInkingTool(.pen, width: 1)78 }79 }80 func setEraser() {81 for i in pageToViewMapping {82 i.value.tool = PKEraserTool(.bitmap)83 }84 }85}

SwiftUIのTutorialsにもmakeCoordinator()を使うことが記載されていましたね・・

Section 4
Add a custom page control
Step 3
Create a nested Coordinator type in PageControl, and add a makeCoordinator() method to create and return a new coordinator.

Interfacing with UIKit — SwiftUI Tutorials | Apple Developer Documentation

コメントを投稿

0 コメント