iOS Snapshot API 行为异常变更:iOS17截图无法捕获键盘
iOS 17 截图无法包含键盘的问题解决
需求是实现截取屏幕并转换为图片,且包含显示中的键盘,核心逻辑为点击按钮后截取屏幕,缩小一半后置于左上角。以下是最小复现代码:
import UIKit class ViewController: UIViewController { func takeSnapshot() -> UIView { let screen = UIScreen.main let snapshot = screen.snapshotView(afterScreenUpdates: true) UIGraphicsBeginImageContextWithOptions(view.frame.size, false, screen.scale) snapshot.drawHierarchy(in: snapshot.bounds, afterScreenUpdates: true) let image = UIGraphicsGetImageFromCurrentImageContext()! UIGraphicsEndImageContext() let imageView = UIImageView(frame: CGRect(x: 0, y: 0, width: view.frame.width/2, height: view.frame.height/2)) imageView.image = image return imageView } @objc func buttonPressed() { let snapshot = takeSnapshot() view.addSubview(snapshot) DispatchQueue.main.asyncAfter(deadline: .now() + 3) { snapshot.removeFromSuperview() } } override func viewDidLoad() { super.viewDidLoad() let gradient = CAGradientLayer() gradient.frame = view.bounds gradient.colors = [UIColor.green.cgColor, UIColor.red.cgColor] view.layer.insertSublayer(gradient, at: 0) let textField = UITextField(frame: CGRect(x: 100, y: 100, width: 100, height: 100)) textField.backgroundColor = .red textField.text = "Text Field" view.addSubview(textField) DispatchQueue.main.async { textField.becomeFirstResponder() } let button = UIButton(frame: CGRect(x: 100, y: 200, width: 100, height: 100)) button.setTitle("Button", for: .normal) button.backgroundColor = .red view.addSubview(button) button.addTarget(self, action: #selector(buttonPressed), for: .touchUpInside) } }
这段代码在iOS 16中运行正常,左上角的截图能完整包含键盘;但在iOS 17中,截图里无法显示键盘。调试发现两个系统均使用独立的键盘场景,但iOS 17的场景机制存在细微变化,导致原方法无法捕获键盘内容。
解决方案
修改takeSnapshot函数,遍历所有已连接的UIWindowScene并绘制每个窗口的层级,以此捕获包括键盘在内的所有屏幕内容:
func takeSnapshot() -> UIView { let screen = UIScreen.main let scale = screen.scale let size = view.bounds.size UIGraphicsBeginImageContextWithOptions(size, false, scale) // 遍历所有关联的窗口场景,包含键盘所在的独立场景 for scene in UIApplication.shared.connectedScenes { guard let windowScene = scene as? UIWindowScene else { continue } for window in windowScene.windows { window.drawHierarchy(in: window.bounds, afterScreenUpdates: true) } } let image = UIGraphicsGetImageFromCurrentImageContext()! UIGraphicsEndImageContext() let imageView = UIImageView(frame: CGRect(x: 0, y: 0, width: size.width/2, height: size.height/2)) imageView.image = image return imageView }
原因说明
iOS 17中系统将键盘放置在独立的UIWindowScene实例中,原代码仅通过UIScreen.snapshotView获取主场景的快照,无法覆盖键盘所在的独立场景。通过遍历所有已连接的UIWindowScene并绘制每个窗口的层级,就能完整捕获屏幕上的所有可见内容,包括键盘。
内容的提问来源于stack exchange,提问作者OMGPOP
相关产品推荐
相关产品推荐

