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

如何获取.widget类型.text子类型PDFAnnotation内的textView并实现交互?

我之前做PDF编辑功能时刚好碰到过这个需求,折腾了一阵终于搞定了,分享下可行的实现方案,完全能达到iOS原生编辑文本注释的效果~

核心思路

PDFKit在你把.widget类型+.text子类型的注释添加到PDFPage后,会自动在PDFView中生成对应的UITextView控件,但这个控件并没有直接暴露给我们。所以我们的目标就是:找到这个隐藏的UITextView,让它成为第一响应者(弹出键盘),或者选中文本。

具体实现步骤

1. 先创建并添加文本注释

首先是常规的创建和添加注释的代码:

// 定义注释的位置和大小
let textAnnotationBounds = CGRect(x: 80, y: 150, width: 250, height: 45)
// 创建.widget类型的文本注释
let textAnnotation = PDFAnnotation(bounds: textAnnotationBounds, 
                                  forType: .widget, 
                                  withProperties: nil)
// 设置子类型为文本输入
textAnnotation.widgetFieldType = .text
// 设置初始文本
textAnnotation.contents = "点击编辑我"

// 添加到目标PDFPage(这里假设你已经获取到pdfPage实例)
pdfPage.addAnnotation(textAnnotation)

2. 找到对应注释的UITextView

PDFView添加注释后需要一点时间渲染对应的UI控件,我们可以通过两种方式来捕获这个时机:

方式一:监听PDFView的注释添加通知(推荐)

注册PDFViewAnnotationAddedNotification,这样能精准捕获注释被添加到PDFView的时刻:

// 在视图初始化时注册通知
NotificationCenter.default.addObserver(self, 
                                     selector: #selector(handleTextAnnotationAdded(_:)), 
                                     name: .PDFViewAnnotationAdded, 
                                     object: yourPDFView)

// 处理通知的方法
@objc private func handleTextAnnotationAdded(_ notification: Notification) {
    // 先判断是不是我们要找的文本注释
    guard let annotation = notification.userInfo?["PDFAnnotationNotificationKey"] as? PDFAnnotation,
          annotation.type == .widget,
          annotation.widgetFieldType == .text else {
        return
    }

    // 切换到主线程操作UI
    DispatchQueue.main.async { [weak self] in
        guard let self = self, let pdfView = self.yourPDFView else { return }
        
        // 递归遍历PDFView的子视图,找到对应注释的UITextView
        func findTargetTextView(for annotation: PDFAnnotation, in view: UIView) -> UITextView? {
            for subview in view.subviews {
                // 通过KVC访问私有属性,判断当前子视图是否对应目标注释
                if let widgetView = subview as? NSObject,
                   let attachedAnnotation = widgetView.value(forKey: "annotation") as? PDFAnnotation,
                   attachedAnnotation == annotation {
                    // 尝试直接获取textView(私有属性)
                    if let textView = widgetView.value(forKey: "textView") as? UITextView {
                        return textView
                    }
                    // 备用方案:遍历子视图找UITextView
                    return subview.subviews.first(where: { $0 is UITextView }) as? UITextView
                }
                // 递归查找子视图
                if let foundTextView = findTargetTextView(for: annotation, in: subview) {
                    return foundTextView
                }
            }
            return nil
        }

        // 找到textView后激活它
        if let targetTextView = findTargetTextView(for: annotation, in: pdfView) {
            // 弹出键盘
            targetTextView.becomeFirstResponder()
            // 可选:自动选中所有文本,和原生编辑行为一致
            targetTextView.selectedTextRange = targetTextView.textRange(from: targetTextView.beginningOfDocument, to: targetTextView.endOfDocument)
        }
    }
}

方式二:延迟执行(简单但不够精准)

如果不想监听通知,也可以在添加注释后延迟一小段时间再查找控件(适合快速测试):

// 添加注释后延迟0.1秒执行(时间可根据实际情况调整)
DispatchQueue.main.asyncAfter(deadline: .now() + 0.1) { [weak self] in
    guard let self = self, let pdfView = self.yourPDFView else { return }
    // 调用上面的findTargetTextView函数查找并激活,代码和上面一致
    if let targetTextView = self.findTargetTextView(for: textAnnotation, in: pdfView) {
        targetTextView.becomeFirstResponder()
        targetTextView.selectedTextRange = targetTextView.textRange(from: targetTextView.beginningOfDocument, to: targetTextView.endOfDocument)
    }
}

3. 注意事项

  • 主线程操作:所有UI相关的操作必须在主线程执行,避免崩溃。
  • 私有API兼容:这里用到了KVC访问PDFKit的私有属性(annotation和textView),虽然在大多数iOS版本中都稳定,但苹果可能在后续版本中修改这些属性名,建议做好兼容性判断(比如用if let而非强制解包)。
  • 移除通知观察者:在视图销毁时记得移除通知观察者,避免内存泄漏:
deinit {
    NotificationCenter.default.removeObserver(self)
}

这样实现后,添加文本注释后就会自动弹出键盘,并且可以直接编辑,完全和iOS原生编辑截图/PDF文本注释的行为一致~

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.25 07:25:55