You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

如何通过代码在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

火山引擎 最新活动