iOS中UIAlertController为顶层控制器时,如何通过代码截取应用屏幕?
解决iOS截取含UIAlertController弹窗的屏幕问题
原代码的问题在于:UIAlertController的弹窗并非嵌套在顶层控制器的view层级中,而是直接附加在应用的**主窗口(keyWindow)**上。所以只渲染顶层控制器的view,只能捕获弹窗本身或者底层页面,无法同时获取两者。
要实现包含弹窗且不含状态栏的全屏截取,直接从主窗口入手即可,以下是修改后的代码:
extension UIViewController { static func takeScreenshotWithoutStatusBar() -> UIImage? { // 兼容iOS 13+多场景,获取当前活跃的主窗口 let window: UIWindow? if #available(iOS 13.0, *) { window = UIApplication.shared.connectedScenes .filter { $0.activationState == .foregroundActive } .compactMap { $0 as? UIWindowScene } .first? .windows .first(where: { $0.isKeyWindow }) } else { window = UIApplication.shared.keyWindow } guard let mainWindow = window else { return nil } // 计算不含状态栏的区域 var captureBounds = mainWindow.bounds let statusBarHeight: CGFloat if #available(iOS 13.0, *) { statusBarHeight = mainWindow.windowScene?.statusBarManager?.statusBarFrame.height ?? 0 } else { statusBarHeight = UIApplication.shared.statusBarFrame.height } // 下移起始点并缩短高度,排除状态栏 captureBounds.origin.y += statusBarHeight captureBounds.size.height -= statusBarHeight UIGraphicsBeginImageContextWithOptions(captureBounds.size, false, UIScreen.main.scale) defer { UIGraphicsEndImageContext() } guard let context = UIGraphicsGetCurrentContext() else { return nil } // 偏移上下文坐标,确保只捕获目标区域 context.translateBy(x: -captureBounds.origin.x, y: -captureBounds.origin.y) // 渲染整个窗口的内容,包含所有层级(弹窗、页面等) mainWindow.layer.render(in: context) return UIGraphicsGetImageFromCurrentImageContext() } }
代码说明:
- 窗口获取:适配iOS 13+的多场景机制,确保拿到当前前台活跃的keyWindow,避免在多场景应用中取错窗口
- 区域调整:通过计算状态栏高度,精准截取窗口中除状态栏外的部分
- 全层级渲染:直接渲染主窗口的layer,所有挂载在窗口上的UI元素(包括UIAlertController弹窗、悬浮视图等)都会被包含在截图中
如果需要截取包含状态栏的完整屏幕,只需要移除captureBounds的调整代码,直接使用mainWindow.bounds即可。
内容的提问来源于stack exchange,提问作者Rehan Ali Khan
相关产品推荐
相关产品推荐

