在 iOS 11 PDFKit 文档上实现墨迹注释

2024-02-07

我想允许用户在 PDFView 中查看的 iOS 11 PDFKit 文档上绘图。绘图最终应嵌入到 PDF 中。

我通过向 PDFPage 添加“ink”类型的 PDFAnnotation 以及与用户绘图相对应的 UIBezierPath 来解决后者。

但是,我如何实际记录用户在 PDFView 上进行的触摸以创建这样的 UIBezierPath?

我尝试过在 PDFView 和 PDFPage 上覆盖 TouchBegan,但它从未被调用。我尝试添加 UIGestureRecognizer,但没有完成任何任务。

我假设我之后需要使用 PDFView 实例方法 Convert(_ point: CGPoint, to page: PDFPage) 将获得的坐标转换为适合注释的 PDF 坐标。


最后我通过创建一个扩展 UIViewController 和 UIGestureRecognizerDelegate 的 PDFViewController 类解决了这个问题。我添加了一个 PDFView 作为子视图,并将一个 UIBarButtonItem 添加到 navigationItem,用于切换注释模式。

我将触摸记录在名为signingPath 的UIBezierPath 中,并使用以下代码将当前注释保存在PDFAnnotation 类型的currentAnnotation 中:

 override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
    if let touch = touches.first {
        let position = touch.location(in: pdfView)
        signingPath = UIBezierPath()
        signingPath.move(to: pdfView.convert(position, to: pdfView.page(for: position, nearest: true)!))
        annotationAdded = false
        UIGraphicsBeginImageContext(CGSize(width: 800, height: 600))
        lastPoint = pdfView.convert(position, to: pdfView.page(for: position, nearest: true)!)
    }
}

override func touchesMoved(_ touches: Set<UITouch>, with event: UIEvent?) {
    if let touch = touches.first {
        let position = touch.location(in: pdfView)
        let convertedPoint = pdfView.convert(position, to: pdfView.page(for: position, nearest: true)!)
        let page = pdfView.page(for: position, nearest: true)!
        signingPath.addLine(to: convertedPoint)
        let rect = signingPath.bounds

        if( annotationAdded ) {
            pdfView.document?.page(at: 0)?.removeAnnotation(currentAnnotation)
            currentAnnotation = PDFAnnotation(bounds: rect, forType: .ink, withProperties: nil)

            var signingPathCentered = UIBezierPath()
            signingPathCentered.cgPath = signingPath.cgPath
            signingPathCentered.moveCenter(to: rect.center)
            currentAnnotation.add(signingPathCentered)
            pdfView.document?.page(at: 0)?.addAnnotation(currentAnnotation)

        } else {
            lastPoint = pdfView.convert(position, to: pdfView.page(for: position, nearest: true)!)
            annotationAdded = true
            currentAnnotation = PDFAnnotation(bounds: rect, forType: .ink, withProperties: nil)
            currentAnnotation.add(signingPath)
            pdfView.document?.page(at: 0)?.addAnnotation(currentAnnotation)
        }
    }
}

override func touchesEnded(_ touches: Set<UITouch>, with event: UIEvent?) {
    if let touch = touches.first {
        let position = touch.location(in: pdfView)
        signingPath.addLine(to: pdfView.convert(position, to: pdfView.page(for: position, nearest: true)!))

        pdfView.document?.page(at: 0)?.removeAnnotation(currentAnnotation)

        let rect = signingPath.bounds
        let annotation = PDFAnnotation(bounds: rect, forType: .ink, withProperties: nil)
        annotation.color = UIColor(hex: 0x284283)
        signingPath.moveCenter(to: rect.center)
        annotation.add(signingPath)
        pdfView.document?.page(at: 0)?.addAnnotation(annotation)
    }
}

注释切换按钮刚刚运行:

pdfView.isUserInteractionEnabled = !pdfView.isUserInteractionEnabled

这确实是关键,因为这会禁用 PDF 上的滚动并使我能够接收触摸事件。

记录触摸事件并立即转换为 PDFAnnotation 的方式意味着注释在 PDF 上书写时可见,并且最终记录到 PDF 中的正确位置 - 无论滚动位置如何。

