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
相关产品推荐
相关产品推荐

