Trick preferredInterfaceOrientationForPresentation to fire on viewController change - iphone

I am using MSNavigationPaneViewController from here and have rotation sort of working.
I've overridden the rotation methods in my root UINavigationController
-(BOOL)shouldAutorotate
{
return YES;
}
-(NSUInteger)supportedInterfaceOrientations
{
AppDelegate *appDelegate = (AppDelegate *)[[UIApplication sharedApplication] delegate];
if (appDelegate.topViewController != nil) {
return [appDelegate.topViewController supportedInterfaceOrientations];
} else {
return UIInterfaceOrientationMaskPortrait;
}
}
- (UIInterfaceOrientation)preferredInterfaceOrientationForPresentation
{
AppDelegate *appDelegate = (AppDelegate *)[[UIApplication sharedApplication] delegate];
if (appDelegate.topViewController != nil) {
return [appDelegate.topViewController preferredInterfaceOrientationForPresentation];
} else {
return UIInterfaceOrientationPortrait;
}
}
which I push the MSNavigationPaneViewController with using presentViewController: animated:completion: and I have rotation working so certain views can have different orientations. The problem is, each view that has a different orientation needs the user to tilt the phone to change the orientation at which point it locks on the correct orientation.
I've done tons of reading to get this working and it seems I need preferredInterfaceOrientationForPresentation to fire before each view is loaded, but it's not firing.
I think it's not firing because the MSNavigationPaneViewController isn't changing view controllers using presentViewController.
This is the code used by MSNavigationPaneViewController to change the view
- (void)setPaneViewController:(UIViewController *)paneViewController
{
if (_paneViewController == nil) {
paneViewController.view.frame = _paneView.bounds;
_paneViewController = paneViewController;
[self addChildViewController:_paneViewController];
[_paneView addSubview:_paneViewController.view];
[_paneViewController didMoveToParentViewController:self];
} else if (_paneViewController != paneViewController) {
paneViewController.view.frame = _paneView.bounds;
[_paneViewController willMoveToParentViewController:nil];
[self addChildViewController:paneViewController];
void(^transitionCompletion)(BOOL finished) = ^(BOOL finished) {
[_paneViewController removeFromParentViewController];
[paneViewController didMoveToParentViewController:self];
_paneViewController = paneViewController;
};
[self transitionFromViewController:_paneViewController
toViewController:paneViewController
duration:0
options:UIViewAnimationOptionTransitionNone
animations:nil
completion:transitionCompletion];
}
}
which looks like it's just switching the viewController and therefor not calling preferredInterfaceOrientationForPresentation
Is there any way to force preferredInterfaceOrientationForPresentation to be called, or to trick it into be called maybe by a hidden view?
Thanks
EDIT ----
I totally understand how the new rotation system works in iOS6 and that it's down to the root to manage it. However preferredInterfaceOrientationForPresentation only seems to be called if the next view is being presented with one of the correct methods. Not if the window is just switched.
So I do actually need a way to trick this to be called.

You can trick the window into re-valuating its supported interface orientations by resetting its rootViewController.
UIApplication *app = [UIApplication sharedApplication];
UIWindow *window = [[app windows] objectAtIndex:0];
UIViewController *root = window.rootViewController;
window.rootViewController = nil;
window.rootViewController = root;
You'd need to make sure that when this code executes, -supportedInterfaceOrientations of the root view controller returns the proper mask (corresponding to how you want to force the orientation).
Be aware, this hack can cause a quick flash on the screen and glitch any ongoing animations.

preferredInterfaceOrientationForPresentation will not be called on controllers within a UINavigationController.
You are going to have to subclass UINavigationController and then implement this feature yourself. You'd simply want to delegated to topViewController.
For reference check out: http://code.shabz.co/post/32051014482/ios-6-supportedorientations-with-uinavigationcontroller
I also found this implementation of a UINavigationController subclass: https://gist.github.com/3842178

