求助:ViewController关闭后未触发viewWillAppear等方法的屏幕方向问题
Hey there, I’ve run into this exact orientation glitch before—super annoying when your landscape view controller gets stuck after dismissing a portrait modal! Let’s walk through several reliable solutions to catch that dismiss event and fix the screen direction issue:
Solution 1: Closure Callback (Cleanest for One-to-One Scenarios)
Add a closure property to your portrait modal view controller, then trigger it when the "Done" button is tapped. Your original landscape VC can define the orientation fix logic in this closure when presenting the modal.
Code Example:
Portrait Modal VC
class PortraitModalVC: UIViewController { // Define a closure to notify dismiss events var onDismiss: (() -> Void)? @IBAction func doneButtonTapped(_ sender: UIButton) { dismiss(animated: true) { // Call the closure after dismissal completes self.onDismiss?() } } }
Original Landscape VC
class LandscapeVC: UIViewController { func presentPortraitModal() { let modalVC = PortraitModalVC() modalVC.onDismiss = { [weak self] in guard let self = self else { return } // Force landscape orientation UIDevice.current.setValue(UIInterfaceOrientation.landscapeLeft.rawValue, forKey: "orientation") // Trigger system to apply the rotation UIViewController.attemptRotationToDeviceOrientation() } present(modalVC, animated: true) } }
Pro tip: Use [weak self] to avoid memory leaks!
Solution 2: Delegate Pattern (Great for Reusable Modals)
If your portrait modal is used across multiple view controllers, a delegate protocol is more scalable. Define a delegate to notify dismissal events, then have your landscape VC conform to it.
Code Example:
Delegate Protocol & Modal VC
// Define the delegate protocol protocol PortraitModalDelegate: AnyObject { func modalDidFinishDismissing() } class PortraitModalVC: UIViewController { weak var delegate: PortraitModalDelegate? @IBAction func doneButtonTapped(_ sender: UIButton) { dismiss(animated: true) { self.delegate?.modalDidFinishDismissing() } } }
Landscape VC Conforming to Delegate
class LandscapeVC: UIViewController, PortraitModalDelegate { func presentPortraitModal() { let modalVC = PortraitModalVC() modalVC.delegate = self present(modalVC, animated: true) } // Implement delegate method to fix orientation func modalDidFinishDismissing() { UIDevice.current.setValue(UIInterfaceOrientation.landscapeRight.rawValue, forKey: "orientation") UIViewController.attemptRotationToDeviceOrientation() } }
Solution 3: iOS 13+ Presentation Controller Delegate (Most Robust)
For iOS 13 and later, use UIAdaptivePresentationControllerDelegate to catch dismissal events—this works even if the modal is dismissed via swipe-down (for sheet-style presentations) instead of just the "Done" button.
Code Example:
class LandscapeVC: UIViewController, UIAdaptivePresentationControllerDelegate { func presentPortraitModal() { let modalVC = PortraitModalVC() // Assign the delegate to the presentation controller modalVC.presentationController?.delegate = self present(modalVC, animated: true) } // Triggered when the modal is dismissed (any method) func presentationControllerDidDismiss(_ presentationController: UIPresentationController) { // Fix orientation here UIDevice.current.setValue(UIInterfaceOrientation.landscapeLeft.rawValue, forKey: "orientation") UIViewController.attemptRotationToDeviceOrientation() } }
Key Notes to Avoid Issues:
- Make sure your landscape VC’s
supportedInterfaceOrientationsreturns the correct landscape values (e.g.,.landscapeLeftor.landscapeRight). - The
UIDevice.setValueapproach is a widely accepted workaround—Apple rarely rejects apps for using it since it’s the standard way to force orientation changes. - Always use weak references (
weak self) in closures/delegates to prevent memory leaks.
内容的提问来源于stack exchange,提问作者Henry Zhang

