I have an app with several view controllers, most of which should be able to have any orientation, but one is required to be in Portrait. However, the app ignores the value I return from supportedInterfaceOrientations()
My code:
UINavigationController subclass:
override func supportedInterfaceOrientations() -> UIInterfaceOrientationMask {
if let topViewController = self.topViewController {
return topViewController.supportedInterfaceOrientations()
}
return [.Landscape, .Portrait]
}
override func shouldAutorotate() -> Bool {
if let topViewController = self.topViewController {
return topViewController.shouldAutorotate()
}
return true
}
UIViewController subclass
override func supportedInterfaceOrientations() -> UIInterfaceOrientationMask {
return .Portrait
}
override func shouldAutorotate() -> Bool {
return true
}
When I'm in a landscape-compatible view controller and go to the one which is supposed to be in portrait, nothing happens - the app does not autorotate to portrait.
I removed supported interface orientations from info.plist as well. Any ideas?
You can set them in AppDelegate.swift, inside this function
func application(application: UIApplication, supportedInterfaceOrientationsForWindow window: UIWindow) -> Int {
return checkOrientationForVC(self.window?.rootViewController?)
}
And inside this function you can do something like :
func checkOrientationForVC(viewController:UIViewController?)-> Int{
if(viewController == nil){
return Int(UIInterfaceOrientationMask.All.rawValue)//All means all orientation
}else if (viewController is SignInViewController){ //Your View controller here
return Int(UIInterfaceOrientationMask.Portrait.rawValue)
}else{
return checkOrientationForVC(viewController!.presentedViewController?)
}
}
Also set orientation in Storyboard too under "Simulated Metrics" in "Orientation".You can also see this Stackoverflow's post.
Related
I've got an Objetive-C app delegate that is part of a project I'm interfacing with my own. I'm attempting to lock orientation, but it looks like the old methods (below) no longer work. Setting the orientation in viewDidLoad rotates the screen but allows the user to rotate back to portrait. I've attempted converting to "override var" but no luck. The current solutions (link below) look to all involve an app delegate call, but I cannot locate the solution for a Swift call to an Objective C app delegate.
How to lock orientation of one view controller to portrait mode only in Swift
override func shouldAutorotate() -> Bool {
return false
}
override func supportedInterfaceOrientations() -> UIInterfaceOrientationMask {
return UIInterfaceOrientationMask.landscapeRight
}
To force only one controller to be at landscape orientation.
Manager:
class OrientationManager {
static let shared = OrientationManager()
/// you can set any orientation to lock
var orientationLock = UIInterfaceOrientationMask.portrait
/// lock orientation and force to rotate device
func lock(for orientation: UIInterfaceOrientationMask, rotateTo rotateOrientation: UIInterfaceOrientation) {
orientationLock = orientation
UIDevice.current.setValue(rotateOrientation.rawValue, forKey: "orientation")
}
}
Usage:
1) Add code to AppDelegate
func application(_ application: UIApplication,
supportedInterfaceOrientationsFor window: UIWindow?) -> UIInterfaceOrientationMask {
return OrientationManager.shared.orientationLock
}
2) Use in controller
open class LandscapeController: UIViewController {
/// orientation for one controller
override open func viewDidLoad() {
super.viewDidLoad()
OrientationManager.shared.lock(for: .landscape, rotateTo: .landscapeLeft)
}
/// set previous state of orientation or any new one
override open func viewWillDisappear(_ animated : Bool) {
super.viewWillDisappear(animated)
OrientationManager.shared.lock(for: .portrait, rotateTo: .portrait)
}
}
Solved my problem using this link, after trying just about everything.
how to lock portrait orientation for only main view using swift
I utilized the answer from JasonJasonJason and updated the code to get rid of the ->.
The below code went in my first VC
extension UINavigationController {
override open var shouldAutorotate: Bool {
return true
}
override open var supportedInterfaceOrientations: UIInterfaceOrientationMask {
return (visibleViewController?.supportedInterfaceOrientations)!
}
}
Then subsequent VCs
override var supportedInterfaceOrientations: UIInterfaceOrientationMask {
return UIInterfaceOrientationMask.landscape
}
Then since I had a TabBarController, I added this to the controller that pushes to the tab view. If you try to re-use the initial UINavigationController extension it won't let you, but the TabBarController ignores it. So the below extension solves it for any VC's with the TabBar
extension UITabBarController {
override open var shouldAutorotate: Bool {
return true
}
override open var supportedInterfaceOrientations: UIInterfaceOrientationMask {
return UIInterfaceOrientationMask.landscape
}
}
For xcode 8.x & swift 3.x
We can control device orientation for particular screen.
On AppDelegate.swift make a variable enableAllOrientation:
var enableAllOrientation = false
func application(_ application: UIApplication, supportedInterfaceOrientationsFor window: UIWindow?) -> UIInterfaceOrientationMask {
if (enableAllOrientation == true){
return UIInterfaceOrientationMask.all
}
return UIInterfaceOrientationMask.portrait
}
& mask for particular view controller as -
override func viewWillAppear(_ animated: Bool)
{
super.viewWillAppear(animated)
let appDelegate = UIApplication.shared.delegate as! AppDelegate
appDelegate.enableAllOrientation = false
}
I was searching that how can I change the orientation to LandScape mode only for spefic view controller when the Device Orientation is set to Portrait in the project settings. Didn't get any succesfull result. so finally I found a way to do it.
this is project device orientation looks like ....
In swift 2.3 add following methods
override func shouldAutorotate() -> Bool {
return false
}
override func supportedInterfaceOrientations() -> UIInterfaceOrientationMask {
return UIInterfaceOrientationMask.LandscapeLeft
}
override func preferredInterfaceOrientationForPresentation() -> UIInterfaceOrientation {
return UIInterfaceOrientation.LandscapeLeft
}
For swift 3.0 do like below ....
override var shouldAutorotate: Bool {
return false
}
override var supportedInterfaceOrientations: UIInterfaceOrientationMask {
return .landscapeLeft
}
override var preferredInterfaceOrientationForPresentation: UIInterfaceOrientation {
return .landscapeLeft
}
Note :This will work fine, if you navigate from one view to another view controller without a navigation controller .
for more see this small video tutorial : change device orientation for specific view controller in ios
if anyone has better way to do this or comments , hope your answer or comments here . thanx .
Use supportedInterfaceOrientationsFor application delegate.add following code in AppDelegate file
func application(_ application: UIApplication, supportedInterfaceOrientationsFor window: UIWindow?) -> UIInterfaceOrientationMask {
if isIpadLandscape {
return UIInterfaceOrientationMask.all;
}else{
return UIInterfaceOrientationMask.portrait;
}
}
Add particular **viewcontroller** page you want to **rotate**
override func viewDidLoad() {
super.viewDidLoad()
isLandscape = true
}
override func viewWillDisappear(_ animated: Bool) {
isLandscape = false
}
And dont forget to add global varibale in appdelegate file
import UIKit
import CoreData
import Foundation
var isLandscape = false
#UIApplicationMain
I have a portrait application with one landscape ViewController.
I've been digging a lot on how to force the orientation to landscape when the app is locked to portrait and I tried a lot of solutions presented here and not only but without any luck so far.
So far I managed to autorotate the VC I need in landscape but since the orientation is not locked, all other VCs will also rotate.
override func viewDidAppear(animated: Bool)
{
let value = UIInterfaceOrientation.LandscapeRight.rawValue
UIDevice.currentDevice().setValue(value, forKey: "orientation")
}
override func shouldAutorotate() -> Bool
{
return true
}
After some more digging I ended up with this after finding a sample project but while it works in that project, it doesn't seem to work for me.
This is in AppDelegate
func application(application: UIApplication, supportedInterfaceOrientationsForWindow window: UIWindow?) -> UIInterfaceOrientationMask {
if self.window?.rootViewController?.presentedViewController is ConclusionReferencesVC {
let conclusionReferencesVC = self.window!.rootViewController!.presentedViewController as! ConclusionReferencesVC
if conclusionReferencesVC.isPresented
{
return UIInterfaceOrientationMask.LandscapeRight;
}
else
{
return UIInterfaceOrientationMask.Portrait;
}
}
else
{
return UIInterfaceOrientationMask.Portrait;
}
}
This is in the VC I want to have in landscape:
var isPresented = true
#IBAction
func dismiss()
{
isPresented = false
self.presentingViewController!.dismissViewControllerAnimated(true, completion: nil);
}
For some reason, the supportedInterfaceOrientationsForWindow method does not validate the initial condition.
I also tried these among others but no luck:
How to lock orientation of one view controller to portrait mode only in Swift
supportedInterfaceOrientationsForWindow in Swift 2.0
Any ideas? It seems I'm missing something but I can't figure it out what.
try this for force to LandscapeRight mode only
override func viewWillAppear(animated: Bool) {
super.viewWillAppear(animated)
if(self.supportedInterfaceOrientations() == UIInterfaceOrientationMask.LandscapeRight && UIDevice.currentDevice().orientation != UIDeviceOrientation.LandscapeRight)
{
let value = UIInterfaceOrientation.LandscapeRight.rawValue
UIDevice.currentDevice().setValue(value, forKey: "orientation")
}
}
and then use a category like this
import UIKit
extension UINavigationController{
override public func shouldAutorotate() -> Bool
{
return (self.viewControllers.last?.shouldAutorotate())!
}
override public func supportedInterfaceOrientations() ->UIInterfaceOrientationMask
{
return (self.viewControllers.last?.supportedInterfaceOrientations())!;
}
override public func preferredInterfaceOrientationForPresentation()-> UIInterfaceOrientation
{
return (self.viewControllers.last?.preferredInterfaceOrientationForPresentation())!;
}
}
EDITED
If you are not using navigation controller use this
override func viewWillAppear(animated: Bool) {
super.viewWillAppear(animated)
if(self.supportedInterfaceOrientations() == UIInterfaceOrientationMask.LandscapeRight && UIDevice.currentDevice().orientation != UIDeviceOrientation.LandscapeRight)
{
let value = UIInterfaceOrientation.LandscapeRight.rawValue
UIDevice.currentDevice().setValue(value, forKey: "orientation")
}
}
override func supportedInterfaceOrientations() ->UIInterfaceOrientationMask
{
return .LandscapeRight;
}
I hope this helps you
As an update to Reinier Melian's post, here is the UINavigationController extension in Swift 3:
import UIKit
extension UINavigationController {
override open var shouldAutorotate: Bool {
return (self.viewControllers.last?.shouldAutorotate)!
}
override open var supportedInterfaceOrientations: UIInterfaceOrientationMask {
return (self.viewControllers.last?.supportedInterfaceOrientations)!
}
override open var preferredInterfaceOrientationForPresentation: UIInterfaceOrientation {
return (self.viewControllers.last?.preferredInterfaceOrientationForPresentation)!
}
}
Unfortunately, this code crashes if you call a UIImagePickerController, as that is contained within a UINavigationController whose last view controller is nil.
probably I´m crazy ;-), but why don´t u use this?
How we can set one particular viewcontroller to landscape mode in swift using xib?
func supportedInterfaceOrientations() -> UIInterfaceOrientationMask {
let orientation: UIInterfaceOrientationMask =
[UIInterfaceOrientationMask.Portrait, UIInterfaceOrientationMask.PortraitUpsideDown]
return orientation
}
I am using the above code but it doesn't seem to work..
I am pretty sure that you can't be that specific for each view controller by using the storyboard. If you are doing it in code as you are, you need to specify the override keyword for that function. You also need to make sure that your app project supports all the interface orientations that you want to support for any particular view controller.
You need to check the device orientation in your proyect target
and then in all viewControllers in portrait add
override func shouldAutorotate() -> Bool {
if (UIDevice.currentDevice().orientation == UIDeviceOrientation.Portrait ||
UIDevice.currentDevice().orientation == UIDeviceOrientation.PortraitUpsideDown ||
UIDevice.currentDevice().orientation == UIDeviceOrientation.Unknown) {
return true;
} else {
return false;
}
}
override func supportedInterfaceOrientations() -> UIInterfaceOrientationMask {
return UIInterfaceOrientationMask.Portrait
}
finally in landscape viweController you want add
override func shouldAutorotate() -> Bool {
return true
}
override func supportedInterfaceOrientations() -> UIInterfaceOrientationMask {
return [UIInterfaceOrientationMask.Portrait, UIInterfaceOrientationMask.Landscape, UIInterfaceOrientationMask.LandscapeLeft, UIInterfaceOrientationMask.LandscapeRight, UIInterfaceOrientationMask.PortraitUpsideDown]
}
How can I unlock orientation just for one controller? I allowed just one - portrait - mode for whole my application, but just in one I need a landscape mode. For this I tried the next snippet:
override func supportedInterfaceOrientations() -> Int {
return Int(UIInterfaceOrientationMask.Portrait.rawValue)
}
override func shouldAutorotate() -> Bool{
return false
}
override func preferredInterfaceOrientationForPresentation() -> UIInterfaceOrientation {
return UIInterfaceOrientation.Portrait
}
but it doesn't help me. Are there any other solutions?
In Appdelegate define a var :
import UIKit
var isViewAppeared = false
now in Appdelegate:
func application(application: UIApplication, supportedInterfaceOrientationsForWindow window: UIWindow?) -> Int {
if isViewAppeared{
return Int(UIInterfaceOrientationMask.AllButUpsideDown.rawValue)
}
return Int(UIInterfaceOrientationMask.Portrait.rawValue)
}
Now in ViewController where you want landscape:
override func viewWillAppear(animated: Bool) {
super.viewWillAppear(animated)
isViewAppeared = true
}
override func viewWillDisappear(animated: Bool) {
super.viewWillDisappear(animated)
isViewAppeared = false
UIView.animateWithDuration(0.4, animations: { () -> Void in
let value = UIInterfaceOrientation.Portrait.rawValue
UIDevice.currentDevice().setValue(value, forKey: "orientation")
})
}
Do the following:
enable the desired orientations in the General Info Screen
in each ViewController.swift
override the autorotation function with either true or false (true for the one that should rotate, false for the others)
Hope that helps :)