Post

Replies

Boosts

Views

Activity

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
264
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
645
Apr ’24