Related

IOS 6 force device orientation to landscape

I gave an app with say 10 view controllers. I use navigation controller to load/unload them.
All but one are in portrait mode. Suppose the 7th VC is in landscape. I need it to be presented in landscape when it gets loaded.
Please suggest a way to force the orientation go from portrait to landscape in IOS 6 (and it will be good to work in IOS 5 as well).
Here is how I was doing it BEFORE IOS 6:
- (void)viewWillAppear:(BOOL)animated {
[super viewWillAppear:animated];
UIViewController *c = [[[UIViewController alloc]init] autorelease];
[self presentModalViewController:c animated:NO];
[self dismissModalViewControllerAnimated:NO];
}
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation{
return (interfaceOrientation == UIInterfaceOrientationPortrait);
}
Presenting and dismissing a modal VC was forcing the app to review its orientation, so shouldAutorotateToInterfaceOrientation was getting called.
What I have have tried in IOS 6:
- (BOOL)shouldAutorotate{
return YES;
}
-(NSUInteger)supportedInterfaceOrientations{
return UIInterfaceOrientationMaskLandscape;
}
- (UIInterfaceOrientation)preferredInterfaceOrientationForPresentation{
return UIInterfaceOrientationLandscapeLeft;
}
On load, the controller keeps staying in portrait. After rotating the device, the orientation changes just ok. But I need to make the controller to rotate automatically to landscape on load, thus the user will have to rotate the device to see the data correctly.
Another problem: after rotating the device back to portrait, the orientation goes to portrait, although I have specified in supportedInterfaceOrientations only UIInterfaceOrientationMaskLandscape. Why it happens?
Also, NONE of above 3 methods are getting called.
Some (useful) data:
In my plist file I have specified 3 orientations - all but upside down.
The project was started in Xcode 4.3 IOS 5. All classes including xibs were created before Xcode 4.5 IOS 6, now I use the last version.
In plist file the status bar is set to visible.
In xib file (the one I want to be in landscape) the status bar is "None", the orientation is set to landscape.
Any help is appreciated. Thanks.
Ok, folks, I will post my solution.
What I have:
A view based application, with several view controllers. (It was navigation based, but I had to make it view based, due to orientation issues).
All view controllers are portrait, except one - landscapeLeft.
Tasks:
One of my view controllers must automatically rotate to landscape, no matter how the user holds the device. All other controllers must be portrait, and after leaving the landscape controller, the app must force rotate to portrait, no matter, again, how the user holds the device.
This must work as on IOS 6.x as on IOS 5.x
Go!
(Update Removed the macros suggested by #Ivan Vučica)
In all your PORTRAIT view controllers override autorotation methods like this:
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation{
return (toInterfaceOrientation == UIInterfaceOrientationPortrait);
}
-(BOOL)shouldAutorotate {
return YES;
}
- (NSUInteger)supportedInterfaceOrientations {
return UIInterfaceOrientationMaskPortrait;
}
You can see the 2 approaches: one for IOS 5 and another For IOS 6.
The same for your LANDSCAPE view controller, with some additions and changes:
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation{
[image_signature setImage:[self resizeImage:image_signature.image]];
return (toInterfaceOrientation == UIInterfaceOrientationLandscapeLeft);
}
-(BOOL)shouldAutorotate {
return YES;
}
- (NSUInteger)supportedInterfaceOrientations {
[image_signature setImage:[self resizeImage:image_signature.image]];
return UIInterfaceOrientationMaskLandscapeLeft;
}
ATTENTION: to force autorotation in IOS 5 you should add this:
- (void)viewDidLoad{
[super viewDidLoad];
if ([[[UIDevice currentDevice] systemVersion] floatValue] < 6.0)
[[UIApplication sharedApplication] setStatusBarOrientation:UIDeviceOrientationLandscapeLeft animated:NO];
}
Analogically, after you leave the LANDSCAPE controller, whatever controller you load, you should force again autorotation for IOS 5, but now you will use UIDeviceOrientationPortrait, as you go to a PORTRAIT controller:
- (void)viewDidLoad{
[super viewDidLoad];
if ([[[UIDevice currentDevice] systemVersion] floatValue] < 6.0)
[[UIApplication sharedApplication] setStatusBarOrientation:UIDeviceOrientationPortrait animated:NO];
}
Now the last thing (and it's a bit weird) - you have to change the way you switch from a controller to another, depending on the IOS:
Make an NSObject class "Schalter" ("Switch" from German).
In Schalter.h say:
#import <Foundation/Foundation.h>
#interface Schalter : NSObject
+ (void)loadController:(UIViewController*)VControllerToLoad andRelease:(UIViewController*)VControllerToRelease;
#end
In Schalter.m say:
#import "Schalter.h"
#import "AppDelegate.h"
#implementation Schalter
+ (void)loadController:(UIViewController*)VControllerToLoad andRelease:(UIViewController*)VControllerToRelease{
//adjust the frame of the new controller
CGRect statusBarFrame = [[UIApplication sharedApplication] statusBarFrame];
CGRect windowFrame = [[UIScreen mainScreen] bounds];
CGRect firstViewFrame = CGRectMake(statusBarFrame.origin.x, statusBarFrame.size.height, windowFrame.size.width, windowFrame.size.height - statusBarFrame.size.height);
VControllerToLoad.view.frame = firstViewFrame;
//check version and go
if (IOS_OLDER_THAN_6)
[((AppDelegate*)[UIApplication sharedApplication].delegate).window addSubview:VControllerToLoad.view];
else
[((AppDelegate*)[UIApplication sharedApplication].delegate).window setRootViewController:VControllerToLoad];
//kill the previous view controller
[VControllerToRelease.view removeFromSuperview];
}
#end
NOW, this is the way you use Schalter ( suppose you go from Warehouse controller to Products controller ) :
#import "Warehouse.h"
#import "Products.h"
#implementation Warehouse
Products *instance_to_products;
- (void)goToProducts{
instance_to_products = [[Products alloc] init];
[Schalter loadController:instance_to_products andRelease:self];
}
bla-bla-bla your methods
#end
Of course you must release instance_to_products object:
- (void)dealloc{
[instance_to_products release];
[super dealloc];
}
Well, this is it. Don't hesitate to downvote, I don't care. This is for the ones who are looking for solutions, not for reputation.
Cheers!
Sava Mazare.
This should work, it's similar to the pre-iOS 6 version, but with a UINavigationController:
UIViewController *portraitViewController = [[UIViewController alloc] init];
UINavigationController* nc = [[UINavigationController alloc] initWithRootViewController:portraitViewController];
[self.navigationController presentModalViewController:nc animated:NO];
[self.navigationController dismissModalViewControllerAnimated:NO];
I'm calling this before I'm pushing the next UIViewController. It will force the next pushed UIViewController to be displayed in Portrait mode even if the current UIViewController is in Landscape (should work for Portrait to Landscape too). Works on iOS 4+5+6 for me.
I think that best solution is to stick to official apple documentation. So according to that I use following methods and everything is working very well on iOS 5 and 6.
In my VC I override following methods:
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
{
// Return YES for supported orientations
return UIInterfaceOrientationIsPortrait(interfaceOrientation);
}
Methods for iOS 6, first method returns supported orientation mask (as their name indicate)
-(NSUInteger)supportedInterfaceOrientations{
return UIInterfaceOrientationMaskPortrait;
}
second one thats tells your VC which is preferred interface orientation when VC is going to be displayed.
- (UIInterfaceOrientation)preferredInterfaceOrientationForPresentation
{
return UIInterfaceOrientationPortrait;
}
Just change Portrait for orientation that you want ;)
This solution is working smooth, I don't like the idea of creating macros and other stuff, that goes around this simple solution.
Hope this help...
I had the same problem, 27 views in my application from which 26 in portrait and only one in all orientations ( an image viewer :) ).
Adding the macro on every class and replace the navigation wasn't a solution I was comfortable with...
So, i wanted to keep the UINavigationController mechanics in my app and not replace this with other code.
What to do:
#1 In the application delegate in method didFinishLaunchingWithOptions
if ([[UIDevice currentDevice].systemVersion floatValue] < 6.0)
{
// how the view was configured before IOS6
[self.window addSubview: navigationController.view];
[self.window makeKeyAndVisible];
}
else
{
// this is the code that will start the interface to rotate once again
[self.window setRootViewController: self.navigationController];
}
#2
Because the navigationController will just responde with YES for autorotation we need to add some limitations:
Extend the UINavicationController -> YourNavigationController and link it in the Interface Builder.
#3 Override the "anoying new methods" from navigation controller.
Since this class is custom only for this application it can take responsibility
for it's controllers and respond in their place.
-(BOOL)shouldAutorotate {
if ([self.viewControllers firstObject] == YourObject)
{
return YES;
}
return NO;
}
- (NSUInteger)supportedInterfaceOrientations {
if ([self.viewControllers firstObject] == YourObject)
{
return UIINterfaceOrientationMaskLandscape;
}
return UIInterfaceOrientationMaskPortrait;
}
I hope this will help you,
From the iOS 6 Release Notes:
Now, iOS containers (such as UINavigationController) do not consult their children to determine whether they should autorotate.
Does your rootViewController pass the shouldAutoRotate message down the ViewController hierarchy to your VC?
I used the same method as OP pre-ios6 (present and dismiss a modal VC) to show a single view controller in landscape mode (all others in portrait). It broke in ios6 with the landscape VC showing in portrait.
To fix it, I just added the preferredInterfaceOrientationForPresentation method in the landscape VC. Seems to work fine for os 5 and os 6 now.
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
{
return (interfaceOrientation == UIInterfaceOrientationLandscapeLeft);
}
- (BOOL)shouldAutorotate
{
return NO;
}
- (UIInterfaceOrientation)preferredInterfaceOrientationForPresentation
{
return UIInterfaceOrientationLandscapeLeft;
}
Hey guys after tryng a lot of different possible solutions with no success i came out with the following solution hope it helps!.
I prepared a recipe :).
Problem:
you need change orientation of viewcontrollers using navigationcontroller in ios 6.
Solution:
step 1. one initial UIviewcontroler to trigger modal segues to landscape and
portrait UInavigationControllers as picture shows....
more deeply in UIViewController1 we need 2 segues actions according to global variable at Appdelegate....
-(void)viewDidAppear:(BOOL)animated{
if([globalDelegate changeOrientation]==0){
[self performSegueWithIdentifier:#"p" sender:self];
}
else{
[self performSegueWithIdentifier:#"l" sender:self];
}
}
also we need a way back to portrait &| landscape....
- (IBAction)dimis:(id)sender {
[globalDelegate setChangeOrientation:0];
[self dismissViewControllerAnimated:NO completion:nil];
}
step 2. the first Pushed UiViewControllers at each NavigationController goes
with...
-(NSUInteger)supportedInterfaceOrientations{
return [self.navigationController supportedInterfaceOrientations];
}
-(BOOL)shouldAutorotate{
return YES;
}
step 3. We overwrite supportedInterfaceOrientations method at subclass of UInavigationController....
in your customNavigationController we have .....
-(NSUInteger)supportedInterfaceOrientations{
if([self.visibleViewController isKindOfClass:[ViewController2 class]]){
return UIInterfaceOrientationMaskPortrait;
}
else{
return UIInterfaceOrientationMaskLandscape;
}
}
step 4. At storyboard or by code, set wantsFullScreenLayout flag to yes, to both portrait and landscape uinavigationcontrollers.
Try segueing to a UINavigationController which uses a category or is subclassed to specify the desired orientation, then segue to the desired VC. Read more here.
As an alternative you can do the same using blocks:
UIViewController *viewController = [[UIViewController alloc] init];
viewController.modalTransitionStyle = UIModalTransitionStyleCoverVertical;
[self presentViewController:viewController animated:NO completion:^{
[self dismissViewControllerAnimated:NO completion:nil];
}];
Also, call it before pushing the new view.
Go to you Info.plist file and make the change
I had the same problem. If you want to force a particular view controller to appear in landscape, do it right before you push it into the navigation stack.
UIInterfaceOrientation currentOrientation = [[UIApplication sharedApplication] statusBarOrientation];
if (currentOrientation == UIInterfaceOrientationPortrait ||
currentOrientation == UIInterfaceOrientationPortraitUpsideDown)
[[UIDevice currentDevice] setOrientation:UIInterfaceOrientationLandscapeLeft];
UIViewController *vc = [[UIViewController alloc] init];
[self.navigationController pushViewController:vc animated:YES];
[vc release];
I solved it by subclassing UINavigationController and overriding the supportedInterfaceOrientations of the navigation Controller as follow:
- (NSUInteger)supportedInterfaceOrientations
{
return [[self topViewController] supportedInterfaceOrientations];
}
All the controllers implemented supportedInterfaceOrientations with their desired orientations.
I have used the following solution. In the one view controller that has a different orientation than all the others, I added an orientation check in the prepareForSegue method. If the destination view controller needs a different interface orientation than the current one displayed, then a message is sent that forces the interface to rotate during the seque.
#import <objc/message.h>
...
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
if(UIDeviceOrientationIsLandscape(self.interfaceOrientation))
{
UIInterfaceOrientation destinationOrientation;
if ([[segue destinationViewController] isKindOfClass:[UINavigationController class]])
{
UINavigationController *navController = (UINavigationController *)[segue destinationViewController];
destinationOrientation = [navController.topViewController preferredInterfaceOrientationForPresentation];
} else
{
destinationOrientation = [[segue destinationViewController] preferredInterfaceOrientationForPresentation];
}
if ( destinationOrientation == UIInterfaceOrientationPortrait )
{
if ([[UIDevice currentDevice] respondsToSelector:#selector(setOrientation:)])
{
objc_msgSend([UIDevice currentDevice], #selector(setOrientation:), UIInterfaceOrientationPortrait );
}
}
}
}

setStatusBarOrientation issue

I have a navigation controller app. And first I push FirstViewController (support Portrait orientation) and then SecondViewController (supports all orientations). When I'm in landscape mode of SecondViewController and press back button, FirstViewController appears in landscape mode. That's why I manually rotate the navigation view, but when I want to set setStatusBarOrientation to Portrait (First view controller should appears only in portrait mode), the orientation of view controller is still landscape, and even if rotate the device to portrait mode, the orientation stay landscape
.Here is my code of FirstViewController:
- (void)viewWillAppear:(BOOL)animated
{
if (UIInterfaceOrientationIsLandscape(self.interfaceOrientation))
{
if (self.interfaceOrientation == UIInterfaceOrientationLandscapeLeft) {
prevInterfaceOrientation = UIInterfaceOrientationLandscapeLeft;
self.navigationController.view.transform = CGAffineTransformIdentity;
self.navigationController.view.transform =
CGAffineTransformMakeRotation(degreesToRadians(90));
}
else if (self.interfaceOrientation ==
UIInterfaceOrientationLandscapeRight) {
prevInterfaceOrientation = UIInterfaceOrientationLandscapeRight;
self.navigationController.view.transform = CGAffineTransformIdentity;
self.navigationController.view.transform =
CGAffineTransformMakeRotation(degreesToRadians(-90));
}
[[UIApplication sharedApplication] setStatusBarOrientation:UIInterfaceOrientationPortrait animated:NO];
[self.tableViewDetail reloadData];
}
}
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
{
return (interfaceOrientation == UIInterfaceOrientationPortrait);
}
- (void)willAnimateRotationToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation duration:(NSTimeInterval)duration
{
if (toInterfaceOrientation == UIInterfaceOrientationPortrait)
{
if (prevInterfaceOrientation == UIInterfaceOrientationLandscapeLeft) {
self.navigationController.view.transform = CGAffineTransformIdentity;
}
else if (prevInterfaceOrientation ==
UIInterfaceOrientationLandscapeRight) {
self.navigationController.view.transform = CGAffineTransformIdentity;
}
[[UIApplication sharedApplication] setStatusBarOrientation:UIInterfaceOrientationPortrait];
[self.tableViewDetail reloadData];
}
}
I even tried to use:
- (void)didRotateFromInterfaceOrientation:(UIInterfaceOrientation)fromInterfaceOrientation
{
if (UIInterfaceOrientationIsLandscape(prevInterfaceOrientation))
{
[[UIApplication sharedApplication] setStatusBarOrientation:UIInterfaceOrientationPortrait];
}
}
but self.interfaceOrientation still stays landscape, when I rotate to portrait.
But I really need to rotate the view to portrait mode manually to allow users to see,that FirstViewController suppors only portrait orientation.
I have the option to put the SecondViewController's view on MainWindow (like modal window), but I don't like this idea, because if apple has setStatusBarOrientation method, it seems to me, that it has to be right solve of this issue.
I would get rid of the transformations, and use
[[UIApplication sharedApplication] setStatusBarOrientation:UIInterfaceOrientationPortrait animated:animated];
This in combination with the forced redrawing of the view stack will get it done. This can be done by adding the following to viewDidAppear to the first controller (it doesn't work in viewWillApear).
- (void)viewDidAppear:(BOOL)animated {
[super viewDidAppear:animated];
UIWindow *window = [[UIApplication sharedApplication] keyWindow];
if ([window.subviews count] > 0) {
UIView *view = [window.subviews objectAtIndex:0];
[view removeFromSuperview];
[window insertSubview:view atIndex:0];
}
else {
DLog(#"NO view to force rotate?");
}
Unfortunately, the transition animation is not very clean when you do this, so I would recommend taking a snapshot of the portrait screen, overlay this over your view, and then fade it out with a separate animation.
Steven Veltema's answer didn't work for me.
I had one view controller where all orientations where allowed, and the rest only supported portrait. When i had the first view controller in landscape and navigated to another view controller, the orientation didn't refresh as you are experiencing.
I found another trick to reload the views i correct orientation. Just add a modal view controller you don't even see it. Add this in all other views:
- (void)viewDidAppear:(BOOL)animated
{
UIInterfaceOrientation interfaceOrientation = [[UIApplication sharedApplication] statusBarOrientation];
if(UIInterfaceOrientationIsLandscape(interfaceOrientation)){
UIViewController * viewController = [[UIViewController alloc] init];
[self presentModalViewController:viewController animated:NO];
[viewController dismissModalViewControllerAnimated:NO];
}
[super viewDidAppear:animated];
....
}
Another quick solution is
Click on your project in the left side bar.
In General settings, choose "Hide during application launch" option.

Storyboards orientation support for xCode 4.2?

I upgraded to xCode 4.2 and it's new Storyboards feature. However, could not find a way to support both portrait and landscape.
Of course, I did it programmatically, with 2 views, one for portrait and one for landscape, like in old days, and:
if (interfaceOrientation == UIInterfaceOrientationLandscapeLeft || interfaceOrientation == UIInterfaceOrientationLandscapeRight)
{
self.view = self.landscapeView;
}
else
{
self.view = self.portraitView;
}
But I was looking for a way to do this automatically somehow. I mean, it's xCode 4.2 now, I expected more from it. Thanks all.
==================================
TEMPORARY SOLUTION:
I will present here a temporary solution. I say it's temporary, because I am still waiting for Apple guys to do something really intelligent about this.
I created another .storyboard file, called "MainStoryboard_iPhone_Landscape", and implemented the landscape view controllers there. Actually, it's exactly like normal(portrait) .storyboard, but all screens are in landscape mode.
So I will extract the ViewController from landscape storyboard, and when rotation occurs, just change self.view with the new viewController's view.
1.Generate Notifications when orientation changes:
[[UIDevice currentDevice] beginGeneratingDeviceOrientationNotifications];
2.Look for notifications:
[[NSNotificationCenter defaultCenter] addObserverForName:UIDeviceOrientationDidChangeNotification object:nil queue:nil usingBlock:^(NSNotification *note) {
// We must add a delay here, otherwise we'll swap in the new view
// too quickly and we'll get an animation glitch
[self performSelector:#selector(updateLandscapeView) withObject:nil afterDelay:0];
}];
3.Implement updateLandscapeView
- (void)updateLandscapeView {
//> isShowingLandscapeView is declared in AppDelegate, so you won't need to declare it in each ViewController
UIDeviceOrientation deviceOrientation = [UIDevice currentDevice].orientation;
if (UIDeviceOrientationIsLandscape(deviceOrientation) && !appDelegate().isShowingLandscapeView)
{
UIStoryboard *storyboard = [UIStoryboard storyboardWithName:#"MainStoryboard_iPhone_Landscape" bundle:[NSBundle mainBundle]];
MDBLogin *loginVC_landscape = [storyboard instantiateViewControllerWithIdentifier:#"MDBLogin"];
appDelegate().isShowingLandscapeView = YES;
[UIView transitionWithView:loginVC_landscape.view duration:0 options:UIViewAnimationOptionTransitionCrossDissolve|UIViewAnimationCurveEaseIn animations:^{
//> Setup self.view to be the landscape view
self.view = loginVC_landscape.view;
} completion:NULL];
}
else if (UIDeviceOrientationIsPortrait(deviceOrientation) && appDelegate().isShowingLandscapeView)
{
UIStoryboard *storyboard = [UIStoryboard storyboardWithName:#"MainStoryboard_iPhone" bundle:[NSBundle mainBundle]];
MDBLogin *loginVC = [storyboard instantiateViewControllerWithIdentifier:#"MDBLogin"];
appDelegate().isShowingLandscapeView = NO;
[UIView transitionWithView:loginVC.view duration:0 options:UIViewAnimationOptionTransitionCrossDissolve|UIViewAnimationCurveEaseIn animations:^{
//> Setup self.view to be now the previous portrait view
self.view = loginVC.view;
} completion:NULL];
}}
Good luck to everybody.
P.S: I will accept Ad Taylor's answer, because, after much time waiting and searching for a solution, I finished up implementing something inspired from his answer. Thanks Taylor.
This is an old question but I read this earlier in the day and then had to spend a fair amount of time work out a better solution. I came up with this solution from hacking up the Apple Alternate View example. Basically it is serving up a modal view for the landscape view.
#pragma mark Rotation view control
- (void)orientationChanged:(NSNotification *)notification
{
// We must add a delay here, otherwise we'll swap in the new view
// too quickly and we'll get an animation glitch
[self performSelector:#selector(updateLandscapeView) withObject:nil afterDelay:0];
}
- (void)updateLandscapeView
{
UIDeviceOrientation deviceOrientation = [UIDevice currentDevice].orientation;
if (UIDeviceOrientationIsLandscape(deviceOrientation) && !self.isShowingLandscapeView)
{
[self performSegueWithIdentifier: #"toLandscape" sender: self];
self.isShowingLandscapeView = YES;
}
else if (deviceOrientation == UIDeviceOrientationPortrait && self.isShowingLandscapeView)
{
[self dismissModalViewControllerAnimated:YES];
self.isShowingLandscapeView = NO;
}
}
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
{
// Return YES for supported orientations
return (interfaceOrientation == UIInterfaceOrientationPortrait);
}
You shouldn't generally be thinking of separate views for different orientations unless they are widely different (which, arguably, they shouldn't be). Instead, you should rely on autoresizing masks to lay out as much of your view's content based on basic restraints when the superview's frame changes. This will allow subviews to respond appropriately to a change in their superview's frame, often as a result of an interface orientation change.
To answer your question more directly, no, there is no way for Xcode to assume or be told which views you want to use for a particular interface orientation as this was never the intent of UIKit's view architecture.
Here is more information about autoresizing masks: Handling Layout Changes Automatically Using Autoresizing Rules.
In XCode v4.2.1 when using StoryBoards you can only change the orientation of the View Controller, and not the View itself, so if you have inserted another view there you wouldn't be able to change it's orientation, even if you could see the View properly.
So the previous way of having two Views would not appear to work when using StoryBoards (when using NIB's where the View Orientation is changeable for separate Views).

Wikitude SDK remove from superview

I have implement Wikitude SDK and I manage to initialize using this code:
-(IBAction)launchAR:(id)sender{
wikitudeAR = [[WikitudeARViewController alloc] initWithDelegate:self applicationPackage:nil applicationKey:nil applicationName:nil developerName:nil];
}
- (void) verificationDidSucceed {
BuddyFinderAppDelegate *appDel = (BuddyFinderAppDelegate *)[[UIApplication sharedApplication] delegate];
[appDel.window addSubview: [wikitudeAR start]];
[window makeKeyAndVisible];
}
How I will go back to my MainViewController View?
(I want to call it from object "custombutton")
I guess your WikitudeARViewController delegate is application delegate.
1) Implement your own View controller , from where you want to launch AR Browser (on button click , preferably).
2) Instantiate WikitudeARViewController from your ViewController(button event) and making ViewController as delegate.
3) make view returned from [wikitudeAR start] to the ViewController.view (and not window.view).
Hope this helps.
you can use CustomMenuButtonDelegateImpl1.m
#implementation CustomMenuButtonDelegateImpl1
- (void) customMenuButtonPressed:(WTPoi *)currentSelectedPoi {
//NSLog(#"addpoi");
[[WikitudeARViewController sharedInstance] hide];
[UIApplication sharedApplication].statusBarHidden = NO;
}
#end
and it woroks very well

Making one specific class of view controller auto rotate in a tab bar app, but forcing all other classes of view controller to stay portrait

I have a tab bar controller with this code
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation {
// Return YES for supported orientations
//NSLog(#"object type %#" ,nil);
if([[self navigationController ] isKindOfClass:[UINavigationController class]])
if([[[self navigationController] visibleViewController] isKindOfClass:[SLImageViewController class]])
return YES;
return (interfaceOrientation == UIInterfaceOrientationPortrait);
}
I need any instance of the SLImageViewController class to rotate, but none of the others. I have done everything i can think of like adding return YES to my SLImageViewController and other fixes.
Can anyone tell me what I'm doing wrong?
You could accomplish this by:
setting statusBar orientation to viewWillAppear and viewWillDisappear
-(void) viewWillAppear:(BOOL)animated {
[super viewWillAppear: animated];
[[UIApplication sharedApplication] setStatusBarOrientation: UIInterfaceOrientationLandscapeRight];
}
-(void) viewWillDisappear:(BOOL)animated {
[super viewWillDisappear: animated];
[[UIApplication sharedApplication] setStatusBarOrientation: UIInterfaceOrientationPortrait];
}
and rotating a view manually: self.view.transform = CGAffineTransformMakeRotation(M_PI/2);
presenting that view modaly will trigger shouldAutorotateToInterfaceOrientation method