Make only top ViewController rotate - ios

I have a question regarding the following. My app is mainly in portrait mode but for a few viewcontrollers, I want to make it rotatable to landscape mode. The code works perfectly for the topviewcontroller, the one that I want to make rotatable, but since it is a sort of image popup viewcontroller, you can also see the controller in the back also rotate. And I don't want that. I just want to make the popup viewcontroller rotatable. What can I do so that only the topviewcontroller rotates?
I already have the following code in AppDelegate:
func application(_ application: UIApplication, supportedInterfaceOrientationsFor window: UIWindow?) -> UIInterfaceOrientationMask {
if let rootViewController = self.topViewControllerWithRootViewController(rootViewController: window?.rootViewController) {
if (rootViewController.responds(to: Selector(("canRotate")))) {
return .allButUpsideDown;
}
}
return .portrait;
}
private func topViewControllerWithRootViewController(rootViewController: UIViewController!) -> UIViewController? {
if (rootViewController == nil) { return nil }
if (rootViewController.isKind(of: UITabBarController.self)) {
return topViewControllerWithRootViewController(rootViewController: (rootViewController as! UITabBarController).selectedViewController)
} else if (rootViewController.isKind(of: UINavigationController.self)) {
return topViewControllerWithRootViewController(rootViewController: (rootViewController as! UINavigationController).visibleViewController)
} else if (rootViewController.presentedViewController != nil) {
return topViewControllerWithRootViewController(rootViewController: rootViewController.presentedViewController)
}
return rootViewController
}
And in my viewcontrollers file:
#IBAction func didDismissButtonPress(sender: UIButton) {
self.dismiss(animated: true) { () -> Void in
UIDevice.current.setValue(Int(UIInterfaceOrientation.portrait.rawValue), forKey: "orientation")
}
}
In advance, thank you for your answer.

First go to Target's setting -> General Tab -> Deployment Info section, in device orientation select portrait, landscape left and landscape right. Now for your case in extension of your viewcontroller below pop,
extension BelowVC {
override var supportedInterfaceOrientations: UIInterfaceOrientationMask {
return UIInterfaceOrientationMask.portrait
}
}
Similarly you can restrict any of the VC's from rotating.

Related

How to rotate forcefully in my SDK VideoViewController to landscape orientation when app supports only portrait orientation in iOS Swift

am developing SDK for video player. But the problem is video auto rotation. When the app supports for both portrait and land scape it works fine. When app supports only portrait app then the auto rotation fails. How do i do the forceful .all orientation from SDK side.
One solution is by implementing func application(application: UIApplication, supportedInterfaceOrientationsForWindow window: UIWindow?) -> UIInterfaceOrientationMask in AppDelegate it will work.
One more solution is overriding shouldAutorotate(), supportedInterfaceOrientations() in my VideoViewController this works only when app too supports both(PORTRAIT and LANDSCAPE) orientation.
But in my case SDK needs to be handle the orientation, because am presenting the VideoViewController above any visible controller. and am not exposing my VideoViewController to app.
How can i achieve it.. Any solution.
If your project is already in portrait you won’t need to change anything. If not, make sure that only portrait is selected.
In Your AppDelegate add this:
func application(_ application: UIApplication, supportedInterfaceOrientationsFor window: UIWindow?) -> UIInterfaceOrientationMask {
if let rootViewController = self.topViewControllerWithRootViewController(rootViewController: window?.rootViewController) {
if let vcp = rootViewController as? ViewControllerRotateProtocol, vcp.canRotate() {
// Unlock landscape view orientations for this view controller
return [.landscapeLeft , .landscapeRight]
}
}
return application.supportedInterfaceOrientations(for: window)
}
private func topViewControllerWithRootViewController(rootViewController: UIViewController!) -> UIViewController? {
if (rootViewController == nil) { return nil }
if (rootViewController.isKind(of: UITabBarController.self)) {
return topViewControllerWithRootViewController(rootViewController: (rootViewController as! UITabBarController).selectedViewController)
} else if (rootViewController.isKind(of: UINavigationController.self)) {
return topViewControllerWithRootViewController(rootViewController: (rootViewController as! UINavigationController).visibleViewController)
} else if (rootViewController.presentedViewController != nil) {
return topViewControllerWithRootViewController(rootViewController: rootViewController.presentedViewController)
}
return rootViewController
}
Create one protocol: and you can expose this protocol to the app.
protocol ViewControllerRotateProtocol {
func canRotate() -> Bool
}
In Your View Controller, add this code:
class ViewController: UIViewController, ViewControllerRotateProtocol {
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
}
override func viewWillDisappear(_ animated : Bool) {
super.viewWillDisappear(animated)
if (self.isMovingFromParentViewController) {
UIDevice.current.setValue(Int(UIInterfaceOrientation.portrait.rawValue), forKey: "orientation")
}
}
override var shouldAutorotate: Bool {
return true
}
override var supportedInterfaceOrientations: UIInterfaceOrientationMask {
return [.landscapeLeft , .landscapeRight]
}
func canRotate() -> Bool {
return true
} }

