Best practices for landscape only apps? - iphone

I'm a new iOS programming and I'm developing a simple iPhone game that needs to run in landscape only. I've ...
set supported orientations in the target settings
added the req. plist item (initial interface orientation)
overridden shouldAutorotateToInterfaceOrientation to return YES only for landscape modes
.. and the app "looks" correct, but there are a few odd things going on.
Issue 1 - I'm trying to manually position my views and not rely on autolayout. I've got a UIView in a NIB that I'm loading that needs to be positioned 150px from the right edge of the screen. I have to get the UIViewController's view's height (not width) to correctly position it - like it's not rotated to landscape at this point in the code.
Issue 2 - Implementing a UINavigationController to go from the title screen to the game interaction. When I'm pushing the interaction UIViewController to the stack, it slides in from the right like it's supposed to. When I go back to the title by popping the interaction, it slides UP to the title. It's seems like it's rotating back to portrait?
I think there is something very basic that I'm missing, but I can't find it in my app code. I've gone over the lists for a landscape app but they don't mention more than the list above.
Are there any other things/settings/methods to override that I should be on the look out for?

You need to set shouldAutorotateToInterfaceOrientation in your other viewControllers as well. Especially the ones displayed inside your UINavigationController.

Issue 2:
Don't use many UIViewController's. Use one view controller. Create one main UIViewController and for other UIViewController's just do:
[mainviewcontrl presentModalViewcontroller: child_viewcontrl animated: YES];
For delete a child view controller, use
[child_viewcontrl dismissModalViewControllerAnimated: YES];

Related

UINavigationController with strange behavior

I am developing an application with the following structure,
Each of the three compoenentes has a UINavigationController associated with.
This application is intended to be identical to facebook.
My problem is that in landscape mode, the "POP" actions of navigations have a strange performance, making the animation from the bottom to the top, as if the navigation had not done the rotation, despite the layout being changed to landscape.
I put all the navigation controller with:
[navCenter.navigationBar setAutoresizesSubviews:YES];
[navCenter shouldAutorotateToInterfaceOrientation:YES];
Any idea why this happen?
Thanks in advance.
EDIT:
If i remove my
[self addChildViewController:self.mainConteinar];
The animation works good. But now, the NavigationBars didn't resize.
You should check all your
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
What you describe sounds as if you forgot to return YES for landscape orientation in one of your child view controllers.

UIViewController shouldAutorotateToInterfaceOrientation not working properly

Alright, I am not entirely sure if I will explain this sufficiently, but here it goes.
In my application I have multiple viewControllers, that are added and removed to display different views, so on and so forth. Some of these controllers, I want to allow to rotate while other I only want in say portrait mode.
However, when I go and change the shouldAutorotateToInterfaceOrientation to return YES for a desired orientation, or even just always return YES, nothing happens when I rotate the device in some of the views.
The first view that I add to the application will rotate properly and does what I want it to do, but any subsequent view that I add to the window, just does not want to rotate as desired.
I set my parentview (main UIWindow), to autoresizeSubViews, and still nothing.
Any suggestions?
I found my problem with this was simply how I was implementing my transitions and adding new views to the screen. Before I was just taking a viewcontroller viewcontroller, and adding it as a subview to the main view, so the only thing that could control the rotation was that main viewcontroller. I did not know about the [self.navigationcontroller pushviewcontroller] thing existed. So yeah, that is what I use now and it does exactly what I need it to do.
The view, you want to allow rotation, you need implement shouldAutorotateToInterfaceOrientation with return YES; for every view! That should work, however, if you don't want to allow landscape mode, then can return NO; for landscape mode. (Default mode is portrait).

How to rotate two UIView's?