确保它最终出现在正确的页面上只需将页码的硬编码 0 更改为 pdfView.page(for:position,nearest:true) 值即可。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

在 iOS 11 PDFKit 文档上实现墨迹注释 的相关文章

  • 如何模拟应用程序在后台被杀死?

    我试图验证我的应用程序 App1 在启动另一个应用程序 App2 后被系统关闭时行为是否正确 有什么方法可以模拟或强制这种行为吗 在 App2 运行时告诉模拟器模拟内存警告不会执行任何操作 直到 App1 返回前台为止 从调试器中杀死 Ap
  • 当应用程序处于后台时,替代 UserNotificationCenter Delegate 的 willPresent

    我正在尝试弄清楚是否可以通过本地通知来实现我的目标 或者是否需要切换到远程通知 我正在练习 iOS 10 Swift 3 方法是构建一个闹钟程序 该程序在一天中的设定时间播放 RSS 更新的广播节目的最新一集 当应用程序位于前台时 可以通过
  • 以编程方式访问 Apple Notes 内容

    是否可以以编程方式访问Apple Notes 即macos和ios中预装的应用程序 内容 macOS 上的 Notes 可使用 AppleScript 编写脚本 要注销所有笔记 请打开脚本编辑器并使用以下内容创建一个新脚本 然后单击播放按钮
  • 当 SwiftUI 中列表数据源为空时,如何在视图中心显示文本消息?

    struct LandmarkList View var body some View NavigationView List landmarkData landmark in LandmarkRow landmark landmark 我
  • HTML 5 + iOS - 创建混合应用程序

    我正在尝试将我的本机 iOS 应用程序转换为使用 HTML 5 的混合应用程序 经过研究后我最终得到了jQuery 移动 phoneGap 我的问题是 是否可以将 html 5 和本机 iOS 功能混合在一个单一的版本中 看法 例如我可以使
  • Dropbox iOS SDK 始终为 isLinked 返回“YES”:

    我正在使用 iOS Dropbox SDK 想要检查我的应用程序是否已与 Dropbox 帐户链接 所以我这样做 if self isLinked NSLog linked However self isLinked总是返回YES 即使在清
  • 如何开发iPhone MDM服务器?

    我刚刚阅读了有关适用于 iOS 设备的移动设备管理服务器的信息 但所有文档均指 第三方 MDM 服务器 我的问题是如何自己开发一个 第三方 MDM 服务器 我找不到任何关于此的文档 你有简单的方法和困难的方法 Easy way OSX Li
  • Three20 和 iOS 6 不工作

    我刚刚尝试了我的一个项目 其中包含 Three20 但它似乎无法编译 给我构建错误 似乎是因为一些 UITouch 界面发生了变化 想知道是否有快速修复方法可以做到这一点 看来问题是在这里 UITouch ivars 已从 iOS 6 SD
  • 转换任何对象?到字符串

    我有一个返回 AnyObject 的函数 func aFunction param String gt AnyObject 如何将其转换为字符串 和字符串 尝试这个 if let result aFunction test as Strin
  • 在 flutter 应用程序中添加启动屏幕的正确方法是什么?

    我正在开发一个基于 flutter 的应用程序 并研究了几种添加闪屏的方法 但我不确定哪一个是最好实现的 import dart async import package flutter material dart import packa
  • 如何在 UIView 中获取父导航控制器

    我创建了一个UITabBarController在我的应用程序委托中 其中每个选项卡栏项目都有不同的UINavigationController加载自定义的UIViewController带NIB 使用 pushViewController
  • iOS Swift 多维数组 - 编译需要很长时间。我应该改变什么?

    我是斯威夫特的新人 以前从未使用过 ObjC 编程 我在使用 iOS 应用程序时遇到了问题 通过选择器查询数组非常简单 我有 4 个多维数组 如下所示 let Setting 0 0 0 0 0 0 2230 0 0 0 0 0 2230
  • iOS 版 Google 地图 SDK 中的热图

    有没有办法添加热图图层适用于 iOS 的 Google 地图 SDK https developers google com maps documentation ios 注意 我指的是存在于Javascript 版本的 Google 地图
  • “找不到开发者磁盘映像”

    最近我收到错误 找不到开发人员磁盘映像 我认为自从我将 iPhone 上的 iOS 更新到 9 1 后就会发生这种情况 如何解决该问题并使 Xcode 支持 iOS 9 1 设 备 Xcode 7 0 1 和 iOS 9 1 不兼容 您需要
  • 处理具有不同缩放/分辨率的所有 iPhone 中的 UI [重复]

    这个问题在这里已经有答案了 在 iOS 中处理 iPhone 4 iPhone 5 iPhone 6 iPhone 6 UI 屏幕的最佳方法是什么 iPhone 6 的尺寸 3 倍缩放 坐标空间 414 x 736 像素 iPhone 6
  • exc_bad_access 于 [NSDate timeIntervalSinceReferenceDate]

    我的行为很奇怪 NSDate timeIntervalSinceReferenceDate 我有以下功能 void insertRow NSTimeInterval timeNow NSDate timeIntervalSinceRefer
  • 具有自定义视图的相机

    我的应用程序使用相机 我想在相机预览上添加叠加层 例如 我想在使用相机时使用相框 还想添加一个用于相机操作的自定义栏 请帮助我做同样的事情 您可能正在尝试使用 UIImagePickerController 但我知道这个可以解决你的问题 您
  • 在 wkwebview 中启用摄像头和麦克风访问

    我有一个针对移动设备优化的网络应用程序 它利用getUserMedia访问网络摄像头和麦克风资源 我正在将这个应用程序包装在WKWebView因为我想提供原生应用程序体验 我知道 iOS 不允许通过浏览器访问相机 但是有什么方法可以使用本机
  • 苹果拒绝任何访问UDID的应用程序,不支持Retina、iPhone 5显示屏?

    得到消息来自TNW http thenextweb com apple 2013 03 21 after a year of warnings apple will no longer accept any apps that use ud
  • UIPopViewController 不工作

    我有一个 xib 文件 其中有 h 和 m 链接 在 xib 中有一个带有 textView 的 UIView 我想要对该视图执行的操作是 当您单击按钮时将其作为 UIPopViewController 打开 这是我的代码 IBAction

