Replacement for deprecated attemptRotationToDeviceOrientation function - ios

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.

Related

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()
}

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

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.

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

UIApplicationShortcutItem in didFinishLaunching

According to Apple documentation :
It’s your responsibility to ensure the system calls this method conditionally, depending on whether or not one of your app launch
methods (application:willFinishLaunchingWithOptions: or
application:didFinishLaunchingWithOptions:) has already handled a
quick action invocation. The system calls a launch method (before
calling this method) when a user selects a quick action for your app
and your app launches instead of activating. The requested quick
action might employ code paths different than those used otherwise
when your app launches. For example, say your app normally launches to
display view A, but your app was launched in response to a quick
action that needs view B. To handle such cases, check, on launch,
whether your app is being launched via a quick action. Perform this
check in your application:willFinishLaunchingWithOptions: or
application:didFinishLaunchingWithOptions: method by checking for the
UIApplicationLaunchOptionsShortcutItemKey launch option key. The
UIApplicationShortcutItem object is available as the value of the
launch option key.
But why there is a need to handle this in didfinishlauncing/willfinishLauncing methods. If the app is in killed state, eventually it will call the performActionForShortcutItem method, so why there is a need to check in didfinish method?
Sample code:
//code
func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool {
var launchedFromShortCut = false
//Check for ShortCutItem
if let shortcutItem = launchOptions?[UIApplicationLaunchOptionsShortcutItemKey] as? UIApplicationShortcutItem {
launchedFromShortCut = true
handleShortCutItem(shortcutItem)
}
//Return false incase application was lanched from shorcut to prevent
//application(_:performActionForShortcutItem:completionHandler:) from being called
return !launchedFromShortCut
}
func application(application: UIApplication, performActionForShortcutItem shortcutItem: UIApplicationShortcutItem, completionHandler: Bool -> Void) {
let handledShortCutItem = handleShortCutItem(shortcutItem)
completionHandler(handledShortCutItem)
}
func handleShortCutItem(shortcutItem: UIApplicationShortcutItem) -> Bool {
var handled = false
//Get type string from shortcutItem
if let shortcutType = ShortcutType.init(rawValue: shortcutItem.type) {
//Get root navigation viewcontroller and its first controller
let rootNavigationViewController = window!.rootViewController as? UINavigationController
let rootViewController = rootNavigationViewController?.viewControllers.first as UIViewController?
//Pop to root view controller so that approperiete segue can be performed
rootNavigationViewController?.popToRootViewControllerAnimated(false)
switch shortcutType {
case .Torquiose:
rootViewController?.performSegueWithIdentifier(toTurquoiseSeque, sender: nil)
handled = true
case.Red:
rootViewController?.performSegueWithIdentifier(toRedSeque, sender: nil)
handled = true
}
}
return handled
}
}
It gives you the flexibility to decide - you can handle it "early" in didFinishLaunching - returning FALSE will inhibit performActionForShortcutItem from getting called later. Or you can return TRUE in didFinishLaunching, and performActionForShortcutItem will still get called.

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