SafeAreas misbehave when presenting a UIViewController - ios

I need to present a UIViewController (ViewControllerTwo) that only supports ".landscape" orientations from another UIViewController (ViewControllerOne) that only supports ".portrait" orientation. If you check the .gif below, you will notice that when the transition occurs it shrinks the content of "ViewControllerOne" and when you dismiss "ViewControllerTwo" the same happens.
The reason why this happens is related to the change of safe areas, which in portrait are different from landscape and vice versa. But if we override supportedInterfaceOrientations of "ViewControllerOne" to just support ".portrait" it should not be informed of the safe area changes if these changes relate to an unsupported orientation right?
Is this a bug/limitation from iOS?
(NO) -> What is the right way to handle this scenario?
(YES) -> What workaround do you recommend to solve this issue in the meantime?
You can check the Example Project here: https://github.com/mantuness/ExampleProject
Check the GIF below:

Related

ios landscape-orientation screen in portrait orientation results

when first entry, the result like this
App into the background and back, the orientation is normal
this is the code for the ViewController:
DDYLoveAutoHallViewController *autoHallViewController = [[DDYLoveAutoHallViewController alloc] initWithEvent:room.currentEventID type:AHRoom_System];
[self presentViewController:autoHallViewController animated:YES completion:nil];
i don't know why, the project is a litter old, it support iOS5 before.
Without understanding on how do you manage layouts it is difficult to give the exact reason, caused you problem, but, i can suggest you couple of little advices:
try to re-check orientation in - (void)viewDidLayoutSubviews, and you can re-position things from there. (probably it will work and solve your problem, but it is not very clean solution, because may be called a few times at time, knowing this you can make it cleaner)
play generally with the methods of layout-lifecycle, to detect where are things is going wrong. Dive deeper in modern way to layout on iOS. (better solution)
Without more details regarding your specific problem, and how you are detecting and adjusting the orientation, it is hard to understand the exact problem, but here are some observations I have made, working with iOS 5.x based (and earlier), apps, that might point you in the correct direction:
[1] Earlier versions of iOS set some defaults, before actually interrogating the hardware to determine orientation and app frame size information.
a) Initially orientation is set to PORTRAIT - along with portrait orientation frame dimensions - during initialization. (This is WRONG if you device is in landscape orientation - so DON’T USE this initial info). (left over from earlier “iPhone only days” - I guess)
b) This continues to be incorrect at the “ViewDidLoad” and “applicationDidBecomeActive” timeframes (at least for my app - possibly - depends on loading time etc…)
c) The correct orientation is yielded later, via the “didChangeStatusBarOrientation method invocation. You can use this information with Window.frame.size information, to display the correct image with the correct size.
This is effectively the trigger to indicate the orientation request will now be correct.
One stategy might be to : Don’t try to display anything until the “didChangeStatusBarOrientation” message has been received.
[2] Non-Code Solution: (using Settings : Supported interface Orientations)
a) If the app is designed to always work in the Landscape orientation, make sure this is reflected in the app settings/info.plist. I would suggest only allowing 1 “supported interface Orientations”, that being Landscape, and all views would reflect the landscape size and orientation.(if your code is not specifically setting or doing anything with orientation, then this might be a solution by setting everything to "landscape only". Otherwise this option probably won't help.)
[3] Last Solution:
a) If you can change the base iOS version higher, the iOS6 and greater versions initialize the orientation and frame sizes earlier in the initialization cycle, so the problem may just disappear due to this.
Here is some of the code used to discover this, along with output below (using an original ipad as a sample, in this case…running iOS 5.1.1 - started in landscape and orientation was unchanged)
-(void) OrientationAndScreenSizeHELPER : (NSString *)fromObject
{
//from:
// NSLog(#"%s:%d someObject=%#", __func__, __LINE__, someObject);
CGRect appFrame = [[UIScreen mainScreen ]applicationFrame];//using frame so status bar is not part of calculations.
appFrame = [[self.viewController view]frame];//using frame so status bar is not part of calculations.
UIInterfaceOrientation orientation = [[UIApplication sharedApplication] statusBarOrientation];
NSLog(#"orientation[%ld] at time[%#] width[%ld] height[%ld]",
(long)orientation,
fromObject,
(long int)appFrame.size.width,
(long int)appFrame.size.height);
}
**Output:**
orientation[1] at time[ViewDidLoad Orientation] width[768] height[1024]
orientation[1] at time[applicationDidBecomeActive] width[768] height[1024]
orientation[3] at time[didChangeStatusBarOrientation] width[1024] height[768]

How to add device orientation to project programmatically in Swift?

