Autorotation in ios 5 vs. ios 6 issues - objective-c

I have an iPad app that must support iOS 5.0 and later. I have a bug that behaves differently in 5.0/5.1 than it does in 6.0. The issue is a view controller in a tabbarcontroller that pushes a modal view, which in turn pushes a full-screen view via navigationController. The problem is, when in the full-screen view, if the iPad is rotated, the underlying viewcontroller (one in the tabbarcontroller) doesn't rotate. Now let me break down the differences in iOS versions:
First of all, this viewController in question implements shouldAutoRotateToInterfaceOrientation (returns YES) as well as willRotateToInterfaceOrientation and willAnimateRotationToInterfaceOrientation.
In iOS 6.0, I noticed that the rotation methods (willRotate... & willAnimate...) were not being called, so I registered it to receive the UIDeviceOrientationDidChangeNotification notification and execute the code from the two Rotate methods if I received that notification and the other methods hadn't executed. That fixed the issue in iOS 6.0.
Problem is, in 5.0/5.1 the rotation methods (willRotate... & willAnimate...) ARE being executed, but the view is not rotating. If the "full-screen view" is not presented over top of this view controller and the iPad is rotated, these two methods execute and the views rotate accordingly.
Please help. Thanks in advance.
Things I've tried other than that stated above.
I've tried checking the UIDeviceOrientation and converting it to a UIInterfaceOrientation and calling [self shouldAutorotateToInterfaceOrientation:xxx]; The view still displays wrong.

When the two rotation methods are being executed, do the CAAffineTransformation for your view. when you are back to normal, again do the same with -90 degree.
https://developer.apple.com/library/ios/#documentation/GraphicsImaging/Reference/CGAffineTransform/Reference/reference.html

Related

Need a way to force a UIInterfaceOrientation rotation without iOS device rotating

