As of iOS 10 and 11, iPad supports Slide Over and Split View. To enable an app in Slide Over and Split View, Requires full screen
must be unchecked. That means the accepted answer cannot be used if the app wants to support Slide Over and Split View. See more from Apple's Adopting Multitasking Enhancements on iPad here.
I have a solution that allows (1) unchecking Requires full screen
, (2) just one function to be implemented in appDelegate
(especially if you don't want to / can't modify the target view controllers), and (3) avoid recursive calls. No need of helper class nor extensions.
appDelegate.swift (Swift 4)
func application(_ application: UIApplication,
supportedInterfaceOrientationsFor window: UIWindow?) -> UIInterfaceOrientationMask {
// Search for the visible view controller
var vc = window?.rootViewController
// Dig through tab bar and navigation, regardless their order
while (vc is UITabBarController) || (vc is UINavigationController) {
if let c = vc as? UINavigationController {
vc = c.topViewController
} else if let c = vc as? UITabBarController {
vc = c.selectedViewController
}
}
// Look for model view controller
while (vc?.presentedViewController) != nil {
vc = vc!.presentedViewController
}
print("vc = " + (vc != nil ? String(describing: type(of: vc!)) : "nil"))
// Final check if it's our target class. Also make sure it isn't exiting.
// Otherwise, system will mistakenly rotate the presentingViewController.
if (vc is TargetViewController) && !(vc!.isBeingDismissed) {
return [.portrait]
}
return [.all]
}
Edit
@bmjohns pointed out that this function is not called on iPad. I verified and yes it was not called. So, I did a bit more testing and found out some facts:
Requires full screen
because I want to enable Slide Over and Slide View on iPad. That requires the app to support all 4 orientation for iPad, in Info.plist: Supported interface orientations (iPad)
.My app works same way as Facebook: on iPhone, most of the time it is locked to portrait. When viewing image in full screen, allows users to rotate landscape for better view. On iPad, users can rotate to any orientation in any view controllers. So, the app looks nice when iPad is stand on Smart Cover (landscape left).
For iPad to call application(_:supportedInterfaceOrientationsFor)
, in Info.plist, only keep portrait for iPad. The app will lose Slide Over + Split View ability. But you can lock or unlock the orientation for any view controller, in just one place and no need to modify ViewController class.
Finally, this function get called on view controller's life cycle, when view is displayed/removed. If your app need to lock/unlock/change orientation in other time, it might not work