How to disable and enable auto rotate on swift? - ios

On general settings I allow portrait and landscapeleft , landscaperight modes. I want to turn off landscape modes. On viewController I write this code:
override func shouldAutorotate() -> Bool {
return false
}
However, the auto rotation works ignoring this function. How do I disable and enable autorotation on swift? IOS programming

It might be the right code, but not in the right View Controller. For example, if the View Controller is embedded in a UINavigationController, the navigation controller can still rotate, causing the View Controller to still rotate. It really depends on your specific situation.

I had the same problem, i have fixed that.
Follow-
info --> custom ios target properties --> Support Interface Orinetations. and delete ![Delete - Landscape (left home button), Landscape (right home button), Landscape (top home button)][1]
This will help you 😊

You can do it by creating a subclass of UINavigationController and inside that, override the should AutoRotate function,then
return false for the viewControllers in which you want to disable autorotation
return true for the viewControllers in which you want autorotation
import UIKit
class CustomNavigationController: UINavigationController {
override func shouldAutorotate() -> Bool {
if !viewControllers.isEmpty {
// Check if this ViewController is the one you want to disable roration on
if topViewController!.isKindOfClass(ViewController) { //ViewController is the name of the topmost viewcontroller
// If true return false to disable it
return false
}
}
// Else normal rotation enabled
return true
}
}
If you want to disable autorotation throughout the navigation controller, remove the if condition and return false always

Extending Josh Gafni's answer and user3655266, the concept also extends to view controllers.
If we have a UIViewController that is a child of another UIViewController in the view hierarchy, overriding the child's shouldAutorotate() to false might still rotate since it parent's controller might still be returning true. It is also important to know that even though the child VC is being displayed, the parent's shouldAutoRotate function are still called. Hence the control should lie there.
Swift 5
class ParentViewController:UIViewController{
override func shouldAutorotate() -> Bool {
// Return an array of ViewControllers that are children of the parent
let childViewControllersArray = self.children
if childViewControllersArray.count > 0 {
// Assume childVC is the ViewController you are interested in NOT allowing to rotate
let childVC = childViewControllersArray.first
if childVC is ChildViewController {
return false
}
}
return true
}
}
** The same can also be done to only allow certain phone orientation **
override var supportedInterfaceOrientations: UIInterfaceOrientationMask {
// This function is called on the parent's controller whenever the child of this parent is trying to rotate
let childrenVCArray = self.children
if childrenVCArray.count > 0 {
// assuming the array of the first element is the current childVC
let topMostVC = childrenVCArray[0]
if topMostVC is ChildViewController {
// Assuming only allowing landscape mode
return .landscape
}
}
// Return portrait otherwise
return .portrait
}

I am not sure if shouldAutorotate() function is still enabled in swift 5 for year 2021. However I recommend calling one of the following functions as part of standard procedure for managing rotation of ViewControllers. ("Handling View Rotations" part in apple developer webside For example preferredInterfaceOrientationForPresentation

Related

UINavigationController: show embedded view controllers with different orientations after each transition?

This is a common question on StackOverflow, but none of the other solutions worked. Many were also written several years ago.
Here are some of the posts considered:
Is it possible to have different orientations for viewControllers inside UINavigationController?
Support landscape for only one view in UINavigationController
Is it possible to have different orientations for viewControllers inside UINavigationController?
Why can't I force landscape orientation when use UINavigationController?
How to force view controller orientation in iOS 8?
We have several view controllers embedded inside a UINavigationController: A, B, C, D.
A, B use portrait.
C, D use landscape.
A is the root controller.
Assume B gets pushed onto A. That works since B is portrait. However, when C gets pushed onto B, the screen doesn't rotate since as the class docs state:
Typically, the system calls this method only on the root view
controller of the window or a view controller presented to fill the
entire screen; child view controllers use the portion of the window
provided for them by their parent view controller and no longer
participate directly in decisions about what rotations are supported.
So overriding supportedInterfaceOrientations inside a custom UINavigationController doesn't help because it isn't consulted on transitions within embedded controllers.
Effectively, we need a way to force orientation changes upon transitions, but there seems to be no supported method for this.
Here's how we override UINavigationController (extension is only used now for debugging purposes since apparently extensions shouldn't be used for overriding):
extension UINavigationController {
override open var shouldAutorotate: Bool {
return true
}
override open var supportedInterfaceOrientations : UIInterfaceOrientationMask {
return visibleViewController?.supportedInterfaceOrientations ?? UIInterfaceOrientationMask.landscapeRight
}
}
Within embedded view controllers, we try to set the orientation like this:
override var shouldAutorotate: Bool {
return true
}
override var preferredInterfaceOrientationForPresentation : UIInterfaceOrientation {
return UIInterfaceOrientation.landscapeRight
}
override var supportedInterfaceOrientations : UIInterfaceOrientationMask {
return UIInterfaceOrientationMask.landscapeRight
}
To summarize, the goals are:
1) Show view controllers embedded inside a UINavigationController with different orientations.
2) VC transitions should yield proper orientation change (e.g., popping from C->B should yield portrait, popping from D->C should yield landscape, pushing from B->C should yield landscape, pushing from A->B should yield portrait).
If it were possible to force the UINavigationController into an orientation (with publicly supported method), one possible solution could be to force the orientation upon showing the new view controller. But this also doesn't seem possible.
Suggestions?
Step 1
Subclass UINavigationController.
class LandscapeNavigationController: UINavigationController {
public var vertical: Bool = true
override var shouldAutorotate: Bool {
get { return true }}
override var supportedInterfaceOrientations: UIInterfaceOrientationMask {
get { return (vertical) ? .portrait : .landscapeLeft }}
override var preferredInterfaceOrientationForPresentation: UIInterfaceOrientation {
get { return (vertical) ? .portrait : .landscapeLeft }}
}
Step 2
Use different UINavigationController for different orientations. Yes, pushing a new UINavigationController atop a previous UINavigationController will essentially be modal, but the transition looks nice.
For added convenience, use User Defined Runtime Attributes to control the orientation of the LandscapeNavigationController.
Step 3
Add a pop method to handle Back buttons on the now modal UIViewController.
#IBAction func doBack(_ sender: UIBarButtonItem) {
if let navigationController = navigationController {
navigationController.dismiss(animated: true, completion: {
})
}
}
In Action
Notice how the Top and Bottom labels on view C are properly laid out.
↻ replay animation
â–º Find this solution on GitHub and additional details on Swift Recipes.