I need to know if there is a way to tell a iOS7 device to set a views orientation without the device being rotated. Some way in code to trigger the device to calling the code that tells it which way to display the view.
If the device is in landscape and remains held in landscape orientation while a certain change happens I want to force a change to show the view in portrait orientation, at which point the user would need to turn the device to look at it properly. I'll explain why below
Looking at my app might make my description clearer - it is free to download
I have a number of view controllers (embedded in navigationControllers) and only one of them needs to be rotated into landscape and then only under certain conditions.
Solutions here on StackOverflow seem to be to make a category on UINavigationController giving it shouldAutorotate and supportedInterfaceOrientations methods and then use those methods in the individual viewControllers to block or allow rotations.
This has worked for me .... however
On the one view controller I wish to rotate , I don't want it to rotate all the time.
This view controller is the diveSiteDetailsController, (if you have downloaded the app you need to select dive sites on the first page then click the '+' to see it). It has a UISegmentedController and 4 subviews (3 tableviews and 1 other UIView). The current version on the App Store works fine now i've solved this - but looking at it may help you understand my issue better).
On diveSiteDetailViewController the UISegmentedController is used to switch between the 4 subviews.
All the subviews are used to enter data about the same dive site but as there is a lot of potential data, I have broken it into logical chucks each of which is a subview - location, data (depths,currents, visibility), type of environment and notes.
The .hidden property of each subview is used to make them appear and disappear.
I only want the second subview to rotate (the data view - it has some sliders on it that are easier to work with if in landscape).
restricting this rotation is easy - iI achieved it like this
- (NSUInteger)supportedInterfaceOrientations{
if (self.dsDataRangeSlidingTV.hidden) {
return UIInterfaceOrientationMaskPortrait;
}
return UIInterfaceOrientationMaskAllButUpsideDown;
}
Now the view will only rotate to landscape when the data table view is displayed.
However, once in landscape, if I chose a different subview with the UISegmentedController then they are, obviously, shown in landscape also as the iOS device hasn't done a rotation. This is the situation I am trying to avoid.
Rotating the iOS device will return those views to portrait as expected but i need to trigger the device to to reevaluate its display when I use the UISegmentedController to switch from the data subview to another subview and its that triggering that I don't know how to do.
any suggestions greatly received.
Heres a workaround that is working for me
I've added the following few lines to the end of my method that responds to the UISegmentedControl being tapped.
UIViewController *aDummyController = [[UIViewController alloc]init];
[self presentViewController:aDummyController animated:NO completion:nil];
[self dismissViewControllerAnimated:NO completion:nil];
adding a new viewController and popping it off triggers the rotation . This is a kludgey way of achieving what I wanted.
I found the solution in this post
Is there a documented way to set the iPhone orientation?
all credit to Josh who although not the accepted answer is the one that 99 people currently have up voted.
I still have a bug in that, if I were holding the device in landscape (although the display is portrait view) whilst on the screen that segues into the diveSiteDetailsController then the initial view the diveSiteDetailsController display will be in landscape.
To get around this I created a Bool property called notThisTime on the diveSiteDetailsController and set it to true in the prepareFor Segue on the viewController that called it.
i then did changed supportedInterfaceOrientation to
- (NSUInteger)supportedInterfaceOrientations
{// DLog(#"Running %# '%#'", self.class, NSStringFromSelector(_cmd));
if (self.notThisTime){
return UIInterfaceOrientationMaskPortrait;
}
if (!self.dsDataRangeSlidingTV.hidden) {
return UIInterfaceOrientationMaskAllButUpsideDown;
}
then at the end of the ViewDidLoad method I added
self.notThisTime = NO;
I would still love to hear from anyone with a suggestion how better to handle this. pushing and popping a dummy view to get the iPhone to do an orientation check seems like a work around for something that should just be available as a standard method call.
One final Note - the iOS simulator does not like this - you need to check on the device - it sometimes tries to draw the iPhone container in landscape while the screen is drawn vertically - however it does work fine on the iPhone

Landscape xib for ipad version only

I have a universal app with seperate xibs for iPhone and iPad
For the iPad version, I want my one of my iPad xibs in landscape mode. I have set it to landscape in simulated metrics, (The app is set for portrait in the summary screen) and the landscape view still shows in portrait when run. Im sure I read on here a naming convention that tells the app the xib is in landscape ie: view1_one.xib~ipad-landscape
Ive tried using screen rotation methods but iOS 6 screen rotation is just proving so frustrating as I have tried so many solutions all of which have no effect. I have done screen rotation before in iOS 6 but I was using storyboards and subclassed a navigation controller for my chosen view, I dont know how to do this with this code as I picked it ip from someone else
So to sum up: How can I get my screen to respect the landscape xib I have created in interface builder instead of showing it in portrait
I would point out I have searched on here for a solution and spent many hours on this before posting this
There are naming conventions for resources (including xib's) that specify on which device type they are loaded. However, these do not exist for specific orientations. -landscape won't do anything extra (more specifically, it will probably load the resource on an iPhone as well, which isn't what you want).
http://developer.apple.com/library/ios/#documentation/Cocoa/Conceptual/LoadingResources/Introduction/Introduction.html#//apple_ref/doc/uid/10000051i-CH1-SW2
As for handling orientation changes, make sure you implement both the iOS 5 and below methods and the iOS 6 methods for handling them:
// Older versions of iOS (deprecated)
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation {
return UIInterfaceOrientationIsLandscape(toInterfaceOrientation);
}
// iOS6
- (BOOL)shouldAutorotate {
return YES;
}
// iOS6
- (NSUInteger)supportedInterfaceOrientations {
return UIInterfaceOrientationMaskLandscape;
}
// Added after comment
- (UIInterfaceOrientation)preferredInterfaceOrientationForPresentation {
return UIInterfaceOrientationLandscapeLeft;
}
This is the official way to ensure that your viewController is only loaded in landscape.
Edit:
I added the preferredInterfaceOrientationForPresentation method as well. While personally I don't like this method, it forces the viewController to present in that orientation, until the next orientation change. Not nice, but it will help you to see if your orientation methods get called at all.
Also try to set a breakpoint in each of these methods. If they don't get called at all, your issue might be with the subclassing. Be certain that the viewController in the storyboard is set to the subclass and not the superclass.
Edit2:
Check this in Interface Builder:

Application Lauch in Landscape mode while Simulator/Device is in Portrait mode in ios6

My application window has UITabBarController as a RootViewController. Then UINavigationController as TabBarController's RootViewController. Then another HomeViewController as NavigationController's RootViewController.
When I launch my application in Portrait mode, then HomeViewController's UIView outlets displayed in Landscape mode. All UIView outlets have Landscape mode coordinate. Because return Orientation is Landscape.
I found many Q&A, Blogs. I applied whatever other developers said, but not succeed.
This issue occurs only in ios6 device/iPhone simulator 6.
Right now I am working on Simulator and its show this issue.
Please help me as soon as possible.
Ask me, if I am not capable to explain my question.
Thank you in advance.
In iOS 6, the app looks at your predefined possible orientations from your project file. Check if that only lists landscape, also it uses the shouldAutoRotate method, so you might have to implement that as well.
Check this for more info:
Similar question

iOS6 rotate methods not called when launching in landscape

Let me start off by saying I'm not having a problem when rotating views in iOS6 after the app is open. This issue is only happening for me when the app is launched for the first time while in landscape. The new shouldAutorotate and supportedInterfaceOrientations methods are both called when launched, however none of the rotation methods are called, like willRotateToInterfaceOrientation:duration:. (shouldAutorotate is always returning YES, and supportedInterfaceOrientations is always returning UIInterfaceOrientationMaskAll)
In iOS5, the 'first' orientation to landscape on launch was taken care of automatically. Is there an explanation for why the device wouldn't call this first landscape rotation in iOS6? (The view controller I'm checking is the root controller of the window/app delegate).
Thanks in advance for any help with and insight into this.
I suppose that since the interface is not actually rotating, that the method isn't being called.
If you want to do some setup based on the orientation, have you thought of using the view controller's intefaceOrientation property?
You should now use the viewWillLayoutSubviews method and not willRotateToInterfaceOrientation:duration:. The reason is because willRotateToInterfaceOrientation:duration: is not guaranteed to be called in a number of situations.
This is stated in the iOS6 release notes among other places.

UIScrollView not functioning correctly after Modal view controller displayed in iOS 5.1

I have a strange problem when using a UIScrollView controller combined with iPhone 4 and iOS 5.1.
I have a UIScrollView which has a content size of 640x480 (double screen effectively) and in addition to the swipe to switch between the two "screens" I also permit the user to tap the screen in response to which I call something like...
[scrollView scrollRectToVisible:(CGRectMake 320,0,320,480) animated:YES];
the first 320 would be 0 if the tap occurred whilst the right hand side of the scroll view was displayed (note the scroll view has paging enabled so it can only come to rest either fully left or fully right).
I also have a situation where I sometimes display an additional view controller modally using presentModalViewController over this view controller containing the scroll view.
Everything works perfectly until the modal view controller is presented and subsequently dismissed after which the scrollRectToVisible method will no longer work if animated is set to YES (if I change animated to NO then it works as expected). Note, the tap is still being registered and the scrollRectToVisible being called, it just doesn't do anything when animated is set to YES).
Here's the kicker, this bug only occurs on an iPhone 4 runnings iOS 5.x.
It works perfectly (even after the modal view controller has been displayed) on my:
iPhone 3G running 4.x,
iPhone 3GS running 3.x,
iPod touch (2nd Gen) running 4.x
and most surprisingly the simulator running 5.x.
I wondered if this was a bug in the animation system so disabled the animation on the modal view controller presentation and dismiss and this had no effect, problem still occurred on the iPhone 4 with iOS 5.1.
Anyone got any ideas as to what might be causing this and how I might work around it?
Finally tracked this down. what a pig...
I'm embedding a view from a view controller as a subview of another view controllers view. So my scroll view contains a view which also has an associated view controller.
Prior to iOS 5.x the methods viewWillAppear, viewWillDisappear, viewDidAppear and viewWillDisappear are never called on the sub views view controllers, only the main view controller. Already knowing this I set up my main view controller to manually call the sub views view controllers methods when these events happen.
However it appears that in iOS 5.x this issue has been "fixed" so where I was manually passing the call to viewWillAppear to my sub view controller I no longer need do this under 5.x as the method automatically gets called under 5.x - as a result it's now being called twice under 5.x but still only once when running on a 4.x or earlier device.
As a result, under 5.x my NSTimer used to call my updateUI method is being created twice, but because in viewDidDisappear I only destroy the timer if it is non nil it only gets destroyed once - therefore I'm leaking NSTimers under 5.x through double allocation where I'm not under 4.x.
As a result of multiple NSTimers hanging around all repeatedly calling my updateUI method is that the constant updating of the UI is killing the animation system and so the animation for the scrollView fails when running on an actual device. I guess it continued working OK on the simulator running 5.x as the CPU in the Mac is more than capable of handling the extra workload and still performing the animations correctly.
A simple check in my viewWillAppear method to ensure the NSTimer hasn't already been created has fixed the problem and has kept compatibility with 4.x and earlier.
I frustratingly run up against these kinds of issues every time Apple update their iOS by major versions... The morale of this story is don't assume that long standing classes still exhibit the same behaviour under different revisions of the OS.
I had the same problem. I realized that after modalViewController is dismissed my UIScrollerView shifts downs by 20px, which is the same height as status bar. So, it means when my UIViewController is loaded and UIScrollView is created, UIScrollView thinks there is no status bar, when actually it is there.
So I tried to put in viewDidLoad:
[[UIApplication sharedApplication] setStatusBarHidden:NO];
Now my UIScrollView always stays under status bar, with Y position 20px. It never shifts down.
I finally managed to get this working on an iPhone4 running 5.1. Ensuring the bounces horizontally property for the scroll view is set fixed the problem, though why having this unchecked should cause the problem in the first place is beyond me - I'm pretty certain this is a bug in iOS.