Rotate totally Landscape view when movie play in VLCPlayer with swift 3

I would like to rotate my view controller when movie play.
My question might be duplicate but I tried many ways when I find in stack overflow. But all codes do not work. May be I put the codes in wrong way.
override var shouldAutorotate: Bool {
return false
}
override var supportedInterfaceOrientations: UIInterfaceOrientationMask {
//return[.portrait,.landscapeRight]
return .landscapeLeft
}
override var preferredInterfaceOrientationForPresentation: UIInterfaceOrientation {
//return UIInterfaceOrientation.landscapeRight
return .landscapeLeft
}
I put this code to vlcplayerviewcontroller.swift file.
When user clicks on play button, then it will goes to vlcplayerviewcontroller.swift and I would like to show the movie in Landscape mode automatically. I have no idea of how can I do this.
My reference link is How to lock orientation of one view controller to portrait mode only in Swift.
Allow only Portrait Device Orientation under project setting.
Add these lines into your AppDelegate file
func application(_ application: UIApplication, supportedInterfaceOrientationsFor window: UIWindow?) -> UIInterfaceOrientationMask {
if let rootViewController = self.topViewControllerWithRootViewController(rootViewController: window?.rootViewController) {
if (rootViewController.isKind(of: your_class_name_for_rotate.self)) {
// Unlock landscape view orientations for this view controller
return .allButUpsideDown;
}
}
// Only allow portrait (standard behaviour)
return .portrait;
}
private func topViewControllerWithRootViewController(rootViewController: UIViewController!) -> UIViewController? {
if (rootViewController == nil) { return nil }
if (rootViewController.isKind(of: UITabBarController.self)) {
return topViewControllerWithRootViewController(rootViewController: (rootViewController as! UITabBarController).selectedViewController)
} else if (rootViewController.isKind(of: UINavigationController.self)) {
return topViewControllerWithRootViewController(rootViewController: (rootViewController as! UINavigationController).visibleViewController)
} else if (rootViewController.presentedViewController != nil) {
return topViewControllerWithRootViewController(rootViewController: rootViewController.presentedViewController)
}
return rootViewController
}
Add this line in viewDidLoad method of your view_controller_for_rotate
let value = UIInterfaceOrientation.landscapeLeft.rawValue
UIDevice.current.setValue(value, forKey: "orientation")
And add these methods in same class
override func viewWillDisappear(_ animated: Bool) {
super.viewWillDisappear(animated)
UIDevice.current.setValue(Int(UIInterfaceOrientation.portrait.rawValue), forKey: "orientation")
}
private func supportedInterfaceOrientations() -> UIInterfaceOrientationMask {
return UIInterfaceOrientationMask.landscapeLeft
}
private func shouldAutorotate() -> Bool {
return true
}
I hope this helps.
I had a solution in the linked answer, but I adjusted for landscape. Follow these steps and it will give you the desired functionality.
Swift 3
In AppDelegate:
/// set orientations you want to be allowed in this property by default
var orientationLock = UIInterfaceOrientationMask.all
func application(_ application: UIApplication, supportedInterfaceOrientationsFor window: UIWindow?) -> UIInterfaceOrientationMask {
return self.orientationLock
}
In some other global struct or helper class, here I created AppUtility:
struct AppUtility {
static func lockOrientation(_ orientation: UIInterfaceOrientationMask) {
if let delegate = UIApplication.shared.delegate as? AppDelegate {
delegate.orientationLock = orientation
}
}
/// Added method to adjust lock and rotate to the desired orientation
static func lockOrientation(_ orientation: UIInterfaceOrientationMask, andRotateTo rotateOrientation:UIInterfaceOrientation) {
self.lockOrientation(orientation)
UIDevice.current.setValue(rotateOrientation.rawValue, forKey: "orientation")
}
}
Then in the desired ViewController you want to lock and rotate orientations, like your movie controller:
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
// rotate and lock
AppUtility.lockOrientation(.landscape, andRotateTo: .landscapeRight)
}
override func viewWillDisappear(_ animated: Bool) {
super.viewWillDisappear(animated)
// Don't forget to reset when view is being removed
AppUtility.lockOrientation(.all)
}

