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
}
Related
I am trying to make just one view of the landscape and other all views are on the portrait. It works but there is an issue on every second-time screen doesn't rotate at all.
Here is the scenario that I am talking about:
On every second time, device rotation doesn't work.
Here is my code
AppDelegate.swift
func application(_ application: UIApplication, supportedInterfaceOrientationsFor window: UIWindow?) -> UIInterfaceOrientationMask {
return .portrait
}
Controller1.swift
override var supportedInterfaceOrientations: UIInterfaceOrientationMask {
return .portrait
}
override var shouldAutorotate: Bool {
return true
}
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
AppUtility.lockOrientation(.portrait)
}
DetailController.swift
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
AppUtility.lockOrientation(.landscape, andRotateTo: .landscapeLeft)
}
override func viewWillDisappear(_ animated: Bool) {
super.viewWillDisappear(animated)
if isMovingFromParentViewController {
AppUtility.lockOrientation(.portrait, andRotateTo: .portrait)
}
}
Code that effects the rotation
struct AppUtility {
static func lockOrientation(_ orientation: UIInterfaceOrientationMask) {
if let delegate = UIApplication.shared.delegate as? AppDelegate {
delegate.orientationLock = orientation
}
}
static func lockOrientation(_ orientation: UIInterfaceOrientationMask, andRotateTo rotateOrientation:UIInterfaceOrientation) {
self.lockOrientation(orientation)
UIDevice.current.setValue(rotateOrientation.rawValue, forKey: "orientation")
}
}
So, How to force rotate detail view every time it loads?
Step 1:- Please define a below-mentioned variable in app delegate.
var shouldRotate : Bool = false
Step 2:- Implement the following delegate method as below.
//MARK:- Set Device Orientation Delegate Method
func application(_ application: UIApplication, supportedInterfaceOrientationsFor window: UIWindow?) -> UIInterfaceOrientationMask {
return shouldRotate ? .landscapeRight : .portrait
}
Step 3 :- Define constant class and add "Set Portrait Orientation" and "Set Landscape Right Orientation" function in the class.
//MARK:- Set Portrait Orientation
func setPortraitOrientation() {
appDelegateInstance.shouldRotate = false
UIDevice.current.setValue(UIInterfaceOrientation.portrait.rawValue, forKey: "orientation")
}
//MARK:- Set Landscape Right Orientation
func setLandscapeRightOrientation() {
appDelegateInstance.shouldRotate = true
UIDevice.current.setValue(UIInterfaceOrientation.landscapeRight.rawValue, forKey: "orientation")
}
Step 4:- Use the following code in your class (Target landscape class)
Step 4.1:- In view will appear call set Landscape Right Orientation function shown below.
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(true)
setLandscapeRightOrientation()
}
Step 4.2 :- When you leave the screen implement the following code in the action.
//MARK:- Left Bar Button Tapped Delegate Method
func leftBarButtonTapped() {
_ = self.navigationController?.popViewController(animated: false)
setPortraitOrientation()
}
Happy Coding! Cheers!!
I want to keep a portrait orientation even if user rotate the phone. At the same time, I want to change the orientation with a button.
If I put only portrait as supported orientation in plist and then rotate, application gives me error. If I put all the supported orientation but shouldAutorotate method to NO, Application crashes.
So, basically as I can see I can only support multiple orientation if I let the application to autorotate.
Can I achieve what I need?
shouldAutorotate
this is a get-only property.
what you can do is:
override var shouldAutorotate: Bool {
return false
}
Maybe this is also interesting for you: how to dissable and enable auto rotate on swift?
May be the following line of code will work for you. set orientation programmatically.
In your Appdelegate class write this code:
var orientationLock = UIInterfaceOrientationMask.all
func application(_ application: UIApplication, supportedInterfaceOrientationsFor window: UIWindow?) -> UIInterfaceOrientationMask {
return self.orientationLock
}
2.Make custom helper class as follows:
struct AppUtility {
static func lockOrientation(_ orientation: UIInterfaceOrientationMask) {
if let delegate = UIApplication.shared.delegate as? AppDelegate {
delegate.orientationLock = orientation
}
}
/// OPTIONAL 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 use it in your desire viewcontroller like:
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
AppUtility.lockOrientation(.portrait)
// Or to rotate and lock
// AppUtility.lockOrientation(.portrait, andRotateTo: .portrait)
}
override func viewWillDisappear(_ animated: Bool){
super.viewWillDisappear(animated)
// Don't forget to reset when view is being removed
AppUtility.lockOrientation(.all)
}
note: keep remember Require Full Screen option is checked from target settings.
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 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.
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?