質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.46%
PDF

PDF(Portable Document Format)とはISOによって国際標準として制定されている電子ドキュメント用の拡張子です。

Q&A

解決済

1回答

79閲覧

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

Gameno

総合スコア10

PDF

PDF(Portable Document Format)とはISOによって国際標準として制定されている電子ドキュメント用の拡張子です。

0グッド

0クリップ

投稿2024/04/29 03:54

実現したいこと

以前こちらでPDFPageOverlayViewProviderのPKTool変更を解決していただきました。
以前の内容
そのコードを使い、if文を利用してbuttonなどの装飾を行いたいのですが、なぜか出来ません。
何がダメなのかも解らず困っています。

発生している問題・分からないこと

buttonやview内に「if文」を入れると、OverlayCoordinatorクラスのsetPen()やsetEraser()が使えなくなってしまいます。
OverlayCoordinatorクラスのpageToViewMapping配列が「if文」を作成すると消えてしまうようです。

環境
macOS Ventura 13.6.6
xcode Version 15.2

エラーメッセージ

error

1エラーメッセージは出ません。

該当のソースコード

swift

1import SwiftUI 2import PDFKit 3import PencilKit 4 5struct PDFUIView: View { 6 @State private var isPen = true 7 8 var body: some View { 9 VStack { 10 HStack{ 11 Button(action: { 12 isPen = true 13 }, label: { 14 Text("ペン") 15 }) 16 Button(action: { 17 isPen = false 18 }, label: { 19 Text("消しゴム") 20 }) 21 //↓問題のコード 22 if isPen == true{ 23 }else { 24 } 25 //↑問題のコード 26 } 27 pdfView(isPen: $isPen) 28 } 29 } 30} 31 32struct pdfView : UIViewRepresentable { 33 typealias UIViewType = PDFView 34 @Binding var isPen: Bool 35 let overlayProvider = OverlayCoordinator() 36 func makeUIView(context: Context) -> PDFView { 37 let pdfView: PDFView = PDFView() 38 if let url = Bundle.main.url(forResource: "example", withExtension: "pdf") { 39 pdfView.pageOverlayViewProvider = overlayProvider 40 pdfView.document = PDFDocument(url: url) 41 pdfView.autoScales = true 42 pdfView.isInMarkupMode = true 43 } 44 return pdfView 45 } 46 func updateUIView(_ uiView: PDFView, context: Context) { 47 48 if isPen { 49 overlayProvider.setPen() 50 } else { 51 overlayProvider.setEraser() 52 } 53 54 } 55} 56 57class OverlayCoordinator : NSObject,PDFPageOverlayViewProvider { 58 var pageToViewMapping = [PDFPage: PKCanvasView]() 59 60 func pdfView(_ view: PDFView, overlayViewFor page: PDFPage) -> UIView? { 61 var resultView:PKCanvasView? = nil 62 if let overlayView = pageToViewMapping[page] { 63 resultView = overlayView 64 } else { 65 let canvasView = PKCanvasView() 66 canvasView.drawingPolicy = .anyInput 67 canvasView.tool = PKInkingTool(.pen, width: 1) 68 canvasView.backgroundColor = .clear 69 pageToViewMapping[page] = canvasView 70 resultView = canvasView 71 } 72 return resultView 73 74 } 75 func setPen() { 76 for i in pageToViewMapping { 77 i.value.tool = PKInkingTool(.pen, width: 1) 78 } 79 print(pageToViewMapping) //デバッグ用 80 81 } 82 func setEraser() { 83 for i in pageToViewMapping { 84 i.value.tool = PKEraserTool(.bitmap) 85 } 86 print(pageToViewMapping) //デバッグ用 87 } 88 89}

試したこと・調べたこと

  • teratailやGoogle等で検索した
  • ソースコードを自分なりに変更した
  • 知人に聞いた
  • その他
上記の詳細・結果

if文を別のところに挿入したり、追加でOverlayCoordinatorとは直接関係のない値を作成しても、「if文」が入ると同様の結果になってしまいました。

swift

1@State private var penMode = true 2 3Button(action: { 4 isPen = true 5 }, label: { 6 if penMode == true{ 7 }else { 8 } 9 })

補足

特になし

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答1

0

ベストアンサー

ごめんなさい。
前回の回答は不十分な内容だったみたいです。
(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 SwiftUI 2import PDFKit 3import PencilKit 4 5struct PDFUIView: View { 6 @State private var isPen = true 7 var body: some View { 8 VStack { 9 HStack{ 10 Button(action: { 11 isPen = true 12 }, label: { 13 Text("ペン") 14 }) 15 Button(action: { 16 isPen = false 17 }, 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 = PDFView 33 @Binding var isPen: Bool 34// 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 = true 41 pdfView.isInMarkupMode = true 42 } 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? = nil 63 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

投稿2024/04/29 05:35

yametai

総合スコア31

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

Gameno

2024/04/29 06:47

回答ありがとうございます。 試したところ問題が解決しました! ベストアンサーに選ばせていただきました。 PDFPageOverlayViewProviderを調べたときに、なぜ必要なのかわからず後回しにしていた問題が、こんな形で影響してくるとは思ってもいませんでした。勉強不足を痛感しました。 本当にありがとうございました。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.46%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問