Post

Replies

Boosts

Views

Activity

PDFKit Zoom Performance Issue with Many Annotations
Hello, I’m using PDFKit to display PDFs with a large number of annotations. However, when there are many annotations, I’m experiencing serious performance issues while zooming in/out with PDFView. • During pinch zoom, it seems like continuous re-rendering occurs. • Memory usage spikes dramatically while zooming, then drops back down repeatedly. • As a result, zooming feels laggy and not smooth. What I’d like to achieve is the following: 1. Prevent unnecessary re-rendering while zooming is in progress. 2. Trigger a single re-render only once the zoom gesture ends (e.g., in scrollViewDidEndZooming). 3. At the very least, avoid the memory spikes during zoom. Is there any way to control how annotations are re-drawn during zooming in PDFKit, or to throttle/debounce rendering so it happens only after the gesture completes? I’d really appreciate any advice from others who have encountered similar issues, or guidance from Apple on the recommended approach. Thanks in advance!
Topic: UI Frameworks SubTopic: UIKit Tags:
0
0
130
Oct ’25
PDFKit – How can I draw annotations behind text in PDFView?
Hi, I’m currently working with PDFKit and using PDFView to display documents. I’m adding free-drawing content as annotations, but I’ve noticed that these annotations are always rendered on top of the text, which ends up covering the text and making it hard to read. What I would like to do is render these drawing annotations behind the text layer, so that the document text remains visible above the drawing. Has anyone found a way to achieve this, or is there a recommended approach for controlling the annotation rendering order in PDFKit? Thanks in advance!
1
0
171
Sep ’25
Does the canvas view on top of the PDFView not re-render?
I added a canvas view using PDFPageOverlayViewProvider. When I zoom the PDFView, the drawing is scaled, but its quality becomes blurry. How can I fix this? import SwiftUI import PDFKit import PencilKit import CoreGraphics struct ContentView: View { var body: some View { if let url = Bundle.main.url(forResource: "sample", withExtension: "pdf"), let data = try? Data(contentsOf: url), let document = PDFDocument(data: data) { PDFRepresentableView(document: document) } else { Text("fail") } } } #Preview { ContentView() } struct PDFRepresentableView: UIViewRepresentable { let document: PDFDocument let pdfView = PDFView() func makeUIView(context: Context) -> PDFView { pdfView.displayMode = .singlePageContinuous pdfView.usePageViewController(false) pdfView.displayDirection = .vertical pdfView.pageOverlayViewProvider = context.coordinator pdfView.document = document pdfView.autoScales = false pdfView.minScaleFactor = 0.7 pdfView.maxScaleFactor = 4 return pdfView } func updateUIView(_ uiView: PDFView, context: Context) { // Optional: update logic if needed } func makeCoordinator() -> CustomCoordinator { return CustomCoordinator(parent: self) } } class CustomCoordinator: NSObject, PDFPageOverlayViewProvider, PKCanvasViewDelegate { let parent: PDFRepresentableView init(parent: PDFRepresentableView) { self.parent = parent } func pdfView(_ view: PDFView, overlayViewFor page: PDFPage) -> UIView? { let result = UIView() let canvasView = PKCanvasView() canvasView.drawingPolicy = .anyInput canvasView.tool = PKInkingTool(.pen, color: .blue, width: 20) canvasView.translatesAutoresizingMaskIntoConstraints = false result.addSubview(canvasView) NSLayoutConstraint.activate([ canvasView.leadingAnchor.constraint(equalTo: result.leadingAnchor), canvasView.trailingAnchor.constraint(equalTo: result.trailingAnchor), canvasView.topAnchor.constraint(equalTo: result.topAnchor), canvasView.bottomAnchor.constraint(equalTo: result.bottomAnchor) ]) for subView in view.documentView?.subviews ?? [] { subView.isUserInteractionEnabled = true } result.layoutIfNeeded() return result } }
1
0
299
Jul ’25
CanvasView overlay on PDFKit loses quality when zoomed – how to preserve drawing resolution?
Hi all, I’m currently building a SwiftUI app that overlays a PKCanvasView onto each page of a PDFView using PDFPageOverlayViewProvider. It works well at the initial scale, but once I zoom into the PDF, the drawings on the PKCanvasView appear blurry or pixelated, even though the PDF itself remains crisp. I’m trying to adjust canvasView.contentScaleFactor relative to pdfView.scaleFactor to preserve the drawing quality. Here’s a simplified version of the relevant code: import SwiftUI import PDFKit import PencilKit struct ContentView: View { var body: some View { if let url = Bundle.main.url(forResource: "sample", withExtension: "pdf"), let data = try? Data(contentsOf: url), let document = PDFDocument(data: data) { PDFRepresentableView(document: document) } else { Text("") } } } #Preview { ContentView() } struct PDFRepresentableView: UIViewRepresentable { let document: PDFDocument let pdfView = PDFView() func makeUIView(context: Context) -> PDFView { pdfView.displayMode = .singlePageContinuous pdfView.usePageViewController(false) pdfView.displayDirection = .vertical pdfView.pageOverlayViewProvider = context.coordinator pdfView.document = document pdfView.autoScales = false pdfView.minScaleFactor = 0.7 pdfView.maxScaleFactor = 4 NotificationCenter.default.addObserver( context.coordinator, selector: #selector(context.coordinator.onPageZoomAndPan), name: .PDFViewScaleChanged, object: pdfView ) return pdfView } func updateUIView(_ uiView: PDFView, context: Context) { // Optional: update logic if needed } func makeCoordinator() -> CustomCoordinator { return CustomCoordinator(parent: self) } } class CustomCoordinator: NSObject, PDFPageOverlayViewProvider, PKCanvasViewDelegate { let parent: PDFRepresentableView init(parent: PDFRepresentableView) { self.parent = parent } func pdfView(_ view: PDFView, overlayViewFor page: PDFPage) -> UIView? { let canvasView = PKCanvasView() let rect = page.bounds(for: .mediaBox) canvasView.drawingPolicy = .anyInput canvasView.tool = PKInkingTool(.pen, color: .black, width: 10) canvasView.translatesAutoresizingMaskIntoConstraints = true canvasView.backgroundColor = .red.withAlphaComponent(0.1) canvasView.frame = rect canvasView.isScrollEnabled = false for subView in view.documentView?.subviews ?? [] { subView.isUserInteractionEnabled = true } return canvasView } @objc func onPageZoomAndPan() { parent.pdfView.documentView?.subviews.forEach { subview in if subview.theClassName == "PDFPageView", let pageViewPrivate = subview.value(forKey: "_private") as? NSObject, let page = pageViewPrivate.value(forKey: "page") as? PDFPage { subview.subviews.forEach { subview in if let canvasView = subview as? PKCanvasView { let zoomScale = parent.pdfView.scaleFactor canvasView.contentScaleFactor = UIScreen.main.scale * zoomScale canvasView.drawing = canvasView.drawing canvasView.setNeedsDisplay() canvasView.layoutIfNeeded() } } } } print("Zoom changed. Current scale: \(parent.pdfView.scaleFactor)") } } extension NSObject { var theClassName: String { return NSStringFromClass(type(of: self)) } } But this doesn’t seem to improve the rendered quality. The lines still appear blurry when zoomed in. What I’ve tried: • Adjusting contentScaleFactor and forcing redraw • Reassigning canvasView.drawing • Calling setNeedsDisplay() and layoutIfNeeded() None of these approaches seem to re-render the canvas at a higher resolution or match the zoomed scale of the PDF. My questions: 1. Is there a correct way to scale PKCanvasView content to match PDF zoom levels? 2. Should I recreate the canvas or drawing when zoom changes? 3. Is PKCanvasView just not intended to handle high zoom fidelity? If anyone has successfully overlaid high-resolution canvas drawing on a zoomable PDFView, I’d love to hear how you managed it. Thanks in advance!
0
0
238
Jul ’25
Does LazyVStack and LazyVGrid release views from memory inside a ScrollView?
I am using LazyVStack inside a ScrollView. I understand that lazy views are rendered only when they come into view. However, I haven’t heard much about memory deallocation. I observed that in iOS 18 and later, when scrolling up, the bottom-most views are deallocated from memory, whereas in iOS 17, they are not (Example 1). Additionally, I noticed a similar behavior when switching views using a switch. When switching views by pressing a button, the view was intermittently deinitialized. (Example 2). Example 1) struct ContentView: View { var body: some View { ScrollView { LazyVStack { ForEach(0..<40) { index in CellView(index: index) } } } .padding() } } struct CellView: View { let index: Int @StateObject var viewModel = CellViewModel() var body: some View { Rectangle() .fill(Color.accentColor) .frame(width: 300, height: 300) .overlay { Text("\(index)") } .onAppear { viewModel.index = index } } } class CellViewModel: ObservableObject { @Published var index = 0 init() { print("init") } deinit { print("\(index) deinit") } } #Preview { ContentView() } Example 2 struct ContentView: View { @State var index = 0 var body: some View { LazyVStack { Button(action: { if index > 5 { index = 0 } else { index += 1 } }) { Text("plus index") } MidCellView(index: index) } .padding() } } struct MidCellView: View { let index: Int var body: some View { switch index { case 1: CellView(index: 1) case 2: CellView(index: 2) case 3: CellView(index: 3) case 4: CellView(index: 4) default: CellView(index: 0) } } } struct CellView: View { let index: Int @StateObject var viewModel = CellViewModel() var body: some View { Rectangle() .fill(Color.accentColor) .frame(width: 300, height: 300) .overlay { Text("\(index)") } .onAppear { viewModel.index = index } } } class CellViewModel: ObservableObject { @Published var index = 0 init() { print("init") } deinit { print("\(index) deinit") } } -------------------- init init init init init 2 deinit 3 deinit 4 deinit init
Topic: UI Frameworks SubTopic: SwiftUI
2
0
369
Feb ’25
not work paragraphStyle in AttributedString
I tried to create a Text View using attributedString. I want to set the line height using paragraphStyle and return the Text, but paragraphStyle is not being applied. Why is that? extension Text { init?(_ content: String, font: StyleType, color: Color = .ppBlack) { var attributedString = AttributedString(content) attributedString.font = Font.custom(font.fontWeight, fixedSize: font.fontSize) attributedString.foregroundColor = color let paragraphStyle = NSMutableParagraphStyle() paragraphStyle.minimumLineHeight = 16 paragraphStyle.maximumLineHeight = 16 paragraphStyle.lineSpacing = 0 attributedString.mergeAttributes(.init([.paragraphStyle: paragraphStyle])) self = Text(attributedString) } }
1
0
353
Feb ’25
how to change overlay View in PDFPageOverlayViewProvider
I’m using PDFPageOverlayViewProvider with pdfview. I want to control the visibility of the overlay view using a button. However, the view updates only when it disappears and reappears. I would like the changes to be reflected immediately. How can I achieve this? struct PDFKitView: View { let bookId: UUID let bookTitle: String @State private var currentPage = "1" @State private var isSideTab = false @State private var selectedNote: [SelectedNote] = [] var body: some View { let pdfDocument = openPDF(at: bookId.uuidString) ZStack(alignment: .trailing) { HStack(spacing: 0) { PDFKitRepresentableView( bookId: bookId, selectedNote: $selectedNote, currentPage: $currentPage, pdfDocument: pdfDocument ) if isSideTab { SideView() .transition(.move(edge: .trailing)) .zIndex(1) .frame(maxWidth: 260) } } .padding(.top, 73) } .onAppear { getAllNote(bookId: bookId) } .customNavigationBar(back: true) { Text("\(currentPage)/\(pdfDocument.pageCount)") .pretendard(.CaptionRegular) .foregroundStyle(Color.Text.primary) } TrailingView: { Button(action: { withAnimation { isSideTab.toggle() } }) { Image(systemName: SFSymbol.squareStack3dDownForwardFill.icon) .sfPro(.IconMedium) .foregroundStyle(Color.Text.primary) } } } @ViewBuilder func SideView() -> some View { VStack(spacing: 16) { HStack(spacing: 4) { Image(systemName: SFSymbol.squareStack3dDownForwardFill.icon) .sfPro(.IconSmall) .foregroundStyle(Color.Text.primary) Text(Literals.sideTabTitle) .pretendard(.P2Bold) .foregroundStyle(Color.Text.primary) Spacer() } .padding(16) .background { Color.Background.white } ScrollView { ForEach($selectedNote, id: \.noteId) { note in NoteCellView(note: note) } } .background { Color.Fill.white } } .background { Color.Background.blueGray } } @ViewBuilder func NoteCellView(note: Binding<SelectedNote>) -> some View { HStack(alignment: .top, spacing: 16) { Image(.writingNote) .resizable() .scaledToFit() .frame(width: 42, height: 60) VStack(alignment: .leading, spacing: 8) { Text(note.wrappedValue.noteId == bookId.uuidString ? "345" : "123") .foregroundStyle(Color.Text.secondary) .padding(.horizontal, 8) .background { Rectangle() .strokeBorder(Color.Layout.secondary) } Text(bookTitle) .lineLimit(2) Toggle("", isOn: note.selected) .labelsHidden() .tint(Color.Fill.activePrimary) } } .padding(EdgeInsets(top: 20, leading: 16, bottom: 16, trailing: 16)) } } struct PDFKitRepresentableView: UIViewRepresentable { let bookId: UUID @Binding var selectedNote: [SelectedNote] @Binding var currentPage: String let pdfDocument: PDFDocument let pdfView = PDFView() let toolPicker = PKToolPicker() func makeUIView(context: Context) -> PDFView { pdfView.displayMode = .singlePageContinuous pdfView.usePageViewController(false) pdfView.displayDirection = .vertical pdfView.pageOverlayViewProvider = context.coordinator pdfView.autoScales = true pdfDocument.delegate = context.coordinator pdfView.document = pdfDocument return pdfView } func updateUIView(_ uiView: PDFView, context: Context) { if let localNote = selectedNote.first(where: {$0.noteId == bookId.uuidString}), !localNote.selected { toolPicker.setVisible(false, forFirstResponder: uiView) } else { toolPicker.setVisible(true, forFirstResponder: uiView) } uiView.becomeFirstResponder() } func makeCoordinator() -> CanvasProvider { return CanvasProvider(parent: self) } } final class CanvasProvider: NSObject, PDFPageOverlayViewProvider, PDFDocumentDelegate { var localNotes = [PDFPage: PKCanvasView]() var passNotes = [PDFPage: Image]() let parent: PDFKitRepresentableView init(parent: PDFKitRepresentableView) { self.parent = parent super.init() getDrawingDatas( bookId: parent.bookId.uuidString, selectedNote: parent.selectedNote, document: parent.pdfDocument ) } func pdfView(_ view: PDFView, overlayViewFor page: PDFPage) -> UIView? { var coverView: PKCanvasView? = PKCanvasView() if let view = localNotes[page], parent.selectedNote.first(where: { $0.noteId == parent.bookId.uuidString })?.selected ?? false { view.backgroundColor = .clear view.isOpaque = true view.drawingPolicy = .anyInput view.delegate = self parent.toolPicker.addObserver(view) coverView = view (page as? CanvasPDFPage)?.canvasView = view } else { coverView = nil } for subView in view.documentView?.subviews ?? [] { if subView.theClassName == "PDFPageView" { subView.isUserInteractionEnabled = true } } return coverView } func pdfView(_ pdfView: PDFView, willDisplayOverlayView overlayView: UIView, for page: PDFPage) { } func pdfView(_ pdfView: PDFView, willEndDisplayingOverlayView overlayView: UIView, for page: PDFPage) { } }
0
0
721
Aug ’24
When using index in a ForEach loop in SwiftUI, you might encounter an "index out of range" error.
I encountered a problem while using ScrollView in SwiftUI. When I perform a refresh, the app crashes. I access the array using an index in a ForEach loop. This is done to create new data from the array in a commonly used view. The function to create data is adopted from a protocol in the view model. I access it by index because the type of the array is not specified; each view using it may have a different data type. Below is an example code. Is it possible to access data from the array using an index? Every time I refresh, I get an "index out of range" error. import SwiftUI struct ContentView: View { @StateObject var viewModel = ViewModel() var body: some View { ScrollView { if !viewModel.testValues.isEmpty { LazyVStack(spacing: 20) { ForEach(Array(zip(viewModel.testValues.indices, viewModel.testValues)), id:\.1) { index, data in test(index: index, data: data, viewModel: viewModel) .onAppear { if !viewModel.isLoading, viewModel.testValues.count - 2 == index { viewModel.fetch() } } } } } else { Text("tesetsetsetsettse") } } .onAppear { viewModel.fetch() } .refreshable { viewModel.refresh() } } } struct test: View { let index: Int let data: String @ObservedObject var viewModel: ViewModel var body: some View { VStack(spacing: 8) { test1(index: index, data: data, viewModel: viewModel) Text("------------------------") } } } struct test1: View { let index: Int let data: String @ObservedObject var viewModel: ViewModel var body: some View { VStack { Text(viewModel.testValues[index]) .font(.system(size: 12)) .foregroundStyle(Color.red) .padding(.horizontal, 40) .padding(.vertical, 50) .background { RoundedRectangle(cornerRadius: 20) .fill(Color.blue) } } } } class ViewModel: ObservableObject { @Published var isLoading = false @Published var testValues: [String] = [] func fetch() { DispatchQueue.main.asyncAfter(deadline: .now() + 0.5) { self.testValues += [ UUID().uuidString, UUID().uuidString, UUID().uuidString, UUID().uuidString, UUID().uuidString, UUID().uuidString, UUID().uuidString, UUID().uuidString, UUID().uuidString, UUID().uuidString, ] } } func refresh() { testValues = [] fetch() } }
4
0
1.5k
May ’24
PDFKit Zoom Performance Issue with Many Annotations
Hello, I’m using PDFKit to display PDFs with a large number of annotations. However, when there are many annotations, I’m experiencing serious performance issues while zooming in/out with PDFView. • During pinch zoom, it seems like continuous re-rendering occurs. • Memory usage spikes dramatically while zooming, then drops back down repeatedly. • As a result, zooming feels laggy and not smooth. What I’d like to achieve is the following: 1. Prevent unnecessary re-rendering while zooming is in progress. 2. Trigger a single re-render only once the zoom gesture ends (e.g., in scrollViewDidEndZooming). 3. At the very least, avoid the memory spikes during zoom. Is there any way to control how annotations are re-drawn during zooming in PDFKit, or to throttle/debounce rendering so it happens only after the gesture completes? I’d really appreciate any advice from others who have encountered similar issues, or guidance from Apple on the recommended approach. Thanks in advance!
Topic: UI Frameworks SubTopic: UIKit Tags:
Replies
0
Boosts
0
Views
130
Activity
Oct ’25
PDFKit – How can I draw annotations behind text in PDFView?
Hi, I’m currently working with PDFKit and using PDFView to display documents. I’m adding free-drawing content as annotations, but I’ve noticed that these annotations are always rendered on top of the text, which ends up covering the text and making it hard to read. What I would like to do is render these drawing annotations behind the text layer, so that the document text remains visible above the drawing. Has anyone found a way to achieve this, or is there a recommended approach for controlling the annotation rendering order in PDFKit? Thanks in advance!
Replies
1
Boosts
0
Views
171
Activity
Sep ’25
Does the canvas view on top of the PDFView not re-render?
I added a canvas view using PDFPageOverlayViewProvider. When I zoom the PDFView, the drawing is scaled, but its quality becomes blurry. How can I fix this? import SwiftUI import PDFKit import PencilKit import CoreGraphics struct ContentView: View { var body: some View { if let url = Bundle.main.url(forResource: "sample", withExtension: "pdf"), let data = try? Data(contentsOf: url), let document = PDFDocument(data: data) { PDFRepresentableView(document: document) } else { Text("fail") } } } #Preview { ContentView() } struct PDFRepresentableView: UIViewRepresentable { let document: PDFDocument let pdfView = PDFView() func makeUIView(context: Context) -> PDFView { pdfView.displayMode = .singlePageContinuous pdfView.usePageViewController(false) pdfView.displayDirection = .vertical pdfView.pageOverlayViewProvider = context.coordinator pdfView.document = document pdfView.autoScales = false pdfView.minScaleFactor = 0.7 pdfView.maxScaleFactor = 4 return pdfView } func updateUIView(_ uiView: PDFView, context: Context) { // Optional: update logic if needed } func makeCoordinator() -> CustomCoordinator { return CustomCoordinator(parent: self) } } class CustomCoordinator: NSObject, PDFPageOverlayViewProvider, PKCanvasViewDelegate { let parent: PDFRepresentableView init(parent: PDFRepresentableView) { self.parent = parent } func pdfView(_ view: PDFView, overlayViewFor page: PDFPage) -> UIView? { let result = UIView() let canvasView = PKCanvasView() canvasView.drawingPolicy = .anyInput canvasView.tool = PKInkingTool(.pen, color: .blue, width: 20) canvasView.translatesAutoresizingMaskIntoConstraints = false result.addSubview(canvasView) NSLayoutConstraint.activate([ canvasView.leadingAnchor.constraint(equalTo: result.leadingAnchor), canvasView.trailingAnchor.constraint(equalTo: result.trailingAnchor), canvasView.topAnchor.constraint(equalTo: result.topAnchor), canvasView.bottomAnchor.constraint(equalTo: result.bottomAnchor) ]) for subView in view.documentView?.subviews ?? [] { subView.isUserInteractionEnabled = true } result.layoutIfNeeded() return result } }
Replies
1
Boosts
0
Views
299
Activity
Jul ’25
CanvasView overlay on PDFKit loses quality when zoomed – how to preserve drawing resolution?
Hi all, I’m currently building a SwiftUI app that overlays a PKCanvasView onto each page of a PDFView using PDFPageOverlayViewProvider. It works well at the initial scale, but once I zoom into the PDF, the drawings on the PKCanvasView appear blurry or pixelated, even though the PDF itself remains crisp. I’m trying to adjust canvasView.contentScaleFactor relative to pdfView.scaleFactor to preserve the drawing quality. Here’s a simplified version of the relevant code: import SwiftUI import PDFKit import PencilKit struct ContentView: View { var body: some View { if let url = Bundle.main.url(forResource: "sample", withExtension: "pdf"), let data = try? Data(contentsOf: url), let document = PDFDocument(data: data) { PDFRepresentableView(document: document) } else { Text("") } } } #Preview { ContentView() } struct PDFRepresentableView: UIViewRepresentable { let document: PDFDocument let pdfView = PDFView() func makeUIView(context: Context) -> PDFView { pdfView.displayMode = .singlePageContinuous pdfView.usePageViewController(false) pdfView.displayDirection = .vertical pdfView.pageOverlayViewProvider = context.coordinator pdfView.document = document pdfView.autoScales = false pdfView.minScaleFactor = 0.7 pdfView.maxScaleFactor = 4 NotificationCenter.default.addObserver( context.coordinator, selector: #selector(context.coordinator.onPageZoomAndPan), name: .PDFViewScaleChanged, object: pdfView ) return pdfView } func updateUIView(_ uiView: PDFView, context: Context) { // Optional: update logic if needed } func makeCoordinator() -> CustomCoordinator { return CustomCoordinator(parent: self) } } class CustomCoordinator: NSObject, PDFPageOverlayViewProvider, PKCanvasViewDelegate { let parent: PDFRepresentableView init(parent: PDFRepresentableView) { self.parent = parent } func pdfView(_ view: PDFView, overlayViewFor page: PDFPage) -> UIView? { let canvasView = PKCanvasView() let rect = page.bounds(for: .mediaBox) canvasView.drawingPolicy = .anyInput canvasView.tool = PKInkingTool(.pen, color: .black, width: 10) canvasView.translatesAutoresizingMaskIntoConstraints = true canvasView.backgroundColor = .red.withAlphaComponent(0.1) canvasView.frame = rect canvasView.isScrollEnabled = false for subView in view.documentView?.subviews ?? [] { subView.isUserInteractionEnabled = true } return canvasView } @objc func onPageZoomAndPan() { parent.pdfView.documentView?.subviews.forEach { subview in if subview.theClassName == "PDFPageView", let pageViewPrivate = subview.value(forKey: "_private") as? NSObject, let page = pageViewPrivate.value(forKey: "page") as? PDFPage { subview.subviews.forEach { subview in if let canvasView = subview as? PKCanvasView { let zoomScale = parent.pdfView.scaleFactor canvasView.contentScaleFactor = UIScreen.main.scale * zoomScale canvasView.drawing = canvasView.drawing canvasView.setNeedsDisplay() canvasView.layoutIfNeeded() } } } } print("Zoom changed. Current scale: \(parent.pdfView.scaleFactor)") } } extension NSObject { var theClassName: String { return NSStringFromClass(type(of: self)) } } But this doesn’t seem to improve the rendered quality. The lines still appear blurry when zoomed in. What I’ve tried: • Adjusting contentScaleFactor and forcing redraw • Reassigning canvasView.drawing • Calling setNeedsDisplay() and layoutIfNeeded() None of these approaches seem to re-render the canvas at a higher resolution or match the zoomed scale of the PDF. My questions: 1. Is there a correct way to scale PKCanvasView content to match PDF zoom levels? 2. Should I recreate the canvas or drawing when zoom changes? 3. Is PKCanvasView just not intended to handle high zoom fidelity? If anyone has successfully overlaid high-resolution canvas drawing on a zoomable PDFView, I’d love to hear how you managed it. Thanks in advance!
Replies
0
Boosts
0
Views
238
Activity
Jul ’25
Is it possible to access the currently drawn (in-progress) drawing data from the canvas view?
The canvasView in PKCanvasViewDelegate only holds the drawing data up to the most recently completed stroke. I want to access the currently in-progress drawing (before the pencil is lifted) in order to measure the path’s size — but I can’t find a way to do it. Is there any way you could help me with this?
Replies
1
Boosts
0
Views
257
Activity
Jul ’25
Does LazyVStack and LazyVGrid release views from memory inside a ScrollView?
I am using LazyVStack inside a ScrollView. I understand that lazy views are rendered only when they come into view. However, I haven’t heard much about memory deallocation. I observed that in iOS 18 and later, when scrolling up, the bottom-most views are deallocated from memory, whereas in iOS 17, they are not (Example 1). Additionally, I noticed a similar behavior when switching views using a switch. When switching views by pressing a button, the view was intermittently deinitialized. (Example 2). Example 1) struct ContentView: View { var body: some View { ScrollView { LazyVStack { ForEach(0..<40) { index in CellView(index: index) } } } .padding() } } struct CellView: View { let index: Int @StateObject var viewModel = CellViewModel() var body: some View { Rectangle() .fill(Color.accentColor) .frame(width: 300, height: 300) .overlay { Text("\(index)") } .onAppear { viewModel.index = index } } } class CellViewModel: ObservableObject { @Published var index = 0 init() { print("init") } deinit { print("\(index) deinit") } } #Preview { ContentView() } Example 2 struct ContentView: View { @State var index = 0 var body: some View { LazyVStack { Button(action: { if index > 5 { index = 0 } else { index += 1 } }) { Text("plus index") } MidCellView(index: index) } .padding() } } struct MidCellView: View { let index: Int var body: some View { switch index { case 1: CellView(index: 1) case 2: CellView(index: 2) case 3: CellView(index: 3) case 4: CellView(index: 4) default: CellView(index: 0) } } } struct CellView: View { let index: Int @StateObject var viewModel = CellViewModel() var body: some View { Rectangle() .fill(Color.accentColor) .frame(width: 300, height: 300) .overlay { Text("\(index)") } .onAppear { viewModel.index = index } } } class CellViewModel: ObservableObject { @Published var index = 0 init() { print("init") } deinit { print("\(index) deinit") } } -------------------- init init init init init 2 deinit 3 deinit 4 deinit init
Topic: UI Frameworks SubTopic: SwiftUI
Replies
2
Boosts
0
Views
369
Activity
Feb ’25
not work paragraphStyle in AttributedString
I tried to create a Text View using attributedString. I want to set the line height using paragraphStyle and return the Text, but paragraphStyle is not being applied. Why is that? extension Text { init?(_ content: String, font: StyleType, color: Color = .ppBlack) { var attributedString = AttributedString(content) attributedString.font = Font.custom(font.fontWeight, fixedSize: font.fontSize) attributedString.foregroundColor = color let paragraphStyle = NSMutableParagraphStyle() paragraphStyle.minimumLineHeight = 16 paragraphStyle.maximumLineHeight = 16 paragraphStyle.lineSpacing = 0 attributedString.mergeAttributes(.init([.paragraphStyle: paragraphStyle])) self = Text(attributedString) } }
Replies
1
Boosts
0
Views
353
Activity
Feb ’25
how to refresh PDFPageOverlayViewProvid
I am using PDFPageOverlayViewProvider from pdfkit. I would like to detect changes in the overlaid view and refresh PDFPageOverlayViewProvider. Currently, it does not refresh even when the overlaid view changes. Is there a way to refresh it?
Replies
0
Boosts
0
Views
519
Activity
Oct ’24
I want to add image and textfield to pkcanvasview.
I want to add a pkcanvasview image and change its position and size by dragging. And I want to draw a picture using a pencil on top. The image must be able to change its position at any time, and a picture must be added on top. If I add it to the subview of pkcanvasview, I cannot do what I want. How can I do this?
Replies
0
Boosts
0
Views
506
Activity
Sep ’24
Can DRM Be Applied to pdfkit?
I need to apply security measures to a PDF. My goal is to prevent it from being leaked, and even if it is leaked, I want to ensure that the PDF cannot be viewed. Is it possible to use pdfkit and apply DRM to achieve this?​⬤
Replies
0
Boosts
0
Views
583
Activity
Sep ’24
how to change overlay View in PDFPageOverlayViewProvider
I’m using PDFPageOverlayViewProvider with pdfview. I want to control the visibility of the overlay view using a button. However, the view updates only when it disappears and reappears. I would like the changes to be reflected immediately. How can I achieve this? struct PDFKitView: View { let bookId: UUID let bookTitle: String @State private var currentPage = "1" @State private var isSideTab = false @State private var selectedNote: [SelectedNote] = [] var body: some View { let pdfDocument = openPDF(at: bookId.uuidString) ZStack(alignment: .trailing) { HStack(spacing: 0) { PDFKitRepresentableView( bookId: bookId, selectedNote: $selectedNote, currentPage: $currentPage, pdfDocument: pdfDocument ) if isSideTab { SideView() .transition(.move(edge: .trailing)) .zIndex(1) .frame(maxWidth: 260) } } .padding(.top, 73) } .onAppear { getAllNote(bookId: bookId) } .customNavigationBar(back: true) { Text("\(currentPage)/\(pdfDocument.pageCount)") .pretendard(.CaptionRegular) .foregroundStyle(Color.Text.primary) } TrailingView: { Button(action: { withAnimation { isSideTab.toggle() } }) { Image(systemName: SFSymbol.squareStack3dDownForwardFill.icon) .sfPro(.IconMedium) .foregroundStyle(Color.Text.primary) } } } @ViewBuilder func SideView() -> some View { VStack(spacing: 16) { HStack(spacing: 4) { Image(systemName: SFSymbol.squareStack3dDownForwardFill.icon) .sfPro(.IconSmall) .foregroundStyle(Color.Text.primary) Text(Literals.sideTabTitle) .pretendard(.P2Bold) .foregroundStyle(Color.Text.primary) Spacer() } .padding(16) .background { Color.Background.white } ScrollView { ForEach($selectedNote, id: \.noteId) { note in NoteCellView(note: note) } } .background { Color.Fill.white } } .background { Color.Background.blueGray } } @ViewBuilder func NoteCellView(note: Binding<SelectedNote>) -> some View { HStack(alignment: .top, spacing: 16) { Image(.writingNote) .resizable() .scaledToFit() .frame(width: 42, height: 60) VStack(alignment: .leading, spacing: 8) { Text(note.wrappedValue.noteId == bookId.uuidString ? "345" : "123") .foregroundStyle(Color.Text.secondary) .padding(.horizontal, 8) .background { Rectangle() .strokeBorder(Color.Layout.secondary) } Text(bookTitle) .lineLimit(2) Toggle("", isOn: note.selected) .labelsHidden() .tint(Color.Fill.activePrimary) } } .padding(EdgeInsets(top: 20, leading: 16, bottom: 16, trailing: 16)) } } struct PDFKitRepresentableView: UIViewRepresentable { let bookId: UUID @Binding var selectedNote: [SelectedNote] @Binding var currentPage: String let pdfDocument: PDFDocument let pdfView = PDFView() let toolPicker = PKToolPicker() func makeUIView(context: Context) -> PDFView { pdfView.displayMode = .singlePageContinuous pdfView.usePageViewController(false) pdfView.displayDirection = .vertical pdfView.pageOverlayViewProvider = context.coordinator pdfView.autoScales = true pdfDocument.delegate = context.coordinator pdfView.document = pdfDocument return pdfView } func updateUIView(_ uiView: PDFView, context: Context) { if let localNote = selectedNote.first(where: {$0.noteId == bookId.uuidString}), !localNote.selected { toolPicker.setVisible(false, forFirstResponder: uiView) } else { toolPicker.setVisible(true, forFirstResponder: uiView) } uiView.becomeFirstResponder() } func makeCoordinator() -> CanvasProvider { return CanvasProvider(parent: self) } } final class CanvasProvider: NSObject, PDFPageOverlayViewProvider, PDFDocumentDelegate { var localNotes = [PDFPage: PKCanvasView]() var passNotes = [PDFPage: Image]() let parent: PDFKitRepresentableView init(parent: PDFKitRepresentableView) { self.parent = parent super.init() getDrawingDatas( bookId: parent.bookId.uuidString, selectedNote: parent.selectedNote, document: parent.pdfDocument ) } func pdfView(_ view: PDFView, overlayViewFor page: PDFPage) -> UIView? { var coverView: PKCanvasView? = PKCanvasView() if let view = localNotes[page], parent.selectedNote.first(where: { $0.noteId == parent.bookId.uuidString })?.selected ?? false { view.backgroundColor = .clear view.isOpaque = true view.drawingPolicy = .anyInput view.delegate = self parent.toolPicker.addObserver(view) coverView = view (page as? CanvasPDFPage)?.canvasView = view } else { coverView = nil } for subView in view.documentView?.subviews ?? [] { if subView.theClassName == "PDFPageView" { subView.isUserInteractionEnabled = true } } return coverView } func pdfView(_ pdfView: PDFView, willDisplayOverlayView overlayView: UIView, for page: PDFPage) { } func pdfView(_ pdfView: PDFView, willEndDisplayingOverlayView overlayView: UIView, for page: PDFPage) { } }
Replies
0
Boosts
0
Views
721
Activity
Aug ’24
When using index in a ForEach loop in SwiftUI, you might encounter an "index out of range" error.
I encountered a problem while using ScrollView in SwiftUI. When I perform a refresh, the app crashes. I access the array using an index in a ForEach loop. This is done to create new data from the array in a commonly used view. The function to create data is adopted from a protocol in the view model. I access it by index because the type of the array is not specified; each view using it may have a different data type. Below is an example code. Is it possible to access data from the array using an index? Every time I refresh, I get an "index out of range" error. import SwiftUI struct ContentView: View { @StateObject var viewModel = ViewModel() var body: some View { ScrollView { if !viewModel.testValues.isEmpty { LazyVStack(spacing: 20) { ForEach(Array(zip(viewModel.testValues.indices, viewModel.testValues)), id:\.1) { index, data in test(index: index, data: data, viewModel: viewModel) .onAppear { if !viewModel.isLoading, viewModel.testValues.count - 2 == index { viewModel.fetch() } } } } } else { Text("tesetsetsetsettse") } } .onAppear { viewModel.fetch() } .refreshable { viewModel.refresh() } } } struct test: View { let index: Int let data: String @ObservedObject var viewModel: ViewModel var body: some View { VStack(spacing: 8) { test1(index: index, data: data, viewModel: viewModel) Text("------------------------") } } } struct test1: View { let index: Int let data: String @ObservedObject var viewModel: ViewModel var body: some View { VStack { Text(viewModel.testValues[index]) .font(.system(size: 12)) .foregroundStyle(Color.red) .padding(.horizontal, 40) .padding(.vertical, 50) .background { RoundedRectangle(cornerRadius: 20) .fill(Color.blue) } } } } class ViewModel: ObservableObject { @Published var isLoading = false @Published var testValues: [String] = [] func fetch() { DispatchQueue.main.asyncAfter(deadline: .now() + 0.5) { self.testValues += [ UUID().uuidString, UUID().uuidString, UUID().uuidString, UUID().uuidString, UUID().uuidString, UUID().uuidString, UUID().uuidString, UUID().uuidString, UUID().uuidString, UUID().uuidString, ] } } func refresh() { testValues = [] fetch() } }
Replies
4
Boosts
0
Views
1.5k
Activity
May ’24
How can I create a list in the Reminders app using EventKit?
I want to create a list in the Reminders app using EventKit. For each created list, I want to create EKReminders. However, it seems that EventKit does not provide a way to create a reminder list directly. How can I achieve this?
Replies
1
Boosts
0
Views
725
Activity
Jan ’24
the header of the last section when using 'plain' ListStyle in SwiftUI
I learned that the background appears on the header of the last section. Why does that happen. Here is my code: This situration does not occur unless .font is applied to the Text. How can we interpret this issue?
Replies
1
Boosts
0
Views
434
Activity
Jun ’23