Is there a way to add or remove these components programatically?
No, not exactly. You need to set up all the possible user interface orientations your app's view controllers MIGHT support in info.plist. Once you've done that there are view controller methods the system calls to see what orientations an individual view controller supports. (See supportedInterfaceOrientations in the docs.)
As of iOS 8 we're not supposed to use rotation methods any more, so check the docs carefully. It looks to me like supportedInterfaceOrientations is still supported, but the willRotate..., willAnimateRotation..., didRotateFromInterfaceOrientation, etc, are deprecated.
I suggest reading about user interface rotation in the UIViewController class reference (in Xcode or in Apple's online documentation on the web.)

iOS5 Custom Window rotation issue

So I'm creating and showing a custom window in my iOS app because I'm writing a dynamic alert view that also functions like a growl/toast alert. It works AWESOMELY in ios6 (Hopefully I can open source this baby and you can all check it out)
But anyway, when I run this in ios5, the window that my alerts exist on doesn't seem to rotate with the device/simulator. No matter what, my custom window stays in portrait mode.
The UIWindow is just a UIView subclass, so there's no nice 'shouldRotate' delegate method.
I'm kinda stumped on why this is happening in ios5 but not 6. Any help would be GREATLY appreciated ^_^
My window has a rootviewcontroller, which I completely forgot about. I just needed to implement
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation{
return YES;
}
To get it to work.
:-D
It's usually not recommended two use multiple instances of UIWindow in one iOS app. The only valid reason to do so is to support external screens. You should use a UIView instead, ideally managed by a UIViewController.
I assume, (since you didn't provide any code, I can only assume) the reason why your window doesn't 'rotate' is, that it's simply not getting any notifications about device rotation. Only the keyWindow receives them by default.
I would highly recommend to redesign your app to use a properly managed UIView instead. If you desperately don't want that for some reason, you would have to register your instance of UIWindow to receive the UIDeviceOrientationDidChangeNotification and then (in the handler) evaluate what the new orientation is and change the window's frame accordingly (plus maybe other things that need to be done in response to the orientation change)

Xcode force enable application rotation

I am working on an iPad/iPhone tab-bar based application. I have about 30 class files and need to enable rotation in the app, so that iPad users can view at any orientation. As far as I know, every class needs rotation to be enabled by using the following:
// Override to allow orientations other than the default portrait orientation.
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation {
// Return YES for supported orientations.
return YES;
}
However, I have some UIViewControllers created and displayed completely in a single class file, and as far as I know you cannot enable it for that type.
Is there a way I can enable global rotation for the app? I have tried in Info.plist. is there something that can be added to the AppDelegate to enable global rotation?
Btw: I have already tried adding returning YES for rotation in every class file.
Thanks in advance,
Baharini
In Xcode on the Project Navigator click on the project name. Now on center view on the Summary tab, you can see the iPad\iPhone Development Info in this part there is Supported Device Orientations. You can set all of them for supporting any orientation!
I hope it be useful for you!

iPhone app in landscape mode, 2008 systems

Please note that this question is from 2008 and now is of only historic interest.
What's the best way to create an iPhone application that runs in landscape mode from the start, regardless of the position of the device?
Both programmatically and using the Interface Builder.
Historic answer only. Spectacularly out of date.
Please note that this answer is now hugely out of date/
This answer is only a historical curiosity.
Exciting news! As discovered by Andrew below, this problem has been fixed by Apple in 4.0+.
It would appear it is NO longer necessary to force the size of the view on every view, and the specific serious problem of landscape "only working the first time" has been resolved.
As of April 2011, it is not possible to test or even build anything below 4.0, so the question is purely a historic curiosity. It's incredible how much trouble it caused developers for so long!
Here is the original discussion and solution. This is utterly irrelevant now, as these systems are not even operable.
It is EXTREMELY DIFFICULT to make this work fully -- there are at least three problems/bugs at play.
try this .. interface builder landscape design
Note in particular that where it says "and you need to use shouldAutorotateToInterfaceOrientation properly everywhere" it means everywhere, all your fullscreen views.
Hope it helps in this nightmare!
An important reminder of the ADDITIONAL well-known problem at hand here: if you are trying to swap between MORE THAN ONE view (all landscape), IT SIMPLY DOES NOT WORK. It is essential to remember this or you will waste days on the problem. It is literally NOT POSSIBLE. It is the biggest open, known, bug on the iOS platform. There is literally no way to make the hardware make the second view you load, be landscape. The annoying but simple workaround, and what you must do, is have a trivial master UIViewController that does nothing but sit there and let you swap between your views.
In other words, in iOS because of a major know bug:
[window addSubview:happyThing.view];
[window makeKeyAndVisible];
You can do that only once. Later, if you try to remove happyThing.view, and instead put in there newThing.view, IT DOES NOT WORK - AND THAT'S THAT. The machine will never rotate the view to landscape. There is no trick fix, even Apple cannot make it work. The workaround you must adopt is having an overall UIViewController that simply sits there and just holds your various views (happyThing, newThing, etc). Hope it helps!
From the Apple Dev Site:
To start your application in landscape
mode so that the status bar is in the
appropriate position immediately, edit
your Info.plist file to add the
UIInterfaceOrientation key with the
appropriate value
(UIInterfaceOrientationLandscapeRight
or
UIInterfaceOrientationLandscapeLeft),
as shown in Listing 2.
Listing 2: Starting your application
in landscape mode
<key>UIInterfaceOrientation</key>
<string>UIInterfaceOrientationLandscapeRight</string>
Summary and integration from all the posts, after testing it myself; check the update for 4.x, 5.x below.
As of 3.2 you cannot change the orientation of a running application from code.
But you can start an application with a fixed orientation, although doing so this is not straightforward.
Try with this recipe:
set your orientation to UISupportedInterfaceOrientations in the Info.plist file
in your window define a 480x320 "base view controller". Every other view will be added as a subview to its view.
in all view controllers set up the shouldAutorotateToInterfaceOrientation: method (to return the same value you defined in the plist, of course)
in all view controllers set a background view with
self.view.frame = CGRectMake(0, 0, 480, 320)
in the viewDidLoad method.
Update (iOS 4.x, 5.x): the Apple iOS App Programming Guide has a "Launching in Landscape Mode" paragraph in the "Advanced App Tricks" chapter.
References:
interface builder landscape design
interface builder landscape design-1
First I set in info.plist
<key>UIInterfaceOrientation</key>
<string>UIInterfaceOrientationLandscapeRight</string>
then I put this code in applicationDidFinishLaunching:
CGAffineTransform rotate = CGAffineTransformMakeRotation(1.57079633);
[window setTransform:rotate];
CGRect contentRect = CGRectMake(0, 0, 480, 320);
window.bounds = contentRect;
[window setCenter:CGPointMake(160.0f, 240.0f)];
This way I can work on the view in Interface Builder in landscape mode.
sasb's and michaelpryor's answer appears to be correct, but if it's not working for you, try this alternative:
- (void)applicationDidFinishLaunchingUIApplication *)application {
application.statusBarOrientation = UIInterfaceOrientationLandscapeRight;
}
Or this one:
[[UIDevice currentDevice] setOrientation:UIInterfaceOrientationLandscapeRight];
Or this one:
[application setStatusBarOrientation: UIInterfaceOrientationLandscapeRight animated:NO];
You may also have to call window makeKeyAndVisible; first.
A few links: Developing in landscape mode, iPhone SDK: How to force Landscape mode only?
#Robert: please refer to The iPhone SDK, NDA, and Stack Overflow.
I'm surprised no one has come up with this answer yet:
In all my tests when a dismissing a modal view controller the parent view controller's preferred orientation set in shouldAutorotateToInterfaceOrientation is honored even when part of a UINavigationController. So the solution to this is simple:
Create a dummy UIViewController with a UIImageView for a background. Set the image to the default.png image your app uses on startup.
When viewWillAppear gets called in your root view controller, just present the dummy view controller without animation.
when viewDidAppear gets called in your dummy view controller, dismiss the view controller with a nice cross dissolve animation.
Not only does this work, but it looks good! BTW, just for clarification i do the root view controller's viewWillAppear like this:
- (void)viewWillAppear:(BOOL)animated
{
if ( dummy != nil ) {
[dummy setModalTransitionStyle:UIModalTransitionStyleCrossDissolve];
[self presentModalViewController:dummy animated:NO];
[dummy release];
dummy = nil;
}
...
}
The latest iPhone OS Programming Guide has a full section on this, with sample code. I am sure this is a recent addition, so maybe you missed it. It explains all the conditions you have to comply with; basically...
set the Info.plist properties (this changes the position of the status bar, but not the view)
rotate your view manually around its center, on either your UIViewController viewDidLoad: method or your applicationDidFinishLaunching: method or implement auto rotation ("Autoresizing behaviors", page 124)
Look for "Launching in Landscape Mode", page 102.
See this answer: Landscape Mode ONLY for iPhone or iPad
add orientation to plist
shouldAutorotateToInterfaceOrientation = YES in all files
Although if you're using mixed modes, you might be better off with
[[UIDevice currentDevice] setOrientation:UIInterfaceOrientationLandscapeRight];

Resources