Where to define the -shouldAutorotate method in iOS 6? - objective-c

I am trying to define the shouldAutorrotate method, but I don't know where to define it as it's never being called. I have a UITabBarController, with three tabs (each one, with a root navigation controller) in my project. My aim is to disable autorotation in some specfic cases.
Thank you!

OK, solved. What I did: In my topmost navigation controller I defined
-(BOOL)shouldAutorotate {return [self.visibleViewController shouldAutorotate];}
and then, in my next viewController
-(BOOL)shouldAutorotate {return NO;}
Thanks guys!!!

you can write that method in viewcontroller.m file, for which you want to disable autorotation
Here is the code for iOS 6:
#ifdef IOS_NEWER_OR_EQUAL_TO_6
-(BOOL)shouldAutorotate
{
return NO;
}
#endif

Read the iOS 6.0 Release Notes:
Autorotation is changing in iOS 6. In iOS 6, the
shouldAutorotateToInterfaceOrientation: method of UIViewController is
deprecated. In its place, you should use the
supportedInterfaceOrientationsForWindow: and shouldAutorotate methods.
More responsibility is moving to the app and the app delegate. Now,
iOS containers (such as UINavigationController) do not consult their
children to determine whether they should autorotate. By default, an
app and a view controller’s supported interface orientations are set
to UIInterfaceOrientationMaskAll for the iPad idiom and
UIInterfaceOrientationMaskAllButUpsideDown for the iPhone idiom.
A
view controller’s supported interface orientations can change over
time—even an app’s supported interface orientations can change over
time. The system asks the top-most full-screen view controller
(typically the root view controller) for its supported interface
orientations whenever the device rotates or whenever a view controller
is presented with the full-screen modal presentation style. Moreover,
the supported orientations are retrieved only if this view controller
returns YES from its shouldAutorotate method. The system intersects
the view controller’s supported orientations with the app’s supported
orientations (as determined by the Info.plist file or the app
delegate’s application:supportedInterfaceOrientationsForWindow:
method) to determine whether to rotate.
The system determines whether
an orientation is supported by intersecting the value returned by the
app’s supportedInterfaceOrientationsForWindow: method with the value
returned by the supportedInterfaceOrientations method of the top-most
full-screen controller.
The setStatusBarOrientation:animated: method
is not deprecated outright. It now works only if the
supportedInterfaceOrientations method of the top-most full-screen view
controller returns 0. This makes the caller responsible for ensuring
that the status bar orientation is consistent.
So I would first try to implement the behaviour in the app delegate. If that’s too coarse for your use case, I would try to implement the -shouldAutorotate (note the single r!) method for the individual content view controllers. If that does not work (see the quote above), implement this method in your container controller, ie. the tab bar controller or the navigation controller.
See also the WWDC 2012 Session #236, The Evolution of View Controllers on iOS.

Related

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.

Minimum steps to get autorotate to work

