Why does this orientation code not work? - iphone

I have a simple UIWebView nested in a ViewController it is presented modally off a navigation controller.
Structure as follows: TableViewController -> TableViewController -> Modal (WebView presented) -> Modal (options, presented via gesture, page curl)
All views handle all orientations except the one with the WebView on it, it is to handle its orientation via configuration.
The controller with the web view has the following orientation code:
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
{
BOOL orientationSwitch = NO;
if([self.webApp.orientationLandscape boolValue] &&
UIInterfaceOrientationIsLandscape(interfaceOrientation))
orientationSwitch = YES;
if([self.webApp.orientationPortrait boolValue] &&
UIInterfaceOrientationIsPortrait(interfaceOrientation))
orientationSwitch = YES;
return orientationSwitch;
}
Now the intention is that you can set some options as to if the view should react to the orientation changes. And for the most part it works, however I have a modal popup where you can choose to dismiss the modal that contains the web view. Once this happens, it seems the orientation is locked for the entire app. All other views subsequently do not respond to any form of rotation.
Any ideas?
Thanks

Here's something to try. Register with the UIDevice for UIDeviceOrientationDidChangeNotification and tell it to start generating notifications. When a notification comes in, call the UIViewController class method attemptRotationToDeviceOrientation (iOS 5 only).
Also it might help to read this tech note, as you may be doing something wrong here: https://developer.apple.com/library/ios/#qa/qa1688/_index.html

first, make sure in your project settings are the right supported orientations clicked (targets -> appname ->summary)
I don't know why this is happening, but I had a similar issue quite a while ago. That long time ago, ios 3.2 or something. I created a ViewRotatorController which only implements the -(BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
{}
method. Every other ViewControllers inherits that. Just let your webappview has a other implementation of this. It is probably not the best solution but it should work.

Related

Autorotation in iOS6

I am updating my app for iOS 6 and having issues with the changes to autorotation. My app has a bunch of view controllers and all of them should only support the portrait layout except 1 which should support all 3 orientations except upside down.
If I add the application:supportedInterfaceOrientationsForWindow: method to the app delegate do I have to add conditions there to check if im displaying the one VC I want to be able to rotate?
The documentation states that if I implement supportedInterfaceOrientations on a VC it should override the app delegate method but this doesn't appear to be the case. I have an log statement in the method on the child VC and it is called once when the VC loads but its not called when I rotate the device, but the method in the app delegate is.
If I completely remove the method from the app delegate the orientation of my VC's seems to be completely dependent on my apps supported interface orientation settings. This of course seems to be due to the method supportedInterfaceOrientations being called once on creation of the VC but never when the device is rotated.
Does anyone have any ideas or suggestions? It would be much appreciated.
Replace
[window addSubview:viewController.view];
with
window.rootViewController = viewController;
You also need to override - (BOOL) shouldAutorotate and return "YES". This makes it so you declare what orientations your VC supports with "supportedInterfaceOrientations" and then on rotation it should call "shouldAutorotate". If you have any navigation controller or tabbar you may need to subclass those to do the same thing within them. I had this issue recently myself.
try this...
-(void)willAnimateRotationToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation duration:(NSTimeInterval)duration
{
if (UIInterfaceOrientationIsLandscape(interfaceOrientation))
{
// here to implement landscope code
}
else
{
// here to implement setframePortrait
}
}

iPhone How to determine which orientations the previous view controller supports