I created a app with the iOS 4.1 SDK.
In this app I did the following: I add two UIView's as subview to the Window of the Application. One view is a navigationcontrollerview and the other is a view that displays advertisement. The user can then navigate trough the app will the ads are displayed uninterrupted.
Now comes the problem: I wanted to add the option to rotate the device from portrait to landscape and back. The problem is only the first view (in my case the navigationcontrollerview) is rotated without problem. The second view is never rotated. Documentation from Apple confirms that this is the default behavior.
So, how do I get my second view rotated? Do I need to restructure my application? And why is the second view never rotated? That doesn't make any sense to me.
Are you just adding the second view (the one that doesn't rotate) as a plain UIView? If so, try adding it after containing it within a UIViewController class. I had the same issue in my app not so long ago. instead of [window addSubview:sampleView], I did [window addSubview:[sampleViewController view]]; where sampleViewController subclasses UIViewController.
In general, always use corresponding view controllers and contain views in them and then add subviews to avoid these issues.

presentModalViewController for UIImagePicker fails in landscape mode for iPhone 3.0

First of all, my code isn't complex - in fact it's just two sample programs from "Beginning iPhone Development: Exploring the iPhone SDK", combined into one program. I took the ViewSwitcher application, which switches between a blue view and a yellow view, and replaced the YellowViewController with the CameraViewController from the camera application.
I have three ViewControllers total. SwitchViewController just switches between BlueViewController and CameraViewController.
Inside CameraViewController, I'm trying to use a UIImagePickerController to choose an image. The picker is presented with presentModalViewController. The catch is that I want to do this in landscape orientation.
Everything works fine under 2.2.1, and everything works fine in 3.0 in portrait mode.
In 3.0 under landscape orientation, however, things break. If I set SwitchViewController to landscape orientation, my screen goes white when I try to present the picker. If I rotate the iPhone a few times, I can see a corner of the picker, which apparently was displayed off screen.
If I set CameraViewController to landscape orientation, the picker doesn't come up at all.
I think this page may have a clue when it says "The most prominent change [in 3.0] I can see is that the modal view controller will always use the application frame instead of the parent view controller's frame." I don't understand exactly what that means, though.
Any help is greatly appreciated. Thanks!
I believe what that means is this: Modal views always use the full screen, even if the parent view controller that invokes them controls a view that is only part of the screen. This makes sense for standard modal views like the camera picker, but I can see why someone who creates a custom modal view might want it to be smaller.
Not sure if that really helps solve your problem though.
Question -- what happens if you bring up the modal view and THEN rotate the phone?
You must have used addSubview in your parent view controller, try using presentModalViewController:.

Selective Autorotation of UIControllers

I did some experiments on autorotation.
The situation: I have a TabBar 4(tabs), three should be portrait only. The last one is a UINavigationController, which by itself should not autorotate any of the stacked controllers. It is basically a browsing application, as I show file and folders everything should be portrait. Some times, a special UIViewController is pushed, and I would like only this one to autorotate (it is always the last on the stack). In this last view, the tabbar is hidden.
How I achieved the goal: I subclassed the UITabBarController, to override the standard shouldAutorotate method behaviour:
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation {
if([self.selectedViewController isKindOfClass:[UINavigationController class]])
return [[(UINavigationController*)self.selectedViewController visibleViewController] shouldAutorotateToInterfaceOrientation:interfaceOrientation];
else
return [self.selectedViewController shouldAutorotateToInterfaceOrientation:interfaceOrientation];
This way, the answer of shouldAutorotate is forwarded to the controlled tabs, and in particular for the UINavigationController, it is again delegated to the visible UIViewController. Basically this works, as I have all the UIViewControllers answering NO, except for the particular one I described above: correctly, when rotating the Simulator, only when the special UIViewController is visible, the interface rotates to landscape, whici is perfect. The Tabbar here is hidden, so user don't get that also that one is rotated (which would be unconsistent in my design: basically whenever the tabbar is visible, which means everywhere except in this special view, the application is portrait only).
The problem is that I would like that, even if the device is still in landscape mode and user pops the special ViewController, the interface should behave consistently and return to portrait mode. Instead, when I pop, the interface stays in landscape (it's not designed in that way so it's a mess, of course) even when showing a UIViewController that would answer NO to shouldAutorotate... this is because (I think) the method is called only when rotation occurs, so until the rotation actually occurs again, the interface is rotated to landscape anyway.
How do avoid this? My first solution would be somehow to intercept the popping of the last view, and rotate manually the view before popping... but I'm not sure, I hope there is some more robust method to handle!!
I use the simulator with 3.0, dunno if this makes a difference.
I know that this is not a solution to your problem, but I think you should really avoid this kind of user interface when portrait-only portrait+landscape or landscape-only pages mixed on the same UINavigationController. Unfortunately the rotation management is extremely buggy and the bugs vary on different firmware versions.
I managed to quite the same thing in one of my projects, but had to remove it later due to firmware bugs: for example if you pressed the "back" button in landscape mode and went back to a portrait-only view, it often occured that the status bar and/or the navigation bar remained in landscape mode and the layout was completely broken. As far as I know this bug is not yet fixed although it was already present in firmware 2.x.
If you still want to do this I suggest the following things:
Make sure that all overridden UIViewController methods (init, viewWillAppear, etc) calls its [super methodName]. If not, auto-rotation is silently buggy. This was mentioned in the "Getting Ready for iPhone OS 3.0 Technical Note" (https://developer.apple.com/iphone/checklist/), but currently this document is unavailable :(
You may experiment with calling the undocumented [UIDevice setOrientation:] method when leaving the landscape view. It sometimes needs to be called twice, once with the current orientation and once with the desired orientation :) You may also need to call [UIDevice setStatusBarOrientation:] if the status bar remains in landscape mode. But note that Apple is likely to reject your application if you use these methods (they introduced an automatic tool some time ago which detects the presence of undocumented symbols in your application).
I had the same problem as you, and I solved this way:
I subclassed the UITabBarController, and added the following code:
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
{
if (self.selectedViewController)
return [self.selectedViewController shouldAutorotateToInterfaceOrientation:interfaceOrientation];
else
return (interfaceOrientation == UIDeviceOrientationPortrait);
}
This way, every child view controller could control its own orientation.
The problem is that you are rotating your UITabBarController (with the child view controller on top of it) rather than just the child view controller. You should be able to implement shouldAutorotateToInterfaceOrientation: only in your child view controller and have it work properly. It would also simplify your code.
I have never had this issue, but I've also never implemented shouldAutorotateToInterfaceOrientation: in a "container" view controller like a UITabBarController or UINavigationController.
The problem with your implementation is that you use the visibleViewController member of UINavigationController. You should use topViewController instead and everything will work as expected.