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

SwiftUI中如何在界面方向变更前执行代码?

解决SwiftUI中设备旋转前执行代码的问题

针对iOS15+的SwiftUI应用,你可以通过以下两种可行方案实现旋转前的代码执行:

方案一:用UIViewController容器托管SwiftUI内容(推荐)

之前你的viewWillTransition没被调用,大概率是因为自定义UIViewController没有成为SwiftUI内容的顶层托管容器,导致没接收到旋转事件。下面是正确的实现方式:

1. 定义监听旋转的ViewController

class RotationMonitorVC: UIViewController {
    // 旋转前的回调闭包
    var willRotateAction: (() -> Void)?
    
    override func viewWillTransition(to size: CGSize, with coordinator: UIViewControllerTransitionCoordinator) {
        super.viewWillTransition(to: size, with: coordinator)
        // 触发旋转前的代码
        willRotateAction?()
        
        // 如果需要和旋转动画同步执行操作,可用coordinator的方法
        coordinator.animate(alongsideTransition: { _ in
            // 这里放和旋转同步的动画逻辑
        }) { _ in
            // 旋转完成后的收尾操作
        }
    }
}

2. 实现UIViewControllerRepresentable容器

这个容器会把你的SwiftUI内容嵌入到上面的自定义VC中,确保旋转事件能被捕获:

struct RotationContainer<Content: View>: UIViewControllerRepresentable {
    let content: Content
    let onWillRotate: () -> Void
    
    func makeUIViewController(context: Context) -> RotationMonitorVC {
        let vc = RotationMonitorVC()
        vc.willRotateAction = onWillRotate
        
        // 将SwiftUI内容包装成UIHostingController并添加到自定义VC中
        let hostingVC = UIHostingController(rootView: content)
        hostingVC.view.translatesAutoresizingMaskIntoConstraints = false
        
        vc.addChild(hostingVC)
        vc.view.addSubview(hostingVC.view)
        
        // 约束铺满整个视图
        NSLayoutConstraint.activate([
            hostingVC.view.topAnchor.constraint(equalTo: vc.view.topAnchor),
            hostingVC.view.leadingAnchor.constraint(equalTo: vc.view.leadingAnchor),
            hostingVC.view.trailingAnchor.constraint(equalTo: vc.view.trailingAnchor),
            hostingVC.view.bottomAnchor.constraint(equalTo: vc.view.bottomAnchor)
        ])
        
        hostingVC.didMove(toParent: vc)
        return vc
    }
    
    func updateUIViewController(_ uiViewController: RotationMonitorVC, context: Context) {
        // 更新SwiftUI内容(如果内容有变化)
        if let hostingVC = uiViewController.children.first as? UIHostingController<Content> {
            hostingVC.rootView = content
        }
    }
}

3. 在SwiftUI中使用容器

把你的主内容视图放到这个容器里,即可监听旋转事件:

struct MainView: View {
    var body: some View {
        RotationContainer(content: {
            // 你的实际内容视图
            VStack {
                Text("当前方向: \(UIDevice.current.orientation.rawValue)")
                    .font(.title)
            }
            .frame(maxWidth: .infinity, maxHeight: .infinity)
            .background(Color.white)
        }, onWillRotate: {
            // 这里写旋转前要执行的代码
            print("设备即将旋转,执行预处理逻辑")
        })
    }
}

方案二:监听系统旋转通知(快速实现)

如果不需要和旋转动画同步,也可以直接监听UIDevice.willRotateNotification,步骤更简单:

struct MainView: View {
    var body: some View {
        VStack {
            Text("Hello World")
                .font(.title)
        }
        .frame(maxWidth: .infinity, maxHeight: .infinity)
        .onAppear {
            // 开启设备方向通知监听
            UIDevice.current.beginGeneratingDeviceOrientationNotifications()
            NotificationCenter.default.addObserver(
                forName: UIDevice.willRotateNotification,
                object: nil,
                queue: .main
            ) { _ in
                // 旋转前执行代码
                print("即将旋转,执行操作")
            }
        }
        .onDisappear {
            // 移除监听,避免内存泄漏
            NotificationCenter.default.removeObserver(
                self,
                name: UIDevice.willRotateNotification,
                object: nil
            )
            UIDevice.current.endGeneratingDeviceOrientationNotifications()
        }
    }
}

注意事项

  • 确保你的App在Info.plist中配置了支持的屏幕方向(UISupportedInterfaceOrientations),否则旋转事件不会触发。
  • 方案一更适合需要和旋转动画同步操作的场景,方案二更适合简单的预处理逻辑。

内容的提问来源于stack exchange,提问作者Baffo rasta

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.08 01:57:44