How to allow iOS users to set the application's orientation - ios

I want to add a new setting for orientation to my application, let user choice of Portrait, Landscape, or OS Setting.
I found some solution that need overwrite UIViewController.
Is there a easy way to do it?
I would like to intercept and mock System's orientation change event? Is it possible?

Implement the UIApplicationDelegate method below and return an appropriate mask based on the user's chosen setting:
func application(_ application: UIApplication, supportedInterfaceOrientationsFor window: UIWindow?) -> UIInterfaceOrientationMask {
// The following conditions are pseudo code to give you an idea
if "userSetting == portrait" {
return .portrait
} else if "userSetting == landscape" {
return .landscape
} else {
return .all
}
}
Also make sure your Info.plist specifies all orientations.

Related

Replacement for deprecated attemptRotationToDeviceOrientation function

I have been using the attemptRotationToDeviceOrientation function to change the orientation of some ViewController when the user presses a button. However, as of iOS 16, this function has been officially deprecated.
What can I use as the replacement?
this can be done in two ways.
personally I prefer this way
1.keep this function in AppDelegate to handle the orientation(this is must)
func application(_ application: UIApplication, supportedInterfaceOrientationsFor window: UIWindow?) -> UIInterfaceOrientationMask {
return .all
}
2. in which ViewController you want the force orientation, go to that view controller and add these lines in the variable declaring section
var forceLandscape: Bool = false
override var supportedInterfaceOrientations: UIInterfaceOrientationMask {
forceLandscape ? .landscape : .portrait
}
we will be updating the forceLandscape so it will get updated, then the supportedInterfaceOrientations also will get updated
3. Here we are setting the trigger for updating the forceLandscape (we can add these lines of code inside button action for handling IOS 16 force roatation)
if #available(iOS 16.0, *) {
self.forceLandscape = true
guard let windowScene = UIApplication.shared.connectedScenes.first as? UIWindowScene else { return }
self.setNeedsUpdateOfSupportedInterfaceOrientations()
DispatchQueue.main.asyncAfter(deadline: .now() + 0.2, execute: {
windowScene.requestGeometryUpdate(.iOS(interfaceOrientations: .landscapeRight)){
error in
print(error)
print(windowScene.effectiveGeometry)
}
})
this will update the forceLandscape, so it will check the orientation and update according to it
According to release note: https://developer.apple.com/documentation/ios-ipados-release-notes/ios-16-release-notes?changes=lat__8_1
I think you may have to use setNeedsUpdateOfSupportedInterface.
Deprecations
[UIViewController shouldAutorotate] has been deprecated is no longer supported. [UIViewController attemptRotationToDeviceOrientation] has been deprecated and replaced with [UIViewController setNeedsUpdateOfSupportedInterfaceOrientations].
Workaround: Apps relying on shouldAutorotate should reflect their preferences using the view controllers supportedInterfaceOrientations. If the supported orientations change, use `-[UIViewController setNeedsUpdateOfSupportedInterface
I think you may have to use setNeedsUpdateOfSupportedInterface.

How to fix alertView orientation on specific controller?

I want to fix orientation of a specific controllers.
I tried more times but I'm unable to fixed. I fixed the controller orientation in appdelegate method (supportedInterfaceOrientationsFor) but cause of alert message orientation doesn't work proper and then that work normally. I mean it's work all type orientation.
func application(_ application: UIApplication, supportedInterfaceOrientationsFor window: UIWindow?) -> UIInterfaceOrientationMask {
if !UIDevice.isIphone() {
let controller = (application.keyWindow?.rootViewController as? UINavigationController)?.visibleViewController
if controller is LiveStreamViewController || controller is VideoStreamingViewController {
return .portrait
} else {
return .all
}
} else {
return .portrait
}
}
Orientation of a "specific controller" is not determined by implementing application(_:supportedInterfaceOrientationsFor:). It is determined from within the specific controller by implementing supportedInterfaceOrientations. And even then, this value is not consulted unless your view controller is topmost.
Alert view surly rotted according to Orientation but if does not work then try to use below code
func didPresent(_ alertView: UIAlertView) {
// UIAlertView in landscape mode for specific controller?
UIView.beginAnimations("", context: nil)
UIView.setAnimationDuration(0.1)
alertView.transform = alertView.transform.rotated(by: 3.14159 / 2)
UIView.commitAnimations()
}

AVPlayer View Controller Autorotation off?

I'm working on an iOS app in portrait mode only, and it's working fine.
Issue is that I'm presenting AVPlayerViewController above navigationController (both created programmatically). This player supports all the rotations (I don't know why!).
I want to fix this to portrait mode only just like other sections of app.
How can we do that?
Create new class that inherits from AVPlayerViewController and implement the supported interface method like this. After this instead of initializing object of AVPlayerViewController just create object of the class that you have created.
class MyPortraitVideoController: AVPlayerViewController {
override var supportedInterfaceOrientations: UIInterfaceOrientationMask {
return .portrait
}
}
Edited to add:
Note that the Documentation for AVPlayerViewController states:
Important Do not subclass AVPlayerViewController. Overriding this
class’s methods is unsupported and results in undefined behavior.
As this is the accepted answer, I assume the OP has tried it and it worked, but I thought I should add a note about it here to make sure future readers are aware of any potential problems. Undefined behavior means this could stop working in a future release of iOS.
In my case, I had to restricted landscape orientation for some views.So I set supportedInterfaceOrientationsFor as portrait in AppDelegate. When I present AVPlayerViewController I had to set supportedInterfaceOrientationsFor as all in AppDelegate.
Check below codes as well.
AppDelegate.swift
var shouldSupportLandscape = Bool()
func application(_ application: UIApplication, supportedInterfaceOrientationsFor window: UIWindow?) -> UIInterfaceOrientationMask {
if self.shouldSupportLandscape == true {
return .all
}else {
return .portrait
}
}
When present AVPlayerViewController
let appDelegate = UIApplication.shared.delegate as! AppDelegate
appDelegate.shouldSupportLandscape = true
When dismiss AVPlayerViewController
let appDelegate = UIApplication.shared.delegate as! AppDelegate
appDelegate.shouldSupportLandscape = false

Swift Code in App Delegate to Load Storyboard Causes Crash

I have an universal app I am writing and I initially wrote it using two storyboard files. I had code in the App Delegate didFinishLaunchingWithOptions routine to decide which storyboard to load and away it would go. I have since realised that that was a silly thing to do because I had duplicate code, so I have deleted one storyboard and made the other universal. I have fixed up the VCs to point at the right class and everything. However, my app now refuses to launch. When I run it in the sim, it gives me the error
The app delegate must implement the window property if it wants to use a main storyboard file.
.
Here is my code in App Delegate:
func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool {
// Override point for customization after application launch.
var deviceIdiom = UIDevice.currentDevice().userInterfaceIdiom
if deviceIdiom == UIUserInterfaceIdiom.Phone {
strDevice = "iPhone"
} else if deviceIdiom == UIUserInterfaceIdiom.Pad {
strDevice = "iPad"
} else {
strDevice = "Unknown"
}
return true
}
What am I doing wrong?
(Questions I've already looked at but didn't help):
Unique Issue displaying first storyboard scene in Xcode
The app delegate must implement the window property if it wants to use a main storyboard file
Managing two storyboards in App Delegate
How to manually set which storyboard view to show in app delegate
Swift - Load storyboard programatically
Your app delegate needs to start like such:
#UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate {
var window: UIWindow?
//...
}

Can't get supportedInterfaceOrientationsForWindow to work with Swift 1.2

Hey Stackoverflow Members,
maybe you could help me to get my problem fixed.
The problem is I want to lock the orientation for all UIViewControllers to "Portrait" but if the MoviePlayer appears it should switch into landscape mode and back if the movie player disappears.
Until Swift 1.2 I used:
func application(application: UIApplication, supportedInterfaceOrientationsForWindow window: UIWindow) -> UIInterfaceOrientationMask {
//If the video is being presented, let the user change orientation, otherwise don't.
if let presentedViewController = window.rootViewController?.presentedViewController? {
if (presentedViewController.isKindOfClass(MPMoviePlayerViewController) && !presentedViewController.isBeingDismissed()) {
return .AllButUpsideDown
}
}
return .Portrait
}
With Swift 1.2 some things changed and so I ended up with the following code:
func application(application: UIApplication, supportedInterfaceOrientationsForWindow window: UIWindow?) -> Int {
//If the video is being presented, let the user change orientation, otherwise don't.
if let presentedViewController = window?.rootViewController?.presentedViewController {
if (presentedViewController.isKindOfClass(MPMoviePlayerViewController) && !presentedViewController.isBeingDismissed()) {
return Int(UIInterfaceOrientationMask.AllButUpsideDown.rawValue)
}
}
return Int(UIInterfaceOrientationMask.Portrait.rawValue)
}
But my code doesn't work, the Movie Player (XCDYoutube) is locked in portrait mode. Device orientation Settings should be fine!
Thanks in advance for your help!
I had similar logic to yours but ending up returning support for all orientations.
return UIInterfaceOrientationMaskAll in appdelegate.
Depending on how many view controllers you have - you may want to create an abstract subclass of UIViewController and return only support for Portrait / and then hack your youtube view controller to support landscape.
(NSUInteger)supportedInterfaceOrientations {
return UIInterfaceOrientationMaskLandscapeLeft | UIInterfaceOrientationMaskLandscapeRight;
}
I just had the exact same issue. I found a way to fix it by reaching the top of the controller stack:
func application(application: UIApplication, supportedInterfaceOrientationsForWindow window: UIWindow?) -> Int {
//If the video is being presented, let the user change orientation, otherwise don't.
if var presentedViewController = window?.rootViewController?.presentedViewController {
// Get the controller on the top of the stack
while (presentedViewController.presentedViewController) != nil {
presentedViewController = presentedViewController.presentedViewController!
}
if (presentedViewController.isKindOfClass(MPMoviePlayerViewController) && !presentedViewController.isBeingDismissed()) {
return Int(UIInterfaceOrientationMask.AllButUpsideDown.rawValue)
}
}
return Int(UIInterfaceOrientationMask.Portrait.rawValue)
}
You can also try to display the type of presentedViewController to be sure it's the right one:
println("presentedViewController type: \(presentedViewController.dynamicType)")

Resources