UISplitViewController: How to prevent expansion when rotating from Compact to Regular

There are many answers to the complementary question, which is how to prevent a transition to PrimaryOverLay on a from Regular to Compact interface change, eg use
func splitViewController(splitViewController: UISplitViewController, collapseSecondaryViewController secondaryViewController: UIViewController, ontoPrimaryViewController primaryViewController: UIViewController) -> Bool
In my case, I have an iPhone 6+ with the detail view showing in portrait. When I rotate the device to horizontal (Compact to Regular), I want the primary view to stay hidden. I've tried setting the preferredDisplayMode to .PrimaryHidden in many places, but it has no apparent affect. Googling has turned up nothing.
Well, after I wrote the question, but before posting it, I tripped on a possible solution, which is to override the trait collection that the split view controller references.
I took that idea and decided to subclass UISplitViewController, and override the traitCollection property. That did the trick:
final class MySplitViewController: UISplitViewController {
var didOnce = false
override var traitCollection: UITraitCollection {
let old = super.traitCollection
let change = UITraitCollection(horizontalSizeClass: .Compact)
let new = UITraitCollection(traitsFromCollections: [old, change])
return new
}
Obviously this is hardcoded for one device - later I'll go and add some functions that I can use to control what is in fact returned.
Don't override traitCollection, instead use the method setOverrideTraitCollection:forChildViewController: in a parent view controller of your split controller, like in Apple's example AAPLTraitOverrideViewController.m
If your split controller doesn't have a parent, making a parent is really easy in the Storyboard. Add a new view controller, make it the entry point, add a container view, delete the default embedded view and instead add an embed segue to the split controller and set the override on self.childViewControllers.firstObject in viewDidLoad.

How to block landscape position from code, separetly for each view controller?

I know that I can select available orientation of my app in targets menu, but I would like to block landscape orientation for each screen EXCEPT the one with youtube player.
I suppose this couldn't be done via app delegate since it does not distinct controllers and apply the rule for the whole app.
I suspect maybe there is a way to do that via sharedApplication(), but have no clue how to.
Do you have any idea how such thing could be done?
Add this to the UIViewController class you wish to set to Portrait only.
override func supportedInterfaceOrientations() -> Int {
return Int(UIInterfaceOrientationMask.Portrait.rawValue)
}
Provided you haven't changed any settings in your target the other screens without this should be able to rotate correctly.
Use this override func in each VC you want to block .LandscapeLeft and .LandscapeRight
override func supportedInterfaceOrientations() -> Int {
return Int(UIInterfaceOrientationMask.Portrait.rawValue) | Int(UIInterfaceOrientationMask.PortraitUpsideDown.rawValue)
}

Restricting portrait orientation to collectionview in iOS doesn't seem to work

I have multiple viewControllers in my app and I would like to restrict certain views only to portrait orientation. I have achieved this by overriding shouldAutoRotate and supportedInterfaceOrientations like below
override func shouldAutorotate() -> Bool {
return false
}
override func supportedInterfaceOrientations() -> Int {
return Int(UIInterfaceOrientation.Portrait.rawValue)
}
I have followed the same for a UICollectionView but it doesn't seem to work. I would like to know if this is the right way to achieve it. Help on this would be much appreciated. Thanks in advance!
In iOS 8 or later, if you want to control the allowed orientations per view controller:
Make sure the "Supported interface orientations" in the Info.plist allows all orientations you want the app to be able to use. (Or just check the correct "Device Orientations" in the Xcode UI interface to the Info.plistfile)
Per view controller, implement (example restricting to portrait):
override func supportedInterfaceOrientations() -> UIInterfaceOrientationMask {
return UIInterfaceOrientationMask.Portrait
}
A problem you can run in to is if your view controller is embedded in another view controller (like an UINavigationController or a UITabBarController, or both).
I suspect this is the situation you are describing.
If so, all view controllers involved need to implement the supportedInterfaceOrientations() method. AFAIK, if you for example have a UINavigationController above your view controller, you need to sub class and create your own navigation controller with the method implemented.

Swift Orientation override for a viewcontroller

I'm having trouble to allow only 1 view controller in marking portrait,Landscape right and left, that view controller has a button to a video on youtube embed link I just want to allow rotation to this view,
I allowed all orientations in app and tried to add this to other view controllers that I wanted to be portrait but no chance
override func supportedInterfaceOrientations() -> Int {
return UIInterfaceOrientationMask.Portrait.rawValue.hashValue | UIInterfaceOrientationMask.PortraitUpsideDown.rawValue.hashValue
}
is there anyother way to implement this I mean I will only allow portrait in general app setting but override one that in the video view controller view,or just like first one I tried in general setting allow all orientations but allow only portrait in all views except videocontrollerview, thanks advance for any help..
Since there is no code I can't say for sure but you might be missing this in your view controller so that those supportedInterfaceOrientations can work:
override func shouldAutorotate() -> Bool {
return true
}

Resources