Rotating only one UIView (of the two) in a UIViewController - ios

I have a GLKViewController with two views: a GLKView and a transparent UIView showing some commands.
The GLKViewController supports two device orientations: portrait and landscape-right.
When the device is rotated from portrait to landscape I would like to:
NOT rotate the GLKView;
rotate the overlaid UIView with the commands.
Basically the GLKView should stay always in portrait, while the other view should follow the device orientation.
The GLKViewController is in a NavigationController. Either I need to have the NavigationController rotating in landscape or I need to implement a fake Navigation Bar and perform the 'pop' programmatically.
I saw a solution which simply rotated the view (after catching a notification), but I would like to keep the animation rotating that view.
I tried to use another UIViewController subclass, receiving the GLKViewController and the View with the commands as two child UIViewControllers but it did not work: the screen stayed black.

When a UINavigationController is involved, create a category on the UINavigationController and override supportedInterfaceOrientations.
#import "UINavigationController+Orientation.h"
#implementation UINavigationController (Orientation)
-(NSUInteger)supportedInterfaceOrientations
{
return [self.topViewController supportedInterfaceOrientations];
}
-(BOOL)shouldAutorotate
{
return YES;
}
#end
Now, iOS containers (such as UINavigationController) do not consult their children to determine whether they should autorotate.
How to create a category
Add a new file (Objective c- category under cocoa touch)
Category : Orientation on UINavigationController
Add the above code to UINavigationController+Orientation.m

Related

Landscape Segue Between Two Portrait UIViewControllers

I am only allowing Device Orientation portrait for UIViewControllers being viewed on iPhones through the following code:
- (BOOL)shouldAutorotate
{
NSString *device = [UIDevice currentDevice].model;
return [device rangeOfString:#"iPhone"].location != NSNotFound ? NO : YES;
}
This works fine - when I rotate my iPhone while looking at ViewController A, the view does not rotate. Similarly, when I rotate my iPhone while looking at ViewController B, the view does not rotate. However, when I rotate my iPhone while looking at ViewController A, tap a button that presents ViewController B modally, the show segue animation (Flip Horizontal) is landscape, and ViewController B appears in landscape.
How can I force the segue to be portrait as well and not rotate ViewController B?
In my tests I've found that shouldAutorotate is only one part of the things you have to do to prevent rotation of the device. shouldAutorotate tells the system if it should rotate all the views as soon as someone rotates the device to a different allowed orientation.
My suggestion would be to prevent more orientations other than Landscape (which allows LandscapeLeft and LandscapeRight). And by that I mean you should override supportedInterfaceOrientations in both ViewControllers and tell the app that it should only allow landscape orientations instead of the default (which allows all but upside-down orientation).

Force first screen of ios application to be portrait but other screens landscape ios 6+

I used this code for forcing my Home screen (first screen of my application) be portrait while other screens remain supporting all orientations:
public class RltNavigationController : UINavigationController
{
public RltNavigationController () : base ()
{
}
public override UIInterfaceOrientationMask GetSupportedInterfaceOrientations ()
{
if(this.TopViewController is HomeScreen )
return UIInterfaceOrientationMask.Portrait ;
else
return UIInterfaceOrientationMask.AllButUpsideDown ;
}
public override bool ShouldAutorotateToInterfaceOrientation (UIInterfaceOrientation toInterfaceOrientation)
{
// Return true for supported orientations
if(this.TopViewController is HomeScreen )
return (toInterfaceOrientation == UIInterfaceOrientation.Portrait );
else
return (toInterfaceOrientation != UIInterfaceOrientation.PortraitUpsideDown) ;
}
}
Now, suppose that the device is on the landscape orientation at home screen (Device is lanscape but screen just show portrait). Now if user go to other views, other views now show portrait while it should show landscape. What solution I can choose in order to load second views with theirs actual rotation?
EDIT
Thanks for all answers, Just notice that already the problem is not that I can not force the screen to be portrait. For understanding the problem please follow the scenario:
-> First screen forced to be portrait.
-> Device is landscape right and I'm in home screen(so home screen show portrait)
-> Now I switch to another screen that support all orientation
-> at another screen because the parent screen was portrait it show portrait (while because device is landscape it should show landscape)
You can also directly select from the XIB a particular viewController be Landscape or Portrait and the same loads.
You can not explicitly say, viewController be landscape and the view will be landscape. The way it works is, you ask the controller that is controller the screen, this may be a navigation controller, tab view controller, a modal, how they want to be able to rotate. If you have a navigation controller then all viewController will only have the rotation of your navigation controller.
There were a few tricks like subclassing the navigation controller and over the should auto rotate method, call [self.visibleViewController shouldAutoRotate]; which works for making screens rotate and not rotate, but if you have only 1 screen that supports all orientations and all the others do not, then you have a pushing/popping error where if you push or pop while in that different orientation the next viewController will be in that orientation.
Since you can't directly tell the rootViewController to explicitly rotate, the next best solutions are,
A: Use QuartzCore to manually rotate the view yourself
B: have a separate xib file for each orientation so when you rotate to landscape you see the landscape viewController and vice versa
The easiest way to do this is to create a custom navigation controller (subclass of UINavigationController) that inherits its rotation based on the currently visible view controller
Inside your custom navigation controller:
-(NSUInteger) supportedInterfaceOrientations {
return UIInterfaceOrientationMaskAllButUpsideDown;
}
-(BOOL) shouldAutorotate {
return self.topViewController.shouldAutorotate;
}
Then inside any of the view controllers within that, add these methods:
-(BOOL)shouldAutorotate{
return NO;
}
-(NSUInteger)supportedInterfaceOrientations{
return UIInterfaceOrientationMaskPortrait;
}
- (UIInterfaceOrientation)preferredInterfaceOrientationForPresentation{
return UIInterfaceOrientationPortrait;
}
That's for a view you DON'T want to autorotate. Modify that accordingly for views you do want to rotate.
Make sure your project settings have rotation in the orientations you want enabled, and make sure to use your custom navigation controller instead of the regular one for any view hierarchies that contain multiple possible rotations.
Note that you may run into problems if a view that is rotated is popped and the previous view is not rotatable. Off the top of my head, I'm not sure whether this will work properly.

Switching between 2 view controllers on same storyboard, on rotation using willAutorotateTo... not working,

im having a little problem here. I have two view controllers on same storyboard (MainStoryboard -> Calc view Controller in portrait mode and Calc view controller in landscape mode). When i have initially created a boolforshouldAutoRotate it did rotate however there was "and still is" a rendering issue, as some buttons etc were not in the place you would expect them to be, in other words they were all over the place in landscape mode. So now i have created 2 view controllers in Landscape mode and main Portrait mode. So now the key is to switch between those two controllers on rotation.
in CalculatorViewController.m i have
UPDATE
I have noticed that some methods were deleted from iOS 6 ( and thats the one i am using now ) after a some research i have found that in iOS 6 the "sort of correct way " would be this
#synthesize portraitView, landscapeView;
-(BOOL)shouldAutorotate
{
return YES;
}
-(NSUInteger)supportedInterfaceOrientations:toInterfaceOrientation
{
if(UIInterfaceOrientationMaskAllButUpsideDown)
{
if ( UIInterfaceOrientationPortrait )
{
self.view = portraitView;
}
else if ( UIInterfaceOrientationLandscapeLeft )
{
self.view = landscapeView;
}
}
return YES;
}
however although i think i am using correct methods in respect to iOS 6 i still cant get the correct view controller to be called upon rotation
and in CalculatorViewController.h
#interface CalculatorViewController : UIViewController {
IBOutlet UIView *portraitView; // declaring view - portrait
IBOutlet UIView *landscapeView; // declaring view - landscape
//rest of irrelevant code below
}
#property (nonatomic, retain) UIView *portraitView;
#property (nonatomic, retain) UIView *landscapeView;
Just ignore those 2 white controllers they are now irrelevant. Submitting picture to show those 2 view controllers
Thank you for your time
I've done things like this a couple of times, and it's frequently easier to have your ViewController have a blank view. Then just add your Landscape view as the prime subview in landscape, and then remove it when you rotate to portrait and so forth. If you try to have separate VC's then your going to have a tangled mess of state saving code just to smoothly transition.
You can even fiddle with this design by having both be constantly subviews, and just showing/hiding them when appropriate. This is more memory intensive, but you can do some nice transition animations.
That way all of your connections and logic will be in a single VC and just the interface will change.