I want one Viewcontroller to be shown in landscape mode only

I'm currently working on an mobile Application which should be locked into Portrait mode only. As I can do this in my project settings it is not a problem, but I want one Viewcontroller to be shown in Landscape mode only.
I tried to disable to Portrait mode in the project settings and added this piece of code to my landscape view controller (and also the one which calls it, but with a portrait orientation):
let value = UIInterfaceOrientation.landscapeLeft.rawValue
UIDevice.current.setValue(value, forKey: "orientation")
UIViewController.attemptRotationToDeviceOrientation()
The problem I face right now is, that this solution is not optimal. The user is still able to rotate his the device. How can I fix this?
Try to lock the auto rotate
override var shouldAutorotate : Bool {
// Lock autorotate
return false
}
This worked before iOS10
viewdidload:
UIDevice.current.setValue(UIInterfaceOrientation.landscapeRight.rawValue, forKey: "orientation")
Also have this in the viewcontroller:
override var shouldAutorotate : Bool {
return true
}
override var supportedInterfaceOrientations : UIInterfaceOrientationMask {
return UIInterfaceOrientationMask.landscapeRight
}
override var preferredInterfaceOrientationForPresentation : UIInterfaceOrientation {
return UIInterfaceOrientation.landscapeRight
}
Below code will work fine.
func application(_ application: UIApplication, supportedInterfaceOrientationsFor window: UIWindow?) -> UIInterfaceOrientationMask {
if let rootViewController = self.topViewControllerWithRootViewController(rootViewController: window?.rootViewController) {
if (rootViewController.responds(to: Selector(("canRotate")))){
// Unlock landscape view orientations for this view controller
return .allButUpsideDown
}
}
// Only allow portrait (standard behaviour)
return .portrait
}
private func topViewControllerWithRootViewController(rootViewController: UIViewController!) -> UIViewController? {
if (rootViewController == nil) { return nil }
if (rootViewController.isKind(of: UITabBarController.self)) {
return topViewControllerWithRootViewController(rootViewController: (rootViewController as! UITabBarController).selectedViewController)
} else if (rootViewController.isKind(of: UINavigationController.self)) {
return topViewControllerWithRootViewController(rootViewController: (rootViewController as! UINavigationController).visibleViewController)
} else if (rootViewController.presentedViewController != nil) {
return topViewControllerWithRootViewController(rootViewController: rootViewController.presentedViewController)
}
return rootViewController}} .
//Add the below method in ViewController .
#objc func canRotate() -> Void {}

Swift - How to enable landscape in full screen video?

