在 App 中集成 Live Text:让图片中的文字活起来
Add Live Text interaction to your app
2022年6月6日
一句话判断
Live Text API 只需要四个类就能让你的图片查看器支持文字选择、数据检测和 QR 码交互——几行代码就能获得系统级的视觉智能能力,不支持太浪费了。
这场 Session 讲了什么
iOS 15 引入了 Live Text 让用户在系统层面和图片中的文字交互。iOS 16 把这个能力开放给了所有开发者。API 非常简洁,只有四个核心类:ImageAnalyzer 执行异步分析,ImageAnalysis 存储分析结果,ImageAnalysisInteraction(iOS/macOS)或 ImageAnalysisOverlayView(macOS)提供交互层。
Session 通过一个实际的图片查看器 demo 展示了集成过程。只需要把 interaction 添加到 UIImageView,在图片加载后调用 analyzer,设置 .automatic 交互类型,就能让用户在图片中选择文字、点击电话号码拨打、点击地址打开地图、扫描 QR 码。整个过程不到 20 行有效代码。
API 还提供了精细的控制:你可以只开启文字选择(.textSelection),只开启数据检测(.dataDetectors),或者让系统自动决定(.automatic)。底部会出现一个 Live Text 按钮和 Quick Actions,你可以隐藏它们、调整 insets、自定义字体。
值得深挖的点
分析时机很重要。 ImageAnalyzer 利用 Neural Engine 做分析,效率很高,但你仍然需要在正确的时机触发。Session 明确建议:只在图片即将显示或已经显示在屏幕上时才开始分析。如果你的 app 有 timeline 这样的滚动列表,等滚动停止后再开始分析。在整个 app 中只共享一个 ImageAnalyzer 实例。这些细节决定了用户体验的流畅度。
手势冲突是需要留意的坑。 Live Text interaction 自带丰富的手势识别器,可能和你的 app 已有手势冲突。Session 提供了三种解决方案:实现 interactionShouldBeginAtPoint delegate 方法检查是否有可交互项目;在 gestureRecognizer 的 gestureRecognizerShouldBegin 中做类似检查;或者 override hitTest 返回正确的 view。如果你的 interaction 在有放大功能的 ScrollView 里,记得把坐标先转换到 window coordinate space 再转换到 interaction 的 view。
代码片段
完整的 Live Text 集成:
import UIKit
import VisionKit
class ImageViewController: UIViewController {
let analyzer = ImageAnalyzer() // 整个 app 共享一个
let interaction = ImageAnalysisInteraction()
override func viewDidLoad() {
super.viewDidLoad()
imageView.addInteraction(interaction) // 添加到承载图片的 view
}
func updateImage(_ newImage: UIImage) {
// 先重置旧的交互
interaction.preferredInteractionTypes = []
interaction.analysis = nil
Task {
let config = ImageAnalyzer.Configuration([.text, .machineReadableCode])
let analysis = try await analyzer.analyze(newImage, configuration: config)
// 确保图片没变
if let analysis = analysis, newImage == currentImage {
interaction.analysis = analysis
interaction.preferredInteractionTypes = .automatic
}
}
}
}
控制交互类型和自定义 UI:
// 只要文字选择,不要数据检测
interaction.preferredInteractionTypes = .textSelection
// 隐藏底部 Live Text 按钮,但保留文字选择功能
interaction.isSupplementaryInterfaceHidden = true
// 调整内容边距避免和你的 UI 重叠
interaction.contentInsets = NSDirectionalEdgeInsets(top: 0, leading: 0, bottom: 44, trailing: 0)
// 用自定义字体显示 Live Text 按钮
interaction.supplementaryInterfaceFont = .systemFont(ofSize: 14, weight: .medium)
处理手势冲突:
// 方法一:通过 delegate 控制交互是否开始
func interactionShouldBegin(at point: CGPoint) -> Bool {
// 如果有可交互的项目或有活跃的文字选择,允许交互
return interaction.hasInteractiveItem(at: point) || interaction.hasActiveTextSelection
}
// 方法二:在你的 gestureRecognizer delegate 中
func gestureRecognizerShouldBegin(_ gestureRecognizer: UIGestureRecognizer) -> Bool {
let point = gestureRecognizer.location(in: nil) // window 坐标
let convertedPoint = interaction.view?.convert(point, from: nil) ?? point
return !interaction.hasInteractiveItem(at: convertedPoint)
}
最佳实践
- 只创建一个 ImageAnalyzer 实例并在整个 app 中共享。
- 传入你手头最原始的图像类型,避免不必要的类型转换。如果碰巧有 CVPixelBuffer,直接用它——最高效。
- 如果你的图片 view 不是 UIImageView,实现
contentsRectForInteractiondelegate 方法,返回正确的 unit rect 来匹配图片的实际显示区域。 - 在 ScrollView 中的图片,把 interaction 放在 image view 上,不要放在 ScrollView 上。
- 对于视频帧分析,使用 AVPlayerLayer 的
currentlyDisplayedPixelBuffer——这是唯一保证能拿到正确帧的方式。
还有什么值得关注
- AVPlayerView 和 AVPlayerViewController 在 iOS 16 自动支持暂停帧的 Live Text,通过
allowsVideoFrameAnalysis属性控制(默认开启)。 - UITextField、UITextView、WebKit 和 Quick Look 已经自动支持 Live Text。
- Live Text 仅在配备 Apple Neural Engine 的设备上可用(iOS),macOS 13 上所有设备都支持。