#方法 1: 使用 UIGraphicsImageRenderer
swift
func captureScreenArea(rect: CGRect) -> UIImage? {
// 获取主窗口
guard let window = UIApplication.shared.windows.first else { return nil }
// 创建渲染器(自动处理 Retina 缩放)
let renderer = UIGraphicsImageRenderer(bounds: rect)
return renderer.image { context in
// 将指定区域绘制到上下文
window.drawHierarchy(in: window.bounds, afterScreenUpdates: false)
}
}
// 使用示例
let captureRect = CGRect(x: 100, y: 200, width: 300, height: 200)
if let screenshot = captureScreenArea(rect: captureRect) {
UIImageWriteToSavedPhotosAlbum(screenshot, nil, nil, nil) // 保存到相册
}
#方法 2: 使用 drawHierarchy
swift
func captureViewArea(view: UIView, rect: CGRect) -> UIImage? {
// 创建临时绘图上下文
UIGraphicsBeginImageContextWithOptions(rect.size, false, 0.0)
defer { UIGraphicsEndImageContext() } // 确保上下文关闭
// 转换坐标系(视图坐标系 → 图像坐标系)
let drawingRect = CGRect(
x: -rect.origin.x,
y: -rect.origin.y,
width: view.bounds.width,
height: view.bounds.height
)
// 渲染指定区域
let success = view.drawHierarchy(in: drawingRect, afterScreenUpdates: false)
guard success, let image = UIGraphicsGetImageFromCurrentImageContext() else {
return nil
}
// 裁剪到目标区域
guard let cgImage = image.cgImage?.cropping(to: CGRect(
origin: .zero,
size: rect.size
)) else { return nil }
return UIImage(cgImage: cgImage)
}
// 使用示例(截取某个子视图的区域)
let targetView = UIView(frame: CGRect(x: 50, y: 100, width: 200, height: 150))
if let screenshot = captureViewArea(view: targetView, rect: CGRect(x: 20, y: 30, width: 100, height: 80)) {
// 使用截图...
}
#方法 3: 使用 CALayer
渲染(底层方法)
swift
func captureLayerArea(layer: CALayer, rect: CGRect) -> UIImage? {
// 创建位图上下文
UIGraphicsBeginImageContextWithOptions(rect.size, false, UIScreen.main.scale)
defer { UIGraphicsEndImageContext() }
guard let context = UIGraphicsGetCurrentContext() else { return nil }
// 调整上下文坐标系
context.translateBy(x: -rect.origin.x, y: -rect.origin.y)
// 渲染图层内容
layer.render(in: context)
return UIGraphicsGetImageFromCurrentImageContext()
}
// 使用示例(截取特定图层的区域)
let targetLayer = CALayer()
targetLayer.frame = CGRect(x: 0, y: 0, width: 400, height: 300)
if let screenshot = captureLayerArea(layer: targetLayer, rect: CGRect(x: 50, y: 50, width: 200, height: 200)) {
// 处理截图...
}
方法 | 优点 | 缺点 | 适用场景 |
---|---|---|---|
UIGraphicsImageRenderer |
自动处理缩放,代码简洁 | 支持 iOS 10+ | iOS 10+ |
drawHierarchy |
兼容旧系统,支持实时渲染 | 需要手动处理坐标系 | 需要兼容 iOS 7+ 的项目 |
CALayer 渲染 |
底层控制,性能最优 | 无法捕获 OpenGL/Vulkan 内容 | 游戏或高性能渲染 |
#扩展功能实现
1. 带安全区域的截图
swift
func safeAreaScreenshot() -> UIImage? {
guard let window = UIApplication.shared.windows.first else { return nil }
let safeArea = window.safeAreaInsets
let captureRect = CGRect(
x: safeArea.left,
y: safeArea.top,
width: window.bounds.width - safeArea.left - safeArea.right,
height: window.bounds.height - safeArea.top - safeArea.bottom
)
return captureScreenArea(rect: captureRect)
}
2. 延时截图(解决渲染未完成问题)
less
func delayedCapture(rect: CGRect, delay: TimeInterval, completion: @escaping (UIImage?) -> Void) {
DispatchQueue.main.asyncAfter(deadline: .now() + delay) {
let screenshot = self.captureScreenArea(rect: rect)
completion(screenshot)
}
}
// 使用示例
delayedCapture(rect: CGRect(x: 0, y: 0, width: 200, height: 200), delay: 0.3) { image in
guard let image = image else { return }
// 处理截图...
}
3. 拼接多个区域
swift
func combineScreenshots(rects: [CGRect]) -> UIImage? {
guard !rects.isEmpty else { return nil }
// 计算总区域
let totalRect = rects.reduce(CGRect.null) { $0.union($1) }
let renderer = UIGraphicsImageRenderer(bounds: totalRect)
return renderer.image { context in
for rect in rects {
if let image = captureScreenArea(rect: rect) {
image.draw(in: rect)
}
}
}
}