You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在PDFKit中监听文档滚动至底部事件以解锁按钮?

滚动到PDF末尾解锁按钮的实现方案

核心思路

给PDFView设置代理监听滚动事件,判断用户是否滚动到文档最后一页的底部,同步更新SwiftUI中按钮的启用状态。

步骤1:修改PDFDocumentView,添加状态绑定

给UIViewRepresentable结构体添加@Binding属性传递按钮启用状态,并将代理与该绑定关联:

import PDFKit
import SwiftUI

struct PDFDocumentView: UIViewRepresentable {
    private var url: URL?
    @Binding var isButtonEnabled: Bool // 绑定按钮启用状态
    private let pdfDocumentDelegate: PdfDocumentDelegate
    
    init(url: URL, isButtonEnabled: Binding<Bool>) {
        self.url = url
        self._isButtonEnabled = isButtonEnabled
        self.pdfDocumentDelegate = PdfDocumentDelegate(isButtonEnabled: isButtonEnabled)
    }
    
    func makeUIView(context: Context) -> PDFView {
        let pdfView = PDFView()
        pdfView.delegate = pdfDocumentDelegate // 设置代理
        if let url {
            pdfView.document = PDFDocument(url: url)
            pdfView.autoScales = true
            pdfView.maxScaleFactor = 3.0
            pdfView.minScaleFactor = pdfView.scaleFactorForSizeToFit
        }
        return pdfView
    }
    
    func updateUIView(_ uiView: PDFView, context: Context) {}
}

步骤2:实现PDFView代理逻辑

完善PdfDocumentDelegate类,通过滚动监听判断是否到达文档末尾:

class PdfDocumentDelegate: NSObject, PDFViewDelegate {
    @Binding private var isButtonEnabled: Bool
    
    init(isButtonEnabled: Binding<Bool>) {
        self._isButtonEnabled = isButtonEnabled
        super.init()
    }
    
    func pdfViewDidScroll(_ pdfView: PDFView) {
        guard let document = pdfView.document else { return }
        let totalPages = document.pageCount
        
        guard let visiblePage = pdfView.currentPage else { return }
        let currentPageIndex = document.index(for: visiblePage) + 1
        
        // 未到最后一页时保持按钮禁用
        guard currentPageIndex == totalPages else {
            if isButtonEnabled { isButtonEnabled = false }
            return
        }
        
        // 计算当前页面可见区域是否到达底部
        let pageBounds = visiblePage.bounds(for: pdfView.displayBox)
        let visibleRect = pdfView.convert(pdfView.bounds, to: visiblePage)
        
        // 留10pt误差避免滚动精度问题
        let isAtBottom = visibleRect.maxY >= pageBounds.maxY - 10
        
        if isAtBottom != isButtonEnabled {
            isButtonEnabled = isAtBottom
        }
    }
}

步骤3:在主视图中使用

创建包含PDFView和按钮的SwiftUI视图,绑定状态控制按钮启用:

struct ContentView: View {
    @State private var buttonEnabled = false
    
    var body: some View {
        VStack {
            PDFDocumentView(url: yourPDFURL, isButtonEnabled: $buttonEnabled)
                .edgesIgnoringSafeArea(.all)
            
            Button("确认完成") {
                // 按钮点击逻辑
            }
            .disabled(!buttonEnabled)
            .padding()
            .background(buttonEnabled ? Color.blue : Color.gray)
            .foregroundColor(.white)
            .cornerRadius(8)
        }
    }
    
    // 替换为你的PDF文件URL
    private var yourPDFURL: URL {
        guard let url = Bundle.main.url(forResource: "sample", withExtension: "pdf") else {
            fatalError("PDF文件不存在")
        }
        return url
    }
}

关键说明

  • 利用@Binding实现SwiftUI与UIKit组件的状态双向同步。
  • 通过PDFViewDelegate的滚动监听方法,实时检查当前页面位置和可见区域。
  • 设置10pt的误差阈值,避免因滚动时的微小偏移导致按钮状态频繁切换。

内容的提问来源于stack exchange,提问作者Konstantin.Efimenko

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.03 11:46:40