如何通过代码在iOS中实现Instant Markup功能?含iOS 11截图场景
在iOS中通过代码实现Instant Markup功能
首先明确:iOS 11及以上系统确实支持通过代码调用和手动截图后一致的Instant Markup标记功能,下面分步骤给你两种可行的实现方案,你可以根据需求选择。
第一步:先捕获屏幕截图
不管哪种方案,你都需要先获取要标记的截图(如果已经有目标图片,可以跳过这一步)。用UIGraphicsImageRenderer是最简洁的方式:
func captureCurrentScreen() -> UIImage? { guard let keyWindow = UIApplication.shared.connectedScenes .filter({$0.activationState == .foregroundActive}) .compactMap({$0 as? UIWindowScene}) .first?.windows .filter({$0.isKeyWindow}).first else { return nil } let renderer = UIGraphicsImageRenderer(size: keyWindow.bounds.size) return renderer.image { context in keyWindow.drawHierarchy(in: keyWindow.bounds, afterScreenUpdates: true) } }
方案一:直接触发系统标记界面(快速简洁)
这种方式通过UIActivityViewController过滤出仅标记活动,直接进入标记界面,完成后可以保存为PDF或分享:
func presentInstantMarkup(for image: UIImage) { guard let imageData = image.pngData() else { return } let activityVC = UIActivityViewController(activityItems: [imageData], applicationActivities: nil) // 隐藏所有其他活动,只保留标记功能 activityVC.excludedActivityTypes = UIActivity.ActivityType.allCases.filter { $0 != .markupAsPDF } // 适配iPad的弹出位置 if let popoverPresentationController = activityVC.popoverPresentationController { popoverPresentationController.sourceView = self.view popoverPresentationController.sourceRect = CGRect(x: self.view.bounds.midX, y: self.view.bounds.midY, width: 0, height: 0) } self.present(activityVC, animated: true) }
方案二:模拟原生截图后的标记体验(更贴近手动操作)
如果你想要更接近手动截图后弹出预览+标记的体验,可以用QuickLook框架的QLPreviewController,启用编辑模式后就能调用原生标记工具:
首先导入QuickLook框架,然后创建一个自定义的预览控制器:
import QuickLook class ScreenshotMarkupController: QLPreviewController, QLPreviewControllerDataSource, QLPreviewControllerDelegate { private let targetImage: UIImage init(image: UIImage) { self.targetImage = image super.init(nibName: nil, bundle: nil) dataSource = self delegate = self allowsEditing = true // 关键:开启编辑/标记功能 } required init?(coder: NSCoder) { fatalError("init(coder:) has not been implemented") } // MARK: QLPreviewControllerDataSource func numberOfPreviewItems(in controller: QLPreviewController) -> Int { return 1 } func previewController(_ controller: QLPreviewController, previewItemAt index: Int) -> QLPreviewItem { // 将图片保存到临时目录,供QLPreviewController读取 let tempURL = FileManager.default.temporaryDirectory.appendingPathComponent("temp_screenshot.png") do { try targetImage.pngData()?.write(to: tempURL) } catch { print("保存临时图片失败:\(error.localizedDescription)") } return tempURL as QLPreviewItem } // 可选:处理标记完成后的回调 func previewController(_ controller: QLPreviewController, didSaveEditedPreviewItem previewItem: QLPreviewItem) { // 这里可以获取编辑后的文件,比如转成UIImage if let editedURL = previewItem as? URL { let editedImage = UIImage(contentsOfFile: editedURL.path) // 后续处理:保存到相册/上传等 } // 删除临时文件 try? FileManager.default.removeItem(at: previewItem as! URL) } }
然后在需要的地方调用:
if let screenshot = captureCurrentScreen() { let markupVC = ScreenshotMarkupController(image: screenshot) self.present(markupVC, animated: true) }
注意事项
- 以上方案仅支持iOS 11及以上系统,因为Instant Markup是iOS 11引入的功能
- 用
QLPreviewController时记得处理临时文件,避免占用设备存储空间 - iPad上需要配置
popoverPresentationController的弹出位置,否则会崩溃
内容的提问来源于stack exchange,提问作者Vinay_Kumar