Since the built-in iOS UIAlertView doesn't give us the ability for skinning, I've built my own UIAlertViewCustom class, which I'm using instead. Any of my view controller can display an instance of UIAlertViewCustom in the same that UIAlertView would be used, except my version allows for skinning graphics/fonts/colors, etc.
My UIAlertViewCustom class works by creating a new key window and root view controller. I then draw my message view on this new root view controller. (The view controller that chose to display the message is seen in the background just like you'd see with UIAlertView.
All of this is working perfectly. There is one piece of functionality that I'd like to implement but haven't figured out how to. I'd like each instance of UIAlertViewCustom to know whether or not it should auto-rotate when the device orientation changes. Of course, I want to know which orientations the view controller beneath (the view controller that created the instance of UIAlertViewCustom and displayed it) supports? If it supports portrait only, then I will not auto-rotate the UIAlertViewCustom, etc.
I don't want each view controller to have to pass in a supported orientation property to each instance of UIAlertViewCustom. I would just like each instance of UIAlertViewCustom to be able to figure out if it should auto-rotate or not.
Any help would greatly be appreciated!
I would try this in your view controller class:
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
{
return [[view superview] shouldAutorotateToInterfaceOrientation:interfaceOrientation];
}
I'm not sure if it's going to work, but that is where I would start. This is necessary because the default implementation for this returns YES for UIInterfaceOrientationPortrait and everything else is NO.
Another small thing. Apple has reserved the prefixes that it uses (NS, CF, CA, UI, etc...) and your custom classes shouldn't use them.
EDIT Changed [self superview] to [view superview]

Does a TabBar application need shouldAutorotateToInterfaceOrientation to be returning YES on all of its viewControllers?

I'm working on an iphone app with a TabBarController as rootcontroller. And this rootcontroller is associated to Navigation Controllers (each one related to a specific Tab Bar button).
One on these navigation controllers shows some photos and thus I needed to enable Lanscape which obviously did not work until I added this code to all view controllers
- (BOOL)shouldAutorotateToInterfaceOrientation (UIInterfaceOrientation)toInterfaceOrientation
{
return YES;
}
However, now that all orientations are enabled in all views some views I didn't want in landscape are showing very ugly :(
Any idea how to just leave the landscape orienation only on this photo view and disable it on all other views?
Consider showing the UIViewController that needs full reorientation capabilities modally.
That would be the common and in my humble opinion correct way to handle such situation.
To answer your subject in short: yes, it does have to return YES if you want any of the tabbed viewControllers to allow reorientation. The same goes for viewControllers within the stack of your UINavigationControllers. Hence the same goes for any combination of those.
From Apple's Technical Note on that subject:
Why won't my UIViewController rotate with the device?
All child view controllers in your UITabBarController or
UINavigationController do not agree on a common orientation set. To
make sure that all your child view controllers rotate correctly, you
must implement shouldAutorotateToInterfaceOrientation for each view
controller representing each tab or navigation level. Each must agree
on the same orientation for that rotate to occur. That is, they all
should return YES for the same orientation positions.
In case using a modally presented view controller is no option for you - here comes another way...
There is also a solution possible that seems a little "hacky" but worked for me in the past. I will draft it in a very very "hacky" way to simplify the answer.
Within the shouldAutorotateToInterfaceOrientation:toInterfaceOrientation implementation of all of your viewControllers, return a global value. Change that global value according to the needs of the currently displayed viewController. Even though it is said that a viewController is only asked once, this common rumor has proven untrue for my. So here comes the super hack;
All view controllers within your navigation stack should implement the shouldAutorotate-method like this:
- (BOOL)shouldAutorotateToInterfaceOrientation (UIInterfaceOrientation)toInterfaceOrientation
{
extern BOOL gSouldAutorotateToAnyOrientationFlag;
if (gShouldAutorotateToAnyOrientationFlag)
{
return YES;
}
return UIInterfaceOrientationIsPortrait(toInterfaceOrientation);
}
Now, somewhere in your app, you should declare and instantiate that global flag - you could place this ugly global flag within your app-delegate implementation, directly below the imports and above the #implementation block:
BOOL gShouldAutorotateToAnyOrientationFlag = NO;
Within all viewControllers that are supposed to be shown in portrait mode only, set that flag towards NO - e.g. within viewWillAppear;
- (void)viewWillAppear:(BOOL)animated
{
extern BOOL gShouldAutorotateToAnyOrientationFlag;
gShouldAutorotateToAnyOrientationFlag = NO;
}
Within the viewController/s that are supposed to be shown in any orientation, set that flag towards YES - again within viewWillAppear;
- (void)viewWillAppear:(BOOL)animated
{
extern BOOL gShouldAutorotateToAnyOrientationFlag;
gShouldAutorotateToAnyOrientationFlag = YES;
}
That way, whenever the entire navigation stack is asked for its orientation capabilities, the proper answer will be given. From my experience, the entire stack is asked, over and over again and answers are not cached, hence my hack worked whenever I needed it. Still, the rumor seems to be widespread that those answers are somehow cached and therefor that rumor might be valid in certain cases - hence I shall not be held responsible if this does not work for you (or even down voted :D )
On the view you only want landscape for:
- (BOOL)shouldAutorotateToInterfaceOrientation (UIInterfaceOrientation)toInterfaceOrientation
{
return UIInterfaceOrientationIsLandscape(toInterfaceOrientation);
}
You can replace UIInterfaceOrientationIsLandscape with UIInterfaceOrientationIsPortrait if that better suits your needs.

UIViewController orientations

I have a UIViewController instance(viewController1) that I want to lock in landscape mode which I am able to do. On tapping on a button I push another UIViewController(viewController2) which supports both orientations. Now, if user changes the orientation of viewController2 to portrait and goes back to viewController1, viewController1 also changes it's orientation to portrait. How can I avoid that?
Thanks in advance.
Add these methods to the view controllers
(BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
{
return (interfaceOrientation == UIInterfaceOrientationPortrait);
}
Thats for the first
(BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
{
return YES);
}
Thats the second
-(BOOL)shouldAutorotateToInterfaceOrientation:UIInterfaceOrientation)toInterfaceOrientation{
if (UIInterfaceOrientationIsPortrait(toInterfaceOrientation)) {
return YES;
}
return NO;
}
If those 2 controllers are both implementation of UIViewController both differente classes each other! you can just implement the method shouldAutorotateToInterfaceOrientation, in the first! this should work even when u go back!
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation {
if (UIInterfaceOrientationIsPortrait(toInterfaceOrientation)) {
return YES;
}
return NO;}
You say push so I assume both ViewControllers are in a NavigationController. If so I'll have to disappoint you, what you want isn't possible. Your rotation callbacks are working correctly, they respond to a rotation, you can't force it. What's happening is the correct behavior.
Best solution is to prevent the user from going back when you're in the orientation the previous ViewController doesn't support, hide the back button for example.
A while back I've made my own NavigationController (doesn't inherit from the UIViewController but it can do exactly the same) and I've tried to implement what you're trying to do. Before pushing or popping, if the view of the ViewController that was about to be shown didn't support the current orientation, I transformed the view of that ViewController by 90° and force the orientation of the status bar to the new ViewController's supported orientation.
As soon as the push or pop was complete I'd do a small trick to force the rotation of the device. If you remove the view of the rootViewController from the window and re-add it, the responder chain will be forced to go through all rotation callbacks. When that happened I checked if a ViewController's view was transformed and reset that transformation.
It did work, mostly. But it was messy code and it goes against Apple's current policy that the rootViewController should be responsible of handling the orientation. Also in iOS6 forcing the status bar orientation is guaranteed to work. So I'd really advise against doing this, I've removed this from my own NavigationController too.

navigationController will/did ShowViewController - How to tell which?

Given the UINavigationController delegate methods:
-(void)navigationController:(UINavigationController*)navigationController (will/did)ShowViewController:(UIViewController*)viewController animated:(BOOL)animated
How do you tell or compare which view controller instance is relevant to the event?
I am developing an app that renders touch-navigable graphs using OpenGL. The root view contains the graph, and pushed navigation controllers contain options. I'd like to disable animation(rendering) of the graph when the user navigates away from it and re-enable it when they return.
(I know rendering should be done after the touch events and not constantly with an on/off; the template openGL code I built the app on doesn't make that an easy change but I'll get around to it eventually!)
(Oh another thing; it's a tab bar app with a navigation controller on each tab. For some reason view(did/will)(appear/disappear) events only seem to get fired when changing tabs, not the position on navigation controller stack.)
Fixed with the following:
if(viewController == [self.viewControllers objectAtIndex:0])
{
NSString* bob = #"Your uncle";
}
Thanks for your direction.
You would keep a list of ViewControllers and then compare to the one that is being shown.
You can compare by just comparing the references
for(UIViewController *vc in viewControllerArray)
{
if(vs == viewController)
//do stuff
}
Does this help or did i misunderstand something?