You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.15 03:01:22