UPDATE: see my answer to this question first. This seems to be a mistake. A minimal test case was created and a report was submitted to Apple. (Fixed with iPhone OS 3.1.)
Here is the puzzle from "I'm so close!" Department.
I have a Tab Bar based iPhone app. On each tab there is a UINavigationController with the usual suspects (navigation bar, tabular view ... which, in turn, can lead to another VC, etc.).
Now one of these lower-level VCs should be used in portait and landscape modes. But there is a problem. Our landscape VC shouldAutorotateToInterfaceOrientation: will not be called out of the box! What to do?
Here is what we do. In my tab bar controller, which I implemented in my own file, I have the following:
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation { return [self.selectedViewController shouldAutorotateToInterfaceOrientation:interfaceOrientation]; }
As a result, this request extends to my landscape VC, which also responds to this message. All my other VCs do not implement this method, so they just come with the default orientation.
The problem is solved !!! Hooray!
Well, not really. : (
Everything seems to be not so good when my landscape VC is called from the depth of the MoreNavigationController tab bar controller.
I decided to compare / compare between the VC called in one of the first four tabs of the UINavigationControllers ... and the same VC called from MoreNavigationController . It will be a bit ultra-detailed, so bear with me. We hope that the game in the game will be useful for surveillance.
When the application loads, there are several initial calls for the tab bar controller shouldAutorotate .... In these early cases, the selectedViewController is zero. Nevertheless, we finish the download, select the initial tab, and everything is fine.
Right First, select one of the first four elements of the tab bar and go to our VC.
We will select the third element of the navigation bar to the third navigation controller. We move on to our VC, which supports rotation. A quick inspection confirms that the parent is indeed the third navigator controller from our list of tab tab view controllers. Good!
Rotate the device. The tab bar controller is suggested to autorotate (see the code above). We observe that selectedViewController also consists in the fact that the third navigation controller, as well as the top and visible controllers of the navigation controller, are installed on our reliable VC, which supports rotation.
So the tab bar controller forwards the shouldAutorotate message to the third navigation controller ... but our spin-friendly VC eventually gets the message. (I am not doing anything special here. Perhaps the desired VC receives the message because it is the top and / or visible VC?) In any case, we are turning into the landscape, things are changing, and everything is fine. "Big success!"
Now push this button back and place the VC stack, leaving the landscape mode in the process. The tab bar controller is requested again.
Time for a little aside. topViewController for our navigation controller still supports VC, but visibleViewController is now set to UISnapshotModalViewController ! Heh. I've never seen this before ... but Erica Sadun has it . This seems to be for the "disappearing view controllers" (which in this case is certainly true - it disappears well).
As I continue to walk through, the visible VC remains like a Snapshot, but the top VC eventually moves on to the next VC on the stack, as my special VC eventually left. Fair enough.
So this is a scenario where everything works well.
Now try the same test, only this time we will go to the MoreNavigationController (element of the "Advanced" tab) and go to the same VC class as before. In my case, this is the 7th in the list of VC-panel controllers.
We introduce a VC with rotation and ... this time it will be asked to turn right! The tab bar controller does not require permission to rotate at all. Hm.
A quick check of the parent VC reveals that it is a MoreNavigationController . Ok, that makes sense.
Now try to rotate the device. NOTHING WILL GET ANYTHING . None of our milestones hit. Not in our VK. Not in our panel controller. (BUT?!?!)
Oh-kaaaay. Put the stack back in the same VC and try turning again. Weird Now we get a call in the input panel controller, asking for permission to autorotate. Here the selected controller is our trusted Nav controller (# 7), but this time its visibleViewController and topViewController are SET TO NIL!
As soon as we continue from here, a mysterious message appears in the debugger console:
Using a two-stage rotation animation. To use a smoother single-stage animation, this application should remove the two-step implementation method.
Mysterious because I do not use two-stage rotation animation ! Variants of the SecondHalf method are not reproduced anywhere in my source code.
Alas, my rotation-supporting VC never says that rotation is happening (even though the rotation is happening on the screen), so of course, my view is eventually smoothed out. Mayhem and sadness appear.: (
We will not even stumble over the stack at this moment.
I think the View Controller document is hinting at a possible problem:
If you want to perform custom animations during orientation changes, you can do this in one of two ways. The orientation changes used to occur in two stages, with notifications occurring at the beginning, middle, and end points of rotation. However, support was added in iPhone OS 3.0 to perform one-step orientation changes. Using a one-step orientation change tends to be faster than the previous two-step process, and is recommended for any new code.
Interestingly, the MoreNavigationController still responds to the two-step process and thus disables any attempts to use the one-step process? Please note that if you are responding to two-step messages, the one-step option will not work (again, for documents). I do not answer them, but I have a hidden suspicion of something behind the scenes of IS.
In fact, if I comment on the one-step method and try to answer willAnimateSecondHalfOfRotationFromInterfaceOrientation: duration: I get a note! But it still doesnβt crash from the stack very cleanly (in terms of visual effects). Even a stranger: willAnimateFirstHalfOfRotationFromInterfaceOrientation: duration: is NOT called even when I tried to steal a call to myself (using the FirstHalf message) in shouldAutorotateToInterfaceOrientation:. It returns immediately during the trace, as if I had not even detected it. Sigh.
So, to play the game.
In general, has anyone successfully handled the one-step rotation of a device for VC called from the MoreNavigationController tab control panel? The requested minds want to know!