I am detecting the device orientation with these lines of code:
UIDevice.currentDevice().orientation.isPortrait.boolValue
UIDevice.currentDevice().orientation.isLandscape.boolValue
And I detect check if it's an iPad with this code:
userInterfaceIdiom == .Pad
I used this code in commonInit() function which is called in the Init() function. When I execute my code on iPad the two first lines return both false which is not correct, one of them should be true. The third line is working fine.
If I use the code in other functions, such as supportedInterfaceOrientations(), it works fine. Do you know what could be the problem?
You are probably neglecting this documentation:
You also use the UIDevice instance to detect changes in the device’s
characteristics, such as physical orientation. You get the current
orientation using the orientation property or receive change
notifications by registering for the
UIDeviceOrientationDidChangeNotification notification. Before using
either of these techniques to get orientation data, you must enable
data delivery using the beginGeneratingDeviceOrientationNotifications
method. When you no longer need to track the device orientation, call
the endGeneratingDeviceOrientationNotifications method to disable the
delivery of notifications.
Also, this is a 3-D orientation. You probably don't want that. What is the actual value of simply the orientation property? See:
enum UIDeviceOrientation : Int {
case Unknown
case Portrait
case PortraitUpsideDown
case LandscapeLeft
case LandscapeRight
case FaceUp
case FaceDown }
Probably what you really want is here:
"interfaceOrientation" is deprecated in iOS 8, How to change this method Objective C
Sometimes TraitCollections doesn't fill all your design needs. For
those cases, Apple recommends to compare view's bounds :
if view.bounds.size.width > view.bounds.size.height {
// ... }
Related
I have an UIViewController that supports all UIInterfaceOrientationMasks
But, in one certain case I need to prevent it from rotation
Before iOS 16 i was just handling this case like this
override var shouldAutorotate: Bool {
return !screenRecorderIsActive
}
And everything was working fine
After update to iOS 16 my controller keeps rotating and I can't find a way to fix it
In my case, I need to prevent auto rotation not based upon a particular orientation, but rather based upon what you're doing in the app and what kind of hardware your device has. And, I need to continue to support iOS versions all the way back to 9.3. These updates forced me to to do the following:
The new functions aren't available back in 9.3, so I have to do some checking if the version of iOS is 16.x. If so, then I had to implement supportedInterfaceOrientations so that the current user interface orientation is queried and only returns TRUE if the orientation requested is the same as the current user interface orientation. In other words, don't allow a change.
Also, since both returning from the background or rotations or events from other view controllers can change my logic choice for which orientations are allowed, I had to be sure to call the setNeedsUpdateOfSupportedInterfaceOrientations method when returning from the background or any other time I needed to prevent auto rotation.
Again, I had to wrap this code in iOS version checks. Finally I had to implement things the old way for older versions of iOS.
I was very disappointed that such a breaking change was introduced. Yes, the methods were deprecated for a long time, but the new methods weren't introduce until 16.0 - and even more critically, my code does different things when using the front landscape camera now available on the iPad 10, so I had to wait until I had a unit in my hands to uncover these issues.
Quoted from the iOS 16 release notes:
[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
To implement dynamic supported interface orientations, you can use some code like this:
var screenRecorderIsActive: Bool {
didSet {
setNeedsUpdateOfSupportedInterfaceOrientations()
}
}
override var supportedInterfaceOrientations: UIInterfaceOrientationMask {
if screenRecorderIsActive {
return [.landscape] // For example, or a variable representing the orientation when the condition was set
}
return [.all]
}
I have been trying to change the device orientation on a button click event for 2 days but I am not able to achieve it properly.
So, I have an iPhone app with a minimum version of 12.4, and the device that I am using to test is 14.4. I have used the code mentioned in this project here (which works properly when presenting a new view controller using push or present) but the same doesn't work when on the same view controller. The user needs to rotate his/her device to initiate the orientation change.
This is the code that I have in the view controller that I am trying to rotate on a button click event.
let appDelegate = AppDelegate.sharedInstance
let oldOrientaion = appDelegate.deviceOrientation
appDelegate.deviceOrientation = oldOrientaion == .landscapeRight ? .portrait : .landscapeRight
let value = appDelegate.deviceOrientation.rawValue
UIDevice.current.setValue(value, forKey: "orientation")
Can someone please help me in figuring out what exactly is missing from this?
Also, on a side note, the view controller is presented on a different view controller so even if I try to present a new view controller like in the project for some time and change the orientation there it doesn't work.
Edit:
This is fixed now. I was trying to use the UIInterfaceOrientationMask to set the orientation instead of UIInterfaceOrientation. So changing the code to use UIInterfaceOrientation at the end works properly now.
Thanks for the help.
You are doing everything correctly, just need to call the attemptRotationToDeviceOrientation method to the oration change to take effect. Based on the documentation:
Some view controllers may want to use app-specific conditions to
determine what interface orientations are supported. If your view
controller does this, when those conditions change, your app should
call this class method. The system immediately attempts to rotate to
the new orientation.
In your code it will look like:
UIViewController.attemptRotationToDeviceOrientation()
My app is crashing when you return to it after switching away from it using the 4-finger task-switch gesture on an iPad.
When the user does the 4-finger gesture to switch away from my app, I see applicationWillResignActive: then applicationDidEnterBackground: in my app delegate, then (assuming we're currently in portrait orientation) my top-level view controller gets viewWillTransitionToSize:withTransitionCoordinator: with a size that indicates landscape layout (even though the device has not rotated). This of course results in a lot of resizing and rearranging of views for the new orientation. Immediately after that I get viewWillTransitionToSize:withTransitionCoordinator: with a size that indicates portrait (the original orientation of the device). And again, I go through all my layout again for the new (actually, original) orientation.
What I'm finding is that if I wait for all of this to complete, I can switch in and out of my app all day. If, on the other hand, I switch back to my app while this needless work is going on, I get a crash deep in some iOS transition code.
At this point I'm trying to understand why I get these stray rotation events. If I can avoid getting those, I can avoid getting into whatever situation is causing the crash. They don't seem necessary.
I can't think of a reason why it would be useful or correct to get viewWillTransitionToSize in the background, so just bounce out if you are in the background:
if UIApplication.shared.applicationState == .background {
return
}
Still, this feels like a bug, and in my opinion you should report it to Apple.
It turns out there isn't a way to prevent the rotation events from being reported to the app. I suspect that's an iOS bug. However, ignoring viewWillTransitionToSize:withTransitionCoordinator: when the application state is UIApplicationStateBackground and doing the same in the view's layoutSubviews (if present) allowed me to work around the problem.
I am wanting to detect where the status bar is on my current view in order to determine which segue to perform. I know the preferred way to do this is to determine the device orientation, but there are two problems with this approach for me:
1.) If the device is not angled far enough away from vertical or horizontal then there is no device orientation detected and the segue doesn't happen
2.) Under certain conditions I am going to "lock" the display orientation such that even though the physical device orientation is landscape the screen is going to be locked to portrait and I will want to perform the portrait segue I have created.
The problem is that the " [UIApplication sharedApplication].statusBarOrientation = " is not returning the actual orientation of the status bar. Is there not an easy way to detect this? Otherwise I am going to have to write a bunch of messy code to keep track of this.
Have you tried: [[UIDevice currentDevice] orientation]?
Note:
Depending on the design of your app it might be necessary to call [[UIDevice currentDevice] beginGeneratingDeviceOrientationNotifications]. If you do that, make sure to call [[UIDevice currentDevice] endGeneratingDeviceOrientationNotifications] at some point.
If that's not sufficient for your purpose I guess you have to manually check the accelerometer. Take a look at: Handling Motion Events for more info on how that's done.
I am working in flash CS5.5 on an app for iOS. I want to get the ipad/iphone to stop animating the orientationChange and just change it directly, is this possible?
I thought this was a solution but it didnt help AS3 - iOS force landscape mode only?.
If you try setting Stage.autoOrients = false;, the flash.events.StageOrientationEvent.ORIENTATION_CHANGE will never fire. That's helpful for disabling orientation changes altogether, but not for your issue. While I haven't tried it myself, you may be able to listen to the event:
flash.events.StageOrientationEvent.ORIENTATION_CHANGING
You may be able to call event.preventDefault() in that listener to stop the actual rotation from occuring. Then you can manually set it yourself:
Stage.setOrientation(StageOrientation.ROTATED_RIGHT);
have you tried the SO answer: Disable orienation change rotation animation ?
the code from that answer that goes in the view-controller that is the home for your flash CS5.5 or air 3.5 is:
- (void)didRotateFromInterfaceOrientation:(UIInterfaceOrientation)fromInterfaceOrientation {
[UIView setAnimationsEnabled:YES];
}
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation {
[UIView setAnimationsEnabled:NO];
return TRUE; /* Your original orientation booleans, in case you prevent one of the orientations */
}
that code makes use of native iOS UIViewController functions that can be overridden. you would have to have a native iOS objective C class that overrides UIViewController, and then you could insert the code above. calls are made when the device is rotated to these as part of view controller life cycle.