iOS PDFKit在PDFView中调整pdf框架

Posted

技术标签:

【中文标题】iOS PDFKit在PDFView中调整pdf框架【英文标题】:iOS PDFKit adjust pdf frame in PDFView 【发布时间】:2020-09-04 12:55:18 【问题描述】:

我有一个 PDF,其中包含不同高度的页面,我想以水平分页的方式显示,一次一页,页面之间没有间隙,并且每页的顶部与视图的顶部对齐.例如:

我想使用PDFKitPDFView,尤其是因为这些设置可以通过以下方式实现:

let pdfView = PDFView()
pdfView.displayDirection = .horizontal
pdfView.displaysPageBreaks = false
pdfView.usePageViewController(true, withViewOptions: nil)

但是,这会产生以下结果:

这是由于页面高度不同造成的。每个页面在PDFView 中垂直居中,如果它的页面高度大于视图的高度(例如第 2 页),则会进行纵横比缩放以适应。

为了尝试解决第一个问题,垂直偏移,我尝试了几件事。首先,这很恶心,我知道这是错误的,在检查视图层次结构并找到在其中呈现页面的私有视图(名为 PDFTextInputView 的类的视图)之后,我尝试将其框架的 origin.y 调整为 @ 987654331@ 每当最外层的滚动视图(另一个私有视图)滚动时。这是因为每当下一页或上一页滚动到视图中时,该页面都会呈现在视图的顶部。但是,一旦用户在该页面上进行捏合缩放,它的框架就会自动跳回居中。这种方法除了依赖私有视图层次结构外,根本行不通。

为了尝试解决“高页面问题”(第 2 页),我尝试在出现新页面时调整 PDFView 的比例因子。可悲的是,.PDFViewPageChanged 通知仅在滚动视图结束减速后触发,因此页面在滚动时被缩小,然后当我调整比例因子时它会跳转以适应屏幕的宽度.然后我转向.PDFViewVisiblePagesChanged,它会在下一页/上一页出现时触发(以及更多次,这很好),这与.PDFViewPageChanged有相同的问题。

我尝试过的其他事情:

调整文档视图上的transform 拦截捏合手势并调整文档视图的中心 创建我自己的页面控制器并为每页呈现一个 PDF 页面(不使用 pdfView.usePageViewController

有人对我如何实现我的目标有任何想法吗?

【问题讨论】:

【参考方案1】:

注意:此答案旨在帮助其他到达这里尝试解决类似问题的人。

自从苹果在 ios13 中引入后,我在 iOS12 中发现了一个讨厌的错误“拖到 隐藏”(苹果“https://developer.apple.com/design/human-interface-guidelines/ios/app-architecture/modality/”)。

如果目标是 iOS13 或更高版本,一切正常。

在 iOS12 中,可能是由于计算大小不同,(我猜..)pdf 呈现错误:某些内容向右移动并被剪掉。

一个肮脏的解决办法是不要打电话

self?.pdfView.autoScales = true

在 viewDidLoad 中,

但在加载每个 PDF 后等待一些毫秒并设置它:

 if #available(iOS 13.0, *) 
    // NADA.. go on..
 else
     self.pdfView.autoScales = false // disable it.
     self?.pdfView.alpha = 1



let pdf = load ....... 

self.pdfView.document = pdf

 if #available(iOS 13.0, *) 
        //nada..
         else 
            // hack for ios 12
            let when = DispatchTime.now() + 0.25
            DispatchQueue.main.asyncAfter(deadline: when, execute:  [weak self] in
                self?.pdfView.autoScales = true // hack for ios 12
                self?.pdfView.alpha = 1
            )
        
  

使用 alpha 防止查看尚未采用的 pdf。

【讨论】:

【参考方案2】:

我认为问题在于将 PDFView 添加到有约束的视图中。当我只使用 addSubview() 和用户正确的框架添加时,它不需要调用 setValue。

让 pdfView = PDFKit.PDFView(frame: self.view.bounds) pdfView.document = PDFKit.PDFDocument(url: url) pdfView.autoresizingMask = [.flexibleHeight, .flexibleWidth] view.addSubview(pdfView)

【讨论】:

【参考方案3】:

只需将 forceTopAlignment 设置为 true

例子:

lazy var pdfView: PDFView = 
    let pdf = PDFView()
    pdf.displayMode = .singlePageContinuous
    pdf.autoScales = true
    pdf.translatesAutoresizingMaskIntoConstraints = false
    pdf.setValue(true, forKey: "forcesTopAlignment")
    return pdf
()

我的答案与接受的答案有何不同?

pdfView 上没有可用的滚动视图属性。因此,您只需将值直接设置为 pdfView。

【讨论】:

【参考方案4】:

新黑客:

事实证明,在挖掘了更多私有 API(是的,这个解决方案仍然很糟糕)之后,我在 PDFScrollView(一个私有的内部视图)上完全忽略了这个神奇的属性,称为...... ?

? forcesTopAlignment ?

要启用此功能,请在您的 PDFView 中找到 PDFScrollView 并:

pdfScrollView.setValue(true, forKey: "forcesTopAlignment")

这就是诀窍!


老黑客:

在摸索了几天后,我终于想出了一个方法让PDFView 表现出我想要的样子。

披露:此解决方案使用方法调配并依赖于私有视图层次结构,并且随时可能中断。也就是说,它现在有效,我对解决方案感到满意。

完整的解决方案在this gist 中提供。 (肉在overrideCenterAlign。)

有一个名为_centerAlign 的私有方法,当pdf 页面出现在屏幕上以及通过捏合手势进行缩放时,它会垂直居中并缩放它们。 Swizzling 该方法允许我注入我自己的逻辑并应用我自己的转换来定位我想要的 pdf 视图(页面顶部与视图顶部对齐。)

有两种情况需要考虑。 “短页”案例(示例中的第 1、3、4 页)和“高页”案例(示例中的第 2 页)。在这两种情况下,我首先调用 _centerAlign 的原始实现,以便它可以应用其转换并管理更新内部滚动视图。

对于“短页”情况,我应用了相同的转换和垂直平移,以将 pdf 的顶部与视图的顶部对齐。 对于“长页面”情况,我调整了内部滚动视图在屏幕上的缩放比例,以适应视图的宽度。

综上所述,我对不依赖私有方法和视图层次结构的更简洁的解决方案持开放态度。如果您知道实现此目的的更好方法,请发布答案!

【讨论】:

以上是关于iOS PDFKit在PDFView中调整pdf框架的主要内容,如果未能解决你的问题,请参考以下文章

如何在 iOS、PDFKit、swift 中获取 pdf 页面的准确 X 和 Y 原点值

我可以在 iOS 11 中通过 Storyboard 添加 PDFView

如何在 ios 13 中禁用 pdfkit pdfview 中的查找、共享、转发菜单项

iOS PDFKit不会写

使用 PDFKit 打印 PDF。(目标 C)

如何知道用户何时在 PDFKit 的 PDFView 中滑动到下一页?