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

SwiftUI+PDFKit:隐藏导航栏时PDF内容上下偏移问题求助

解决SwiftUI+PDFKit导航栏切换时文档位移的问题

我用SwiftUI结合PDFKit开发阅读器,通过全屏弹窗展示文档,支持点击切换导航栏和状态栏的显隐,但切换时文档会跟着导航栏高度变化上下移动,导致无法点击文档链接且影响体验。

导航栏和状态栏显示状态
导航栏和状态栏隐藏状态

核心问题原因

NavigationView/NavigationStack在导航栏显隐时会自动调整内容区域的安全区Insets,导致PDFView的布局被重新计算,从而出现位移。要解决这个问题,需要让PDFView固定占据全屏,不受导航栏和安全区的影响。

解决方案步骤

1. 修正PDFKitView的布局实现

确保PDFView在UIKit层面固定铺满整个控制器视图,不受安全区约束:

import PDFKit
import SwiftUI

struct PDFKitView: UIViewControllerRepresentable {
    let url: URL
    
    func makeUIViewController(context: Context) -> PDFViewController {
        PDFViewController(url: url)
    }
    
    func updateUIViewController(_ uiViewController: PDFViewController, context: Context) {}
}

class PDFViewController: UIViewController {
    private let pdfView = PDFView()
    private let url: URL
    
    init(url: URL) {
        self.url = url
        super.init(nibName: nil, bundle: nil)
    }
    
    required init?(coder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }
    
    override func viewDidLoad() {
        super.viewDidLoad()
        
        pdfView.translatesAutoresizingMaskIntoConstraints = false
        view.addSubview(pdfView)
        
        // 强制PDFView铺满整个控制器视图,忽略所有安全区
        NSLayoutConstraint.activate([
            pdfView.topAnchor.constraint(equalTo: view.topAnchor),
            pdfView.leadingAnchor.constraint(equalTo: view.leadingAnchor),
            pdfView.trailingAnchor.constraint(equalTo: view.trailingAnchor),
            pdfView.bottomAnchor.constraint(equalTo: view.bottomAnchor)
        ])
        
        if let document = PDFDocument(url: url) {
            pdfView.document = document
            pdfView.autoScales = true
            pdfView.displayMode = .singlePageContinuous
            pdfView.displayDirection = .vertical
        }
    }
}

2. 调整SwiftUI页面布局

让PDFKitView忽略安全区,并关闭导航栏切换的动画,避免布局跳动:

struct PDFReaderView: View {
    @Environment(\.dismiss) var dismiss
    @State private var hideNavigationBar = false
    @State private var hideStatusBar = false
    
    let documentURL = Bundle.main.url(forResource: "PDFTest", withExtension: "pdf")!

    var body: some View {
        NavigationStack {
            PDFKitView(url: documentURL)
                .edgesIgnoringSafeArea(.all) // 让PDFView铺满全屏,不受SwiftUI安全区影响
                .onTapGesture {
                    withAnimation(.none) { // 关闭状态切换动画,消除布局跳动
                        hideNavigationBar.toggle()
                        hideStatusBar.toggle()
                    }
                }
                .toolbar {
                    ToolbarItemGroup(placement: .navigationBarLeading) {
                        Button(action: dismiss) {
                            Image(systemName: "xmark")
                        }
                    }
                }
                .navigationTitle("PDF Test")
                .navigationBarTitleDisplayMode(.inline)
                .navigationBarHidden(hideNavigationBar)
                .statusBarHidden(hideStatusBar)
        }
    }
}

兼容旧版本说明

如果需要兼容iOS 15及以下,将NavigationStack换回NavigationView,并保留导航视图样式:

NavigationView {
    // ... 其余内容不变
}
.navigationViewStyle(StackNavigationViewStyle())

效果说明

修改后,导航栏和状态栏的显隐切换不会再影响PDF文档的位置,文档始终固定在全屏区域,点击文档内的链接也能正常响应。

内容的提问来源于stack exchange,提问作者peres22

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.26 01:06:21