I am working on an iPhone(Swift) app and I have a WebView which loads a Youtube video and I would like to allow landscape mode only when the video is full screen. My whole app is portrait and rotation is disabled when the video is not playing in full screen. I don't want the user to be able to rotate the app to landscape when the youtube video is not in full screen, only when the video is playing in full screen.
I tried the following code, but it doesn't work.
override func supportedInterfaceOrientations() -> Int {
return Int(UIInterfaceOrientationMask.Portrait.rawValue)
}
supportedInterfaceOrientations was not such a reliable solution in my case as well. What I did was getting current view controller in app delegate application supportedInterfaceOrientationsForWindow method and checked if that controller was a view controller that supported all orientations so its return value was calculated based on this condition
func application(application: UIApplication, supportedInterfaceOrientationsForWindow window: UIWindow?) -> Int {
if let currentVC = getCurrentViewController(self.window?.rootViewController){
//VideoVC is the name of your class that should support landscape
if currentVC is VideoVC{
return Int(UIInterfaceOrientationMask.All.rawValue)
}
}
return Int(UIInterfaceOrientationMask.Portrait.rawValue)
}
func getCurrentViewController(viewController:UIViewController?)-> UIViewController?{
if let tabBarController = viewController as? UITabBarController{
return getCurrentViewController(tabBarController.selectedViewController)
}
if let navigationController = viewController as? UINavigationController{
return getCurrentViewController(navigationController.visibleViewController)
}
if let viewController = viewController?.presentedViewController {
return getCurrentViewController(viewController)
}else{
return viewController
}
}
I came across this problem recently and using Zell B.'s answer, here is a Swift 5 version that will detect an AVPlayer and update the orientation settings.
Just copy and paste the below code into your AppDelegate (no editing necessary):
func application(_ application: UIApplication, supportedInterfaceOrientationsFor window: UIWindow?) -> UIInterfaceOrientationMask {
if let currentVC = getCurrentViewController(self.window?.rootViewController), currentVC is AVPlayerViewController {
return .allButUpsideDown
}
return .portrait
}
func getCurrentViewController(_ viewController: UIViewController?) -> UIViewController? {
if let tabBarController = viewController as? UITabBarController {
return getCurrentViewController(tabBarController.selectedViewController)
}
if let navigationController = viewController as? UINavigationController{
return getCurrentViewController(navigationController.visibleViewController)
}
if let viewController = viewController?.presentedViewController {
return getCurrentViewController(viewController)
}
return viewController
}