随机推荐

  • 谷歌地图最大缩放

    我想设置最大缩放级别以阻止在地图中的某个点之后进行缩放的可能性 var mapa obiekt globalny function dodajMarker opcjeMarkera opcjeMarkera map mapa var mar
  • Jquery UI 可排序 - 在启动事件触发之前执行操作

    我已经在 STACKOVERFLOW 和其他论坛中搜索了我的问题的解决方案 如果我错过了可行的解决方案 请指出它 我的问题 每当在可排序列表中拖动元素 Portlet div 时 我需要在实际拖动过程开始之前执行一些操作 根据我在 STAR
  • 如何在 Tkinter 中禁用(灰显)检查按钮?

    我不知道如何使 Tkinter 变灰Checkbutton 我尝试使用state DISABLED但它不起作用 我收到一条错误消息 tkinter TclError 错误选项 enable 必须是 column columnspan in
  • 如何访问父/兄弟模块方法

    有什么办法可以访问吗baz method inside class Qux没有从一开始就提到模块名称空间 当有很多嵌套模块时 代码看起来不干净 module Foo module Bar module Baz class Qux def s
  • Angular 2 - 使用 ng2-idle 注销

    我的问题是 当单击注销按钮时 ng2 idle 继续工作 为了尝试解决这个问题 我再次将 setIdle 和 setTimeout 函数设置为 1 秒 但是 当用户转移到登录屏幕时 应用程序需要 1 秒才能超时 我想知道在单击调用 logo
  • 如何在 Eclipse 中进行 git merge 压缩

    有时我需要从 Eclipse 合并南瓜 我知道我可以在命令行中完成此操作 但是在 Eclipse 中集成图形选项将非常有用 你知道该怎么做吗 您可以开始一个Egit 中的交互式变基 http wiki eclipse org EGit Us
  • 是否有可靠的工具可以在担任领班时单步执行代码

    我正在寻找一些关于类似于使用 binding pry 的工具的建议 我正在与 foreman 一起在本地提供 Rails 应用程序 并且希望实现相同的功能 将 调试器 放入我的代码中 当进程遇到该问题时 冻结并打开该代码部分中的控制台环境
  • 在 ASP.NET Core MVC 中使用 Tag Helpers 有什么好处

    我刚刚看到一篇关于 ASP NET Core 新功能的好文章 名为标签助手 http stephenwalther com archive 2015 02 24 top 10 changes in asp net 5 and mvc 6 从
  • 挂在 bootstrap 表中的 1000 或 5000 条记录上

    下面的链接给出了很好的例子 http issues wenzhixin net cn bootstrap table 但是 当分页大小从 10 更改为 1000 或 5000 时 浏览器会挂起超过 20 秒或一分钟才能填充网格 数据中的记录
  • 通过绑定新数据来操作元素

    我正在尝试弄清楚如何通过绑定新数据来更新一些 D3 js 元素 我实际上不确定这是否可能 但感觉应该是 首先我创建了四个 SVG 圆圈 并设置cx偏移量作为数据的函数 div div var svg d3 select div contai
  • 固定标题和固定列表

    我的固定标题和固定列表有问题 标题是固定的 但列不是 那么我该如何解决这个问题呢 我试图给第一列位置 固定 但它不能正常工作 如果可能的话 不用Javascript 我试图从同一主题的早期问题中找到解决方案 但这些都没有帮助我 这是我的Co
  • 如何以编程方式清除 Android 中的 DataStore 首选项和房间数据 [关闭]

    Closed 这个问题不符合堆栈溢出指南 help closed questions 目前不接受答案 我正在开发一个 Android 应用程序 当我按下按钮时 我需要以编程方式清除数据 包括数据存储首选项和房间数据 要清除共享首选项 Sha
  • 以显式意图启动 Android IntentService NullPointerException

    我正在尝试开始一个IntentService来自我主要活动中的点击处理程序 我正在学习Intents现在但还不太明白 我不确定我应该如何在这里实例化我的意图并将其传递给startService 我不知道为什么我必须做这样的事Intent据我
  • Flutter改变FloatingActionButton的子图标颜色

    我是新来的Flutter并试图更改 FloatingActionButton 的子图标颜色 子图标颜色默认为白色 我怎样才能改变它 下面给出的是我已经编写的代码 floatingActionButton new FloatingAction
  • 如何在java中从像素字节数组制作bmp图像

    我有一个字节数组 其中包含 bmp 文件中的像素值 它是通过这样做生成的 BufferedImage readImage ImageIO read new File fileName byte imageData DataBufferByt
  • 需要一种方法在 MAUI 的编辑器/输入字段中隐藏软键盘

    我发现此链接中似乎有用的内容 Xamarin Forms 中的键盘禁用了 Entry 控件 https theconfuzedsourcecode wordpress com 2017 05 19 a keyboard disabled e
  • 在spark(2.4及更高版本)中,如何完全“编辑”所有敏感信息

    在 py spark 2 4 中 可以从事件日志中编辑一些敏感信息 例如 config spark eventLog enabled true config spark eventLog dir hdfs tmp spark events
  • snort make 文件给出错误

    我在创建 snort makefile 时收到此错误消息 usr bin ld usr local lib libpcre a pcre compile o 制作共享对象时不能使用针对 gt rodata 的重定位 R X86 64 32S
  • 如何从 .usdz 创建 SCNNode?

    我已经下载了Apple提供的 usdz模型 https developer apple com arkit gallery https developer apple com arkit gallery 但现在 我想使用这些模型之一创建一个
  • 在 iOS 11 PDFKit 文档上实现墨迹注释

    我想允许用户在 PDFView 中查看的 iOS 11 PDFKit 文档上绘图 绘图最终应嵌入到 PDF 中 我通过向 PDFPage 添加 ink 类型的 PDFAnnotation 以及与用户绘图相对应的 UIBezierPath 来