I am trying to rotate one view while all other views (5) are fixed to portrait. The reason is that in that one view I want the user to watch pictures which he saved before. I guess this is possible but so far I couldn't figure out how to achieve that. Can anyone help or give me a hint? I am programming that in Swift running on iOS8
Setting the app upWhen on the main screen, under the orientation section, you will see a number of options like 'Auto-rotate OFF', 'Auto-rotate ON', 'Forced Portrait' and 'Forced Landscape'. As the names suggest, you can use these buttons as one-tap shortcuts to toggle the orientation of your device.
For Android, open the AndroidManifest. xml file and within the activity element add 'android:screenOrientation="portrait"' to lock to portrait or 'android:screenOrientation="landscape"' to lock to landscape.
From ios 10.0 we need set { self. orientations = newValue } for setting up the orientation, Make sure landscape property is enabled in your project.
I'd recommend using supportedInterfaceOrientationsForWindow
in your appDelegate
to allow rotation only in that specific view controller, ex:
Swift 4/Swift 5
func application(_ application: UIApplication, supportedInterfaceOrientationsFor window: UIWindow?) -> UIInterfaceOrientationMask {
// Make sure the root controller has been set
// (won't initially be set when the app is launched)
if let navigationController = self.window?.rootViewController as? UINavigationController {
// If the visible view controller is the
// view controller you'd like to rotate, allow
// that window to support all orientations
if navigationController.visibleViewController is SpecificViewController {
return UIInterfaceOrientationMask.all
}
// Else only allow the window to support portrait orientation
else {
return UIInterfaceOrientationMask.portrait
}
}
// If the root view controller hasn't been set yet, just
// return anything
return UIInterfaceOrientationMask.portrait
}
Note that if that SpecificViewController
is in landscape before going to a portrait screen, the other view will still open in landscape. To circumvent this, I'd recommend disallowing transitions while that view is in landscape.
Swift 3
func application(application: UIApplication, supportedInterfaceOrientationsForWindow window: UIWindow?) -> Int {
// Make sure the root controller has been set
// (won't initially be set when the app is launched)
if let navigationController = self.window?.rootViewController as? UINavigationController {
// If the visible view controller is the
// view controller you'd like to rotate, allow
// that window to support all orientations
if navigationController.visibleViewController is SpecificViewController {
return Int(UIInterfaceOrientationMask.All.rawValue)
}
// Else only allow the window to support portrait orientation
else {
return Int(UIInterfaceOrientationMask.Portrait.rawValue)
}
}
// If the root view controller hasn't been set yet, just
// return anything
return Int(UIInterfaceOrientationMask.Portrait.rawValue)
}
You can also do it in a protocol oriented way. Just create the protocol
protocol CanRotate {
}
Add the the same 2 methods in the AppDelegate in a more "swifty" way
func application(_ application: UIApplication, supportedInterfaceOrientationsFor window: UIWindow?) -> UIInterfaceOrientationMask {
if topViewController(in: window?.rootViewController) is CanRotate {
return .allButUpsideDown
} else {
return .portrait
}
}
func topViewController(in rootViewController: UIViewController?) -> UIViewController? {
guard let rootViewController = rootViewController else {
return nil
}
if let tabBarController = rootViewController as? UITabBarController {
return topViewController(in: tabBarController.selectedViewController)
} else if let navigationController = rootViewController as? UINavigationController {
return topViewController(in: navigationController.visibleViewController)
} else if let presentedViewController = rootViewController.presentedViewController {
return topViewController(in: presentedViewController)
}
return rootViewController
}
And in every ViewController that you want a different behaviour, just add the protocol name in the definition of the class.
class ViewController: UIViewController, CanRotate {}
If you want any particular combination, they you can add to the protocol a variable to override
protocol CanRotate {
var supportedInterfaceOrientations: UIInterfaceOrientationMask
}
Sometimes when you're using a custom navigation flow (that may get really complex) the above-mentioned solutions may not always work. Besides, if you have several ViewControllers that need support for multiple orientations it may get quite tedious.
Here's a rather quick solution I found. Define a class OrientationManager
and use it to update supported orientations in AppDelegate:
class OrientationManager {
static var landscapeSupported: Bool = false
}
Then in AppDelegate put the orientations you want for that specific case:
func application(_ application: UIApplication, supportedInterfaceOrientationsFor window: UIWindow?) -> UIInterfaceOrientationMask {
if OrientationManager.landscapeSupported {
return .allButUpsideDown
}
return .portrait
}
Then in the ViewControllers that you want to have multiple navigations update the OrientationManager
:
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
OrientationManager.landscapeSupported = true
}
Also, don't forget to update it once again when you'll be exiting this ViewController:
override func viewWillDisappear(_ animated: Bool) {
super.viewWillDisappear(animated)
OrientationManager.landscapeSupported = false
//The code below will automatically rotate your device's orientation when you exit this ViewController
let orientationValue = UIInterfaceOrientation.portrait.rawValue
UIDevice.current.setValue(orientationValue, forKey: "orientation")
}
Hope this helps!
Update:
You may just want to add a static func
to your Orientation Support Manager
class:
static func setOrientation(_ orientation: UIInterfaceOrientation) {
let orientationValue = orientation.rawValue
UIDevice.current.setValue(orientationValue, forKey: "orientation")
landscapeSupported = orientation.isLandscape
}
Then you can call this function whenever you need to set the orientation back to portrait. That will also update the static landscapeSupported
value:
OSM.setOrientation(.portrait)
This is for Swift 4 and Swift 5. You can use the follow code in your AppDelegate.swift :
func application(_ application: UIApplication, supportedInterfaceOrientationsFor window: UIWindow?) -> UIInterfaceOrientationMask {
guard let rootViewController = self.topViewControllerWithRootViewController(rootViewController: window?.rootViewController),
(rootViewController.responds(to: Selector(("canRotate")))) else {
// Only allow portrait (standard behaviour)
return .portrait;
}
// Unlock landscape view orientations for this view controller
return .allButUpsideDown;
}
private func topViewControllerWithRootViewController(rootViewController: UIViewController!) -> UIViewController? {
guard rootViewController != nil else { return nil }
guard !(rootViewController.isKind(of: (UITabBarController).self)) else{
return topViewControllerWithRootViewController(rootViewController: (rootViewController as! UITabBarController).selectedViewController)
}
guard !(rootViewController.isKind(of:(UINavigationController).self)) else{
return topViewControllerWithRootViewController(rootViewController: (rootViewController as! UINavigationController).visibleViewController)
}
guard !(rootViewController.presentedViewController != nil) else {
return topViewControllerWithRootViewController(rootViewController: rootViewController.presentedViewController)
}
return rootViewController
}
You can then make a custom UIViewController rotate by overriding shouldAutorotate
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With