Swift中PDF当前页面保存与返回定位实现问题咨询
解决SwiftUI中PDF页码保存与自动跳转问题
你当前的核心问题是在updateUIView中直接修改页码存储会触发视图无限更新循环,同时缺少对PDF页码变化的有效监听机制。下面是修复后的完整代码,同时保留你原有的tab切换逻辑:
import SwiftUI import PDFKit import SlidingTabView struct PDFKitRepresentedView: UIViewRepresentable { let url: URL @Binding var pageNum: [String: Int] init(_ url: URL, _ pageNum: Binding<[String: Int]>) { self.url = url self._pageNum = pageNum } // 定义Coordinator监听PDF页码变化 class Coordinator: NSObject, PDFViewDelegate { var parent: PDFKitRepresentedView init(parent: PDFKitRepresentedView) { self.parent = parent } // 页码变化时触发,更新字典存储 func pdfViewDidChangeCurrentPage(_ pdfView: PDFView) { guard let currentPage = pdfView.currentPage, let document = pdfView.document else { return } let pageIndex = document.index(for: currentPage) parent.pageNum[parent.url.lastPathComponent] = pageIndex } } func makeCoordinator() -> Coordinator { Coordinator(parent: self) } func makeUIView(context: UIViewRepresentableContext<PDFKitRepresentedView>) -> UIView { guard let document = PDFDocument(url: url) else { return UIView() } let pdfView = PDFView() pdfView.document = document pdfView.autoScales = true pdfView.delegate = context.coordinator // 初始化时跳转到保存的页码,默认0(第一页) let savedPageIndex = pageNum[url.lastPathComponent] ?? 0 if let targetPage = document.page(at: savedPageIndex) { pdfView.go(to: targetPage) } return pdfView } func updateUIView(_ uiView: UIView, context: UIViewRepresentableContext<PDFKitRepresentedView>) { // 仅在必要时更新,这里不需要修改状态,避免循环 guard let pdfView = uiView as? PDFView, let document = pdfView.document else { return } // 处理切换tab后可能的页码同步(确保视图切换后页码正确) let savedPageIndex = pageNum[url.lastPathComponent] ?? 0 if let targetPage = document.page(at: savedPageIndex), pdfView.currentPage != targetPage { pdfView.go(to: targetPage) } } } struct PDFKitView: View { var url: URL @Binding var pageNum: [String: Int] var body: some View { PDFKitRepresentedView(url, $pageNum) } } struct ContentView: View { @State private var showPicker = false @State private var fileURLs: [URL] = [] @State private var tabs: [String] = [] @State private var selectedTabIndex = 0 @State private var pageNums: [String: Int] = [:] @ViewBuilder var barItems: some View { if !fileURLs.isEmpty && selectedTabIndex < fileURLs.count { PDFKitView(url: fileURLs[selectedTabIndex], pageNum: $pageNums) .id(selectedTabIndex) } else { Text("No File Selected") } } var body: some View { NavigationView { VStack(alignment: .leading) { if !tabs.isEmpty { SlidingTabView(selection: $selectedTabIndex, tabs: tabs) } barItems.padding() Spacer() } .animation(.none, value: selectedTabIndex) .fileImporter(isPresented: $showPicker, allowedContentTypes: [.pdf]) { result in switch result { case .success(let fileURL): var fileName = fileURL.lastPathComponent // 处理重复文件名 let duplicateCount = tabs.filter { $0.hasPrefix(fileName) }.count if duplicateCount > 0 { fileName += " - \(duplicateCount)" } // 更新tab列表 if tabs.isEmpty { tabs.append(fileName) tabs.append("Open a new file") } else { if let newFileIndex = tabs.lastIndex(of: "Open a new file") { tabs[newFileIndex] = fileName tabs.append("Open a new file") } } fileURLs.append(fileURL) // 初始化当前PDF的页码为0(第一页) pageNums[fileName] = 0 case .failure(let error): print(error.localizedDescription) } } .navigationBarTitle("Tinjin", displayMode: .inline) .toolbar { Button { showPicker.toggle() } label: { Image(systemName: "folder") } } } } } struct ContentView_Previews: PreviewProvider { static var previews: some View { ContentView() } }
关键修改说明
- Coordinator监听页码变化:通过实现
PDFViewDelegate的pdfViewDidChangeCurrentPage方法,仅在用户手动翻页时更新页码字典,完全避免了updateUIView中的循环问题。 - 初始化时加载页码:在
makeUIView中直接读取字典里的保存值并跳转,确保PDF加载后直接显示上次浏览的位置。 - 优化文件名处理:简化了重复文件名的判断逻辑,同时限制文件选择器仅接受PDF类型,更符合需求。
- 初始化页码默认值:添加新PDF时自动给
pageNums字典设置初始页码0,避免字典中无对应键导致的崩溃。
内容的提问来源于stack exchange,提问作者toast
相关产品推荐
相关产品推荐

