I need to execute a code before the device's interface starts rotating but I can't seem to find any viable solution.
I came across UIDevice.orientationDidChangeNotification
but couldn't find anything like that to be notified that an orientation change will start.
I tried creating an UIViewControllerRepresentable
with a custom UIViewController
that overrides func viewWillTransition(to size: CGSize, with coordinator: UIViewControllerTransitionCoordinator)
, but that function doesn't get invoked at all (I didn't forget to propagate it using super).
Any idea?
EDIT: Needs support for iOS 15.0+
EDIT 2: This is needed in a SwiftUI app (so not UIKit)
If you create a regular UIViewController
that post
's a Notification
you can onReceive
the notification after you subscribe
.
import SwiftUI
struct TransitionNotificationView: View {
typealias SizeData = TransitionVM.SizeData
var body: some View {
Text("Hello, World!")
.subscribeToTransition() //subscribe
.onReceive(NotificationCenter.default.publisher(for: .willTransitionSize), perform: { notification in
guard let object = notification.object as? SizeData else {return}
print("received size Transision \(object.size.debugDescription)")
})
}
}
#Preview {
TransitionNotificationView()
}
The code behind this is pretty standard.
extension View {
func subscribeToTransition() -> some View {
modifier(TransitionVM())
}
}
struct TransitionVM: ViewModifier {
typealias TraitData = Transition_UI.TraitData
typealias SizeData = Transition_UI.SizeData
func body(content: Content) -> some View {
content.background(Transition_UI().frame(width: 0, height: 0))
}
struct Transition_UI: UIViewControllerRepresentable {
typealias TraitData = (newCollection: UITraitCollection, coordinator: UIViewControllerTransitionCoordinator)
typealias SizeData = (size: CGSize, coordinator: UIViewControllerTransitionCoordinator)
func makeUIViewController(context: Context) -> some UIViewController {
TransitionVC(nibName: nil, bundle: nil)
}
func updateUIViewController(_ uiViewController: UIViewControllerType, context: Context) {
}
class TransitionVC: UIViewController {
///UIKit calls this method before changing the size of a presented view controller’s view.
override func viewWillTransition(to size: CGSize, with coordinator: UIViewControllerTransitionCoordinator) {
print(#function)
super.viewWillTransition(to: size, with: coordinator)
NotificationCenter.default.post(name: .willTransitionSize, object: (size, coordinator))
}
///UIKit calls this method before changing the current object’s **traits**
override func willTransition(to newCollection: UITraitCollection, with coordinator: UIViewControllerTransitionCoordinator) {
super.willTransition(to: newCollection, with: coordinator)
print(#function)
NotificationCenter.default.post(name: .willTransitionTrait, object: (newCollection, coordinator))
}
}
}
}
extension Notification.Name {
static let willTransitionTrait = Notification.Name("willTransitionTrait")
static let willTransitionSize = Notification.Name("willTransitionSize")
}