I've trying to implement autorotate but my app is not listening to me!
The app has a tab bar controller which supervises 3 view controllers. The tab bar is created programatically in the app delegate. Each of the view controllers has this standard simple method:
- (BOOL) shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
{
return YES;
}
The app delegate looks like this:
self.tabBarController = [[UITabBarController alloc] init];
self.tabBarController.viewControllers = [NSArray arrayWithObjects:gameVC, settingsVC, helpVC, nil];
self.window.rootViewController = self.tabBarController;
In addition, in the target summary area I have all 4 orientations for both the iPad and iPhone activated.
In the simulator, no rotation occurs with either device. I seem to be missing something. Perhaps one more setting is needed? Something out of order? There is nothing else in the project related to rotating views.
The only thing that you seemed to not have said in your response that I can think of is changing the device orientations under your info.plist. I know from personal experience that if you click on the supported device orientations in the target summary area, it might not actually change it in the Info property list. Check and make sure that all four are selected in the property list by doing the following:
Go to your Info.plist
Look under Supported interface orientations and Supported interface orientations (iPad)
Make sure that it has 4 strings under both: Portrait (bottom home button), Portrait (top home button), Landscape (left home button), Landscape (right home button)
User a ViewController for super purpose, and then inheritance it in the each of view controllers. In the super ViewController add this
(BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation{
return YES;
}
So, you just need to do once to make them autorotate
from http://developer.apple.com/library/ios/#DOCUMENTATION/WindowsViews/Conceptual/ViewControllerCatalog/Chapters/TabBarControllers.html#//apple_ref/doc/uid/TP40011313-CH3-SW26
Tab bar controllers support a portrait orientation by default and do
not rotate to a landscape orientation unless all of the contained view
controllers support such an orientation. When a device orientation
change occurs, the tab bar controller queries its array of view
controllers. If any one of them does not support the orientation, the
tab bar controller does not change its orientation.
#Zack #AlexanderZats This was subtle. I was reading this SO answer which brought me here This 2nd link is a great discussion of different possible reasons an app may not rotate. The last point caught my attention. Sure enough, I was overriding initWithNibName and not calling super on it. I think this ultimately meant that the the VCs were not in the responder chain. A huge thanks to all who gave me ideas and suggestions!

Only support orientation for modal UIViewController

My app has a UINavigationController, it does not support rotation. However I want to show a modal view controller on top of the navigationcontroller that should support rotation. Is this possible? I tried to override shouldAutorotateToInterfaceOrientation on the view controller that is shown modally but that doesn't seem to work.
I think that in addition to shouldAutorotateToInterfaceOrientation of the view controller that is shown modally returning YES, your navigation controller's shouldAutorotateToInterfaceOrientation should be overridden to return YES when that modal view controller is showing, and NO otherwise.
You need to make sure your device generates device orientation notifications (UIDeviceOrientationDidChangeNotification):
make sure:
generatesDeviceOrientationNotifications is set to true
From the Apple docs:
"The window object does much of the work associated with changing the current orientation. However, it works in conjunction with the root view controller to determine whether an orientation change should occur at all and, if so, what additional methods should be called to respond to the change. If this controller is a container, it may rely on a child to decide whether the orientation should occur."
So if you root view controller (UINavigationController?) doesn't support rotations then this might be set to false when your app starts. In which case you will need to turn it back on when appropriate:
UIDevice myDevice = [UIDevice currentDevice];
[myDevice beginGeneratingDeviceOrientationNotifications];
I found the answer in another post: UIViewController inside a root ViewController not rotating
The key is
- (void)addChildViewController:(UIViewController *)childController
and
- (BOOL)automaticallyForwardAppearanceAndRotationMethodsToChildViewControllers

Multiple Presented View Controllers and Rotation on iPad

I have recently run into an issue when porting some code from an iPhone app over to the iPad. It may be related to the issue described here, though I found the explanations/solutions of that question unsatisfactory. The scenario is this:
View controller 'A' (The Root View Controller) presents a modal view controller (call it 'B') with the "Form Sheet" modal presentation style.
View controller B presents view controller 'C' with the "Full Screen" modal presentation style.
The iPad is rotated while view controller C is the top-most presented view controller.
Upon dismissal of C, B is re-displayed, but has the incorrect orientation.
As far as I can tell, there should not be an issue with chaining of multiple presented view controllers -- in fact, this behavior is explicitly supported in the Presenting View Controllers from Other View Controllers documentation. I have also read the following statement in the iOS 5 Release Notes:
Rotation callbacks in iOS 5 are not applied to view controllers that are presented over a full screen. What this means is that if your code presents a view controller over another view controller, and then the user subsequently rotates the device to a different orientation, upon dismissal, the underlying controller (i.e. presenting controller) will not receive any rotation callbacks. Note however that the presenting controller will receive a viewWillLayoutSubviews call when it is redisplayed, and the interfaceOrientation property can be queried from this method and used to lay out the controller correctly.
As far as I can tell, this does not occur -- View controller B receives a call to -shouldAutoRotateToInterfaceOrientation but the value the interfaceOrientation parameter in this call is the value of view controller B's interface orientation when it presented view controller C, not the value of C's interface orientation upon dismissal. Since we're on an iPad, all these view controllers return YES in -shouldAutoRotateToInterfaceOrientation. Thus the bounds of B's view never change, so -willLayoutSubviews is never called.
I have tried saving the orientation of view controller C in a callback to B before B dismisses it, and then using that information the next time -shouldAutoRotateToInterfaceOrientation is called and returning YES only for the orientation of C when it is dismissed. This fixes, the broken UI that appears without making this check, but view controller B does not update its interface orientation to this value, so subsequent modal presentations will animate in/out from the wrong side of the device.
Has anyone been able to successfully get a view controller configuration like this working? It doesn't seem like that unusual of a scenario, so I am a little surprised that it isn't working as I initially expected it to.
Thanks in advance.
In my opinion multiple chained modal view controllers result in a confusing and annoying user experience if you don't use a navigation controller. I think View controller B should be in a navigation controller (you don't have to show the nab bar if you don't want).
Modal presentation is really supposed to be for single dead-ended entities (a single view controller or a navigation controller containing multiple children view controllers).
Out of interest, are you saying that this works fine on iPhone but not on iPad? Or did you not allow rotation on the iPhone version?
I've also found this thread which says that presenting your modal view controllers from the root view controller may help.
I have worked on multiple modal view controllers being presented on iPhone. There is no problem with layout, unless there is something wrong with my own code for handling multiple orientations. Auto rotation methods actually never get called when view controller is behind another view controller, so I would also adjust layout on viewWillAppear: as well.
On viewWillAppear:, willRotateToInterfaceOrientation:duration:, and didRotateToInterfaceOrientation:, I would adjust the layout to the correct orientation as needed, for example:
- (void)viewWillAppear:(BOOL)animated {
[super viewWillAppear:animated];
[self switchToInterfaceOrientation:self.interfaceOrientation];
}
- (void)willRotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation duration:(NSTimeInterval)duration {
[super willRotateToInterfaceOrientation:interfaceOrientation duration:duration];
[self switchToInterfaceOrientation:toInterfaceOrientation];
// be careful, self.view.frame is still according to self.interfaceOrientation
}
- (void)didRotateFromInterfaceOrientation:(UIInterfaceOrientation)fromInterfaceOrientation {
[super didRotateFromInterfaceOrientation:fromInterfaceOrientation];
// self.view.frame is updated
// update something else here
}
- (void)switchToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation {
// update your layout here
}
I'm not sure about how the above code would behave on view controllers on iPad. Since it supports view controller with different modal presentation styles, there might be some surprises.

The child view does not rotate from landscape to portrait and vice versa

I'm making an application for the iPad.
I have a view controll that has to stay in landscape, this works just fine.
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation
{
return UIInterfaceOrientationIsLandscape(toInterfaceOrientation);
}
From this view i push towards an other view, this child view should rotate to the appropriate rotation (landscape or portrait) whenever the user tilts his ipad.
in this child view i use this code to make this happen, but it doesn't work. It sticks to the landscape.
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
{
return YES;
}
In order for a view controller to support rotation, all view controllers in its hierarchy must support rotation.
From the Responding to Orientation Changes documentation:
The window looks for an appropriate view controller and calls itsshouldAutorotateToInterfaceOrientation:method to determine if it supports the new orientation.
Container view controllers may intercept this method and use their own heuristics to determine whether the orientation change should occur. For example, the tab bar controller allows orientation changes only if all of its managed view controllers support the new orientation.
Further, you should not be using multiple view controllers to manage a single screen.
From the View Controller Programming Guide documentation (emphasis mine):
The one-to-one correspondence between a view controller and the views in its view hierarchy is the key design consideration. You should not use multiple content view controllers to manage different portions of the same view hierarchy. Similarly, you should not use a single content view controller object to manage multiple screens’ worth of content.
In this case, I'd suggest disabling rotation handling in your parent view controller, changing the child view controller to be simply a view (to meet the above criteria), and manually monitoring orientation changes to update your child view's layout.
You can monitor for orientation changes by listening for the UIDeviceOrientationDidChangeNotification notification. Example code:
[[UIDevice currentDevice] beginGeneratingDeviceOrientationNotifications];
NSNotificationCenter *nc = [NSNotificationCenter defaultCenter];
[nc addObserver:self selector:#selector(yourSelector:)
name:UIDeviceOrientationDidChangeNotification object:nil];
Update
If by "push" you mean push a view controller onto a navigation view controller then please disregard the second part of my response.
If this is the case, you must ensure that you have overridden the shouldAutorotateToInterfaceOrientation: method of your navigation controller to return YES as well as your view controller in order to support rotation handling.