How to fix alertView orientation on specific controller? - ios

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

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 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

Swift Selective Orientation Issues moving from Portrait to Landscape

Environment:
Using the latest Xcode 8.3
Language: Swift3
Devices are all updated (iPhone 7 v10.3.1)
(Target -> Deployment Info -> Device Orientation) is set to Portrait for all options for 'Devices'
Scenario:
I have 2 ViewControllers (VC1 and VC2), both which inherit from UIViewController.
VC1 is always meant to be portrait
VC2 is always meant to be landscape
VC1 and VC2 have all their subviews and objects configured and added to the ViewController's view in the viewDidLoad call.
I am presenting VC2 from VC1 via the call (as I need a nav bar):
let vc2 = UINavigationController(rootViewController: VC2())
self.present(vc2, animated: true, completion: nil)
Whether VC2 inherits from a UINavigationController or UIViewController has made no difference to the occurrence to the issue.
AppDelegate.swift enforces the orientation as such:
func application(_ application: UIApplication, supportedInterfaceOrientationsFor window: UIWindow?) -> UIInterfaceOrientationMask {
if let rootViewController = self.topViewControllerWithRootViewController(rootViewController: window?.rootViewController) {
if rootViewController is VC2 {
let vc2 = rootViewController as! VC2
if vc2.isPresented {
return .landscapeRight
}
}
return .portrait
}
The above function uses this function to find the topViewControllerWithRootViewController:
private func topViewControllerWithRootViewController(rootViewController: UIViewController!) -> UIViewController? {
if (rootViewController == nil) {
return nil
}
if (rootViewController.isKind(of: UITabBarController.self)) {
return topViewControllerWithRootViewController(rootViewController: (rootViewController as! UITabBarController).selectedViewController)
} else if (rootViewController.isKind(of: UINavigationController.self)) {
return topViewControllerWithRootViewController(rootViewController: (rootViewController as! UINavigationController).visibleViewController)
} else if (rootViewController.presentedViewController != nil) {
return topViewControllerWithRootViewController(rootViewController: rootViewController.presentedViewController)
}
return rootViewController
}
Issue:
This usually always works however in some instances the view will result in VC2 being presented vertically with properties being derived from a horizontal view:
Here
This happens randomly with no errors being shown in Xcode (including it's debug console).
Additional Notes:
Please note there are tasks being run on background threads that require the use of the GPU. These are declared from ViewControllers other than VC1 and VC2.
Perhaps this might cause time sensitive device orientation functions to be called in the incorrect order.
I have tried the implementations from the following links:
http://www.jairobjunior.com/blog/2016/03/05/how-to-rotate-only-one-view-controller-to-landscape-in-ios-slash-swift/

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