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

iOS 17下Swift相机应用如何绕过竖屏锁定实现自动旋转?

在iOS 17中绕过系统竖屏锁定实现相机应用自由旋转

问题分析

iOS 16+版本中,系统全局竖屏锁定的优先级高于视图控制器的supportedInterfaceOrientations和shouldAutorotate设置,所以单纯重写这两个属性无法绕过锁定。要实现类似WhatsApp相机的效果,必须通过主动向系统请求界面几何更新的方式实现。

解决方案

通过UIWindowScene.requestGeometryUpdate(_:completionHandler:)方法主动请求界面方向变更,同时监听设备方向变化并适配相机预览层的方向。

1. 监听设备方向变化

在视图控制器的viewDidLoad中开启设备方向通知监听:

override func viewDidLoad() {
    super.viewDidLoad()
    
    // 开启设备方向通知
    UIDevice.current.beginGeneratingDeviceOrientationNotifications()
    NotificationCenter.default.addObserver(
        self,
        selector: #selector(deviceOrientationChanged),
        name: UIDeviceOrientationDidChangeNotification,
        object: nil
    )
}

2. 主动请求界面方向更新

实现方向变化的处理方法,通过windowScene请求更新界面方向:

@objc private func deviceOrientationChanged() {
    guard let windowScene = view.window?.windowScene else { return }
    let deviceOrientation = UIDevice.current.orientation
    
    // 过滤无效方向(未知、屏幕朝上/朝下)
    guard let targetInterfaceOrientation = deviceOrientation.toInterfaceOrientation(),
          targetInterfaceOrientation != .unknown else {
        return
    }
    
    // 向系统请求更新界面方向
    let orientationMask = UIInterfaceOrientationMask(rawValue: targetInterfaceOrientation.rawValue)
    windowScene.requestGeometryUpdate(.iOS(interfaceOrientations: orientationMask)) { error in
        if let error = error {
            print("方向更新请求失败: \(error.localizedDescription)")
        }
    }
    
    // 同步更新相机预览层方向
    updateCameraPreviewOrientation(for: targetInterfaceOrientation)
}

// 扩展:将UIDeviceOrientation转为UIInterfaceOrientation
extension UIDeviceOrientation {
    func toInterfaceOrientation() -> UIInterfaceOrientation? {
        switch self {
        case .portrait: return .portrait
        case .portraitUpsideDown: return .portraitUpsideDown
        case .landscapeLeft: return .landscapeRight
        case .landscapeRight: return .landscapeLeft
        default: return nil
        }
    }
}

3. 适配相机预览层方向

相机预览层AVCaptureVideoPreviewLayer不会自动跟随界面旋转,需要手动设置其视频方向:

// 假设你已经初始化了previewLayer(AVCaptureVideoPreviewLayer实例)
private var previewLayer: AVCaptureVideoPreviewLayer?

private func updateCameraPreviewOrientation(for orientation: UIInterfaceOrientation) {
    guard let previewLayer = previewLayer,
          let connection = previewLayer.connection,
          connection.isVideoOrientationSupported else {
        return
    }
    
    let videoOrientation: AVCaptureVideoOrientation
    switch orientation {
    case .portrait: videoOrientation = .portrait
    case .portraitUpsideDown: videoOrientation = .portraitUpsideDown
    case .landscapeLeft: videoOrientation = .landscapeLeft
    case .landscapeRight: videoOrientation = .landscapeRight
    default: videoOrientation = .portrait
    }
    
    connection.videoOrientation = videoOrientation
}

4. 清理资源

在视图控制器销毁时移除监听,避免内存泄漏:

deinit {
    UIDevice.current.endGeneratingDeviceOrientationNotifications()
    NotificationCenter.default.removeObserver(self)
}

注意事项

  • 该方案仅适用于iOS 16及以上版本(你的环境iOS 17完全兼容)
  • 无需额外权限,requestGeometryUpdate是系统公开API
  • 测试时需确保相机预览层已正确关联到AVCaptureSession

内容的提问来源于stack exchange,提问作者Ahmed rafaat

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.20 04:46:17