Rotation only in one ViewController

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
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
With everyone's ideas I wrote the most elegant way to do it I think.
Result:
func application(_ application: UIApplication, supportedInterfaceOrientationsFor window: UIWindow?) -> UIInterfaceOrientationMask {
return (UIApplication.getTopViewController() as? Rotatable == nil) ? .portrait : .allButUpsideDown
}
Add this extension to your project which will always be useful not only for this:
extension UIApplication {
class func getTopViewController(base: UIViewController? = UIApplication.shared.keyWindow?.rootViewController) -> UIViewController? {
if let nav = base as? UINavigationController {
return getTopViewController(base: nav.visibleViewController)
}
if let tab = base as? UITabBarController {
if let selected = tab.selectedViewController {
return getTopViewController(base: selected)
}
}
if let presented = base?.presentedViewController {
return getTopViewController(base: presented)
}
return base
}
}
Create the protocol:
protocol Rotatable {}
And implement it:
class ViewController: UIViewController, Rotatable {
}
Use the shouldAutorotate and the supportedInterfaceOrientations method in the ViewController you want to display in landscape and portrait mode:
This method should override the storyboard-settings.
override func shouldAutorotate() -> Bool {
return true
}
override func supportedInterfaceOrientations() -> Int {
return UIInterfaceOrientation.Portrait.rawValue | UIInterfaceOrientation.LandscapeLeft.rawValue | UIInterfaceOrientation.LandscapeRight.rawValue
}
I just faced a very similar problem where I wanted to present a video player in portrait and landscape mode whereas the rest of the app is portrait only. My main problem was that when I dismissed the video vc in landscape mode the presenting vc was only briefly in landscape mode.
As pointed out in the comment to #Lyndsey Scott's answer this can be circumvented by disallowing transitions while in landscape mode, but by combining this and this I've found a better and more generic solution (IMO). This solution allows rotation in all vc where you put canRotate(){} and doesn't rotate the presenting vc.
Swift 3:
In AppDelegate.swift:
func application(_ application: UIApplication, supportedInterfaceOrientationsFor window: UIWindow?) -> UIInterfaceOrientationMask {
if let rootViewController = self.topViewControllerWithRootViewController(rootViewController: window?.rootViewController) {
if (rootViewController.responds(to: Selector(("canRotate")))) {
// Unlock landscape view orientations for this view controller if it is not currently being dismissed
if !rootViewController.isBeingDismissed{
return .allButUpsideDown
}
}
}
// Only allow portrait (standard behaviour)
return .portrait
}
private func topViewControllerWithRootViewController(rootViewController: UIViewController!) -> UIViewController? {
if (rootViewController == nil) {
return nil
}
if (rootViewController.isKind(of: UITabBarController.self)) {
return topViewControllerWithRootViewController(rootViewController: (rootViewController as! UITabBarController).selectedViewController)
} else if (rootViewController.isKind(of: UINavigationController.self)) {
return topViewControllerWithRootViewController(rootViewController: (rootViewController as! UINavigationController).visibleViewController)
} else if (rootViewController.presentedViewController != nil) {
return topViewControllerWithRootViewController(rootViewController: rootViewController.presentedViewController)
}
return rootViewController
}
In each view controller where rotation should be allowed:
func canRotate(){}
Swift 5 using Marker protocol
Combined version of several answers here, done in what I think is a more readable/elegant implementation. (Derived from earlier answers here, not original work by me!)
protocol RotatableViewController {
// No content necessary, marker protocol
}
class MyViewController: UIViewController, RotatableViewController {
// normal content... nothing more required
}
extension AppDelegate {
func application(_ application: UIApplication, supportedInterfaceOrientationsFor window: UIWindow?) -> UIInterfaceOrientationMask {
guard
let rootVc = self.topViewControllerWithRootViewController(rootViewController: window?.rootViewController),
rootVc.isBeingDismissed == false,
let _ = rootVc as? RotatableViewController
else {
return .portrait // Some condition not met, so default answer for app
}
// Conditions met, is rotatable:
return .allButUpsideDown
}
private func topViewControllerWithRootViewController(rootViewController: UIViewController!) -> UIViewController? {
if (rootViewController == nil) {
return nil
}
if (rootViewController.isKind(of: UITabBarController.self)) {
return topViewControllerWithRootViewController(rootViewController: (rootViewController as! UITabBarController).selectedViewController)
}
else if (rootViewController.isKind(of: UINavigationController.self)) {
return topViewControllerWithRootViewController(rootViewController: (rootViewController as! UINavigationController).visibleViewController)
}
else if (rootViewController.presentedViewController != nil) {
return topViewControllerWithRootViewController(rootViewController: rootViewController.presentedViewController)
}
return rootViewController
}
}
Swift 3:
Add code to AppDelegate.swift
func application(_ application: UIApplication, supportedInterfaceOrientationsFor window: UIWindow?) -> UIInterfaceOrientationMask {
if let rootViewController = self.topViewControllerWithRootViewController(rootViewController: window?.rootViewController) {
if (rootViewController.responds(to: Selector(("canRotate")))) {
// Unlock landscape view orientations for this view controller
return .allButUpsideDown;
}
}
// Only allow portrait (standard behaviour)
return .portrait;
}
private func topViewControllerWithRootViewController(rootViewController: UIViewController!) -> UIViewController? {
if (rootViewController == nil) { return nil }
if (rootViewController.isKind(of: (UITabBarController).self)) {
return topViewControllerWithRootViewController(rootViewController: (rootViewController as! UITabBarController).selectedViewController)
} else if (rootViewController.isKind(of:(UINavigationController).self)) {
return topViewControllerWithRootViewController(rootViewController: (rootViewController as! UINavigationController).visibleViewController)
} else if (rootViewController.presentedViewController != nil) {
return topViewControllerWithRootViewController(rootViewController: rootViewController.presentedViewController)
}
return rootViewController
}
Then :
import UIKit
class ViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
}
override func viewWillDisappear(_ animated : Bool) {
super.viewWillDisappear(animated)
if (self.isMovingFromParentViewController) {
UIDevice.current.setValue(Int(UIInterfaceOrientation.portrait.rawValue), forKey: "orientation")
}
}
func canRotate() -> Void {}
}
http://www.jairobjunior.com/blog/2016/03/05/how-to-rotate-only-one-view-controller-to-landscape-in-ios-slash-swift/
SWIFT 4
For UITabBarController can we use this line of code in AppDelegate.swift.
func application(_ application: UIApplication, supportedInterfaceOrientationsFor window: UIWindow?) -> UIInterfaceOrientationMask {
if let tabBarController = window?.rootViewController as? UITabBarController {
if let tabBarViewControllers = tabBarController.viewControllers {
if let projectsNavigationController = tabBarViewControllers[1] as? UINavigationController {
if projectsNavigationController.visibleViewController is PickerViewController //use here your own ViewController class name {
return .all
}
}
}
}
return .portrait
}
Solution Swift 5.1
In App delegate implement this method
func application(_ application: UIApplication, supportedInterfaceOrientationsFor window: UIWindow?) -> UIInterfaceOrientationMask {
if let topController = UIApplication.topViewController() {
if topController.isKind(of: YourSpecificViewController.self) {
return .all
}
return .portrait
}
return .portrait
}
Then add this extension to get the top most ViewController
extension UIApplication {
class func topViewController(base: UIViewController? = UIApplication.shared.keyWindow?.rootViewController) -> UIViewController? {
if let nav = base as? UINavigationController {
return topViewController(base: nav.visibleViewController)
} else if let tab = base as? UITabBarController, let selected = tab.selectedViewController {
return topViewController(base: selected)
} else if let presented = base?.presentedViewController {
return topViewController(base: presented)
}
return base
}
}
Just wanted to share my solution as someone who has spent too much time rotating one view controller in the app:
var preferredInterfaceOrientationForPresentation: UIInterfaceOrientation { get }
overriding this UIViewController method helped me do what I need.
On the view controller that you want to rotate do this for landscape left rotation:
override var preferredInterfaceOrientationForPresentation: UIInterfaceOrientation {
return UIInterfaceOrientation.landscapeLeft
}
Make sure you enable rotation in the desired directions from the project settings:
And add this to AppDelegate to disable other screens' rotation:
func application(_ application: UIApplication, supportedInterfaceOrientationsFor window: UIWindow?) -> UIInterfaceOrientationMask {
return .portrait
}
Swift 5
Another answer, this one covers the isBeingDismissed case.
In AppDelegate:
func application(_ application: UIApplication, supportedInterfaceOrientationsFor window: UIWindow?) -> UIInterfaceOrientationMask {
if
let vvc = navigationController?.visibleViewController,
vvc is YOURViewControllerClassName &&
!vvc.isBeingDismissed
{
return UIInterfaceOrientationMask.landscape
} else {
return UIInterfaceOrientationMask.portrait
}
}
None of these answers worked for me. Fundamentally, AppDelegate's method does not allow specification on which viewController. So either the topMost ViewController is rotatable, in which case the whole view controller hierarchy gets rotated, or nothing gets rotated.
However, I did find a promising answer in Child View Controller to Rotate While Parent View Controller Does Not
It references https://developer.apple.com/library/archive/qa/qa1890/_index.html

Resources