UIView added on top of window does not rotate on iOS

I have a tabBar based application and want to present some custom view above whole screen (not as modal view) and I do it like that:
[self.view.window addSubview:self.myViewController.view];
The reason I did this is because this way view is positioned above UITabBar.
Anyway view is presented nicely and it covers whole screen like I want to. But there is a problem. When I rotate device this top view does not rotate, but view's underneath do.
I've tested on iOS5 and iOS6 without luck. Have also put this code in delegate:
- (NSUInteger)application:(UIApplication *)application supportedInterfaceOrientationsForWindow:(UIWindow *)window
{
return UIInterfaceOrientationMaskAll;
}
Similar code is in myViewController's view:
- (NSUInteger)supportedInterfaceOrientations
{
return UIInterfaceOrientationMaskAll;
}
The view just doesn't rotate... ?
As far as i know only the first subview of the window gets the rotation events. You're adding another view (your view) to the window and therefore need to deal with propagating the rotation events yourself.
Providing some really quick-help for you, just check out the following implementation : AGWindowView (not maintained from 2016)
You can set the rootController for your UIWindow.
e.g:
fileprivate(set) var bottonOverlayWindow = UIWindow()
self.bottonOverlayWindow.rootViewController = self;
// 'self' will the ViewController on which you had added UIWindow view. So whenever you ViewController change the orientation, your window view also change it's orientation.
Let me know if you face any issue.

UITabBar autorotate issue

I'm wondering why iPad project based on UITabBarController won't autorotate when i specify some of the tab should autorotate in landscape mode and the other will autorotate in landscape and portrait mode.
i've used the
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
for all the UIViewController and specify if landscape return YES; other wise return NO;
In the other hand, if the UIViewController should rotate in landscape and portrait i've justreturn YES;` always.
Thx in advance.
for all the UIViewController you are loading in tabbarcontroller you must return True in
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
Note:
A tab bar controller will not auto rotate unless ALL the controllers it contains also auto rotate.
from Rotate one UIViewController in UITabBar application -->>
There is no easy way to have only one view in landscape mode, while the others are in landscape, nor an easy way to programmatically switch to landscape mode.
One possible approach would be using a CGAffineTransform to transform your view in your viewWillAppear (i.e., right before the view is shown):
- (void)viewWillAppear:(BOOL)animated; {
//-- Adjust the status bar
[UIApplication sharedApplication].statusBarOrientation = UIInterfaceOrientationLandscapeRight;
//-- Rotate the view
CGAffineTransform toLandscape = CGAffineTransformMakeRotation(degreesToRadian(90));
toLandscape = CGAffineTransformTranslate(toLandscape, +90.0, +90.0 );
[self.view setTransform:toLandscape];
}

Resources