So in cocos2d (I believe I was on v2.1) I did this to lock and set the orientations:
AppDelegate *delegate = (AppDelegate *)[[UIApplication sharedApplication] delegate];
const UIInterfaceOrientation ORIENTATION = delegate.navController.interfaceOrientation;
delegate.navController.
delegate.navController.screenOrientation = ORIENTATION == UIInterfaceOrientationMaskPortrait;
UIViewController *mVC = [[UIViewController alloc] init];
[delegate.navController presentModalViewController:mVC animated:NO];
[delegate.navController dismissModalViewControllerAnimated:NO];
With some functions added to the AppDelegate.
I cannot seem to get the same results in iOS7 and cocos2d v3.
I have dug through a bit and the proper functions seem to be in place but cannot seem to set up a global variable to set the orientation and return only the one I want at the certain time. Can someone point me down the proper path. I think I'm missing something really small cause the proper code seems to be there already.
Here's the code for my AppDelegate
#implementation AppDelegate
-(BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
[self setupCocos2dWithOptions:#{
CCSetupShowDebugStats: #(NO),
}];
[[UIDevice currentDevice] beginGeneratingDeviceOrientationNotifications];
return YES;
}
-(CCScene *)startScene
{
return [HomeScreen scene];
}
-(NSUInteger)supportedInterfaceOrientations
{
return UIInterfaceOrientationMaskLandscape;
}
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
{
return UIInterfaceOrientationIsLandscape(interfaceOrientation);
}
My code never hits the interfaceOrientation functions.
Thoughts??!?
After a couple days fooling around I figured out a solution:
in AppDelegate I needed this function:
-(NSUInteger)application:(UIApplication *)application supportedInterfaceOrientationsForWindow:(UIWindow *)window
{
if (!self.lockedToOrientation) {
if( [[UIDevice currentDevice] userInterfaceIdiom] == UIUserInterfaceIdiomPhone ){
return UIInterfaceOrientationMaskPortrait;
}
return UIInterfaceOrientationMaskPortrait;
}
else {
return self.lockedToOrientation;
}
}
Where
#property UIInterfaceOrientationMask lockedToOrientation;
Hope this helps someone!
Cheers.
Related
When a certain button is pressed in my app, the view should change orientation from portrait to
landscape. When the user comes back, the view controller should change back to portrait. But
sometimes the orientation doesn't change or the wrong view frame is used.
Here is my code
-(void)btnSignClicked:(CustomSignButton *)btn {
isSignButtonClicked = true;
if (NSFoundationVersionNumber > NSFoundationVersionNumber_iOS_7_0) {
NSNumber *value = [NSNumber numberWithInt:UIInterfaceOrientationLandscapeRight];
[[UIDevice currentDevice] setValue:value forKey:#"orientation"];
}
else
{
[[UIApplication sharedApplication] setStatusBarOrientation:UIInterfaceOrientationLandscapeRight animated:YES];
}
selectedWaiverId = btn.customTag;
SignatureView *obj = [[SignatureView alloc] initWithFrame:CGRectMake(0, 0, self.view.frame.size.width, self.view.frame.size.height) delegate:self]; // Most of time got size (568,320) but some time i got (320,568), Don't know why
[self.view addSubview:obj];
}
#pragma mark - SIGNATUREVIEW DELEGATE
-(void)removeSignatureView:(SignatureView *)signatureView {
isSignButtonClicked = false;
if (NSFoundationVersionNumber > NSFoundationVersionNumber_iOS_7_0)
{
NSNumber *value = [NSNumber numberWithInt:UIInterfaceOrientationPortrait];
[[UIDevice currentDevice] setValue:value forKey:#"orientation"]; // Some time not changed the orientation are view remaining in landscape
}
else
{
[[UIApplication sharedApplication] setStatusBarOrientation:UIInterfaceOrientationPortrait animated:YES];
}
[signatureView removeFromSuperview];
signatureView = nil;
}
#pragma mark
#pragma mark - Rotate screen
-(UIInterfaceOrientationMask)supportedInterfaceOrientations
{
if (isSignButtonClicked == true)
{
return UIInterfaceOrientationMaskLandscapeRight|UIInterfaceOrientationMaskLandscape;
}
else
{
return UIInterfaceOrientationMaskPortrait;
}
}
- (BOOL)shouldAutorotate
{
return YES;
}
-(BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
{
if (isSignButtonClicked == true)
{
return (interfaceOrientation == UIInterfaceOrientationLandscapeRight);
}
else
{
return (interfaceOrientation == UIInterfaceOrientationPortrait);
}
}
UPDATE
Sometimes viewWillTransitionToSize method is not called so I also integrate this notification
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(deviceOrientationDidChange:) name:UIDeviceOrientationDidChangeNotification object:nil];
[[UIDevice currentDevice] beginGeneratingDeviceOrientationNotifications];
But sometimes this also does not work.
Add in AppDelegate.m file or any base controller file
#implementation UINavigationController (Orientation)
- (UIInterfaceOrientationMask) supportedInterfaceOrientations
{
return [(UIViewController*)[[self viewControllers] lastObject] supportedInterfaceOrientations];
}
- (UIInterfaceOrientation)preferredInterfaceOrientationForPresentation
{
return [(UIViewController*)[[self viewControllers] lastObject] preferredInterfaceOrientationForPresentation];
}
- (BOOL) shouldAutorotate
{
return [(UIViewController*)[[self viewControllers] lastObject] shouldAutorotate];
}
#end
Now put your ViewController object in UINavigationController object and push the view controller.
EX.
UINavigationController *obj=[[UINavigationController alloc] initWithRootViewController:_yourViewCtrlObj];
[self presentViewController:obj.....];
or
[self.navigationController pushViewController:obj animated:YES];
Set your desired orientation in all view controller.
If your app uses UINavigationViewController then create a custom class for UINAvigationController Like:
//CustomNavViewController.h
#import <UIKit/UIKit.h>
#interface CustomNavViewController : UINavigationController <UINavigationControllerDelegate>
#end
//CustomNavViewController.m
#import "CustomNavViewController.h"
#interface CustomNavViewController ()
#end
#implementation CustomNavViewController
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view.
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
- (BOOL)shouldAutorotate {
return [self.visibleViewController shouldAutorotate];
}
- (UIInterfaceOrientationMask)supportedInterfaceOrientations {
return [self.visibleViewController supportedInterfaceOrientations];
}
#end
And Now in your AppDelegate declare a property Like:
//AppDelegate.h
#property (assign, nonatomic) BOOL shouldRotate;
//AppDelegate.m
- (UIInterfaceOrientationMask)application:(UIApplication *)application supportedInterfaceOrientationsForWindow:(UIWindow *)window
{
if (self.shouldRotate) {
return UIInterfaceOrientationMaskLandscapeLeft|UIInterfaceOrientationMaskLandscapeRight;
}
return UIInterfaceOrientationMaskPortrait;
}
Now you can call orientation methods to ViewController which required fix orientation Like:
//YourViewController.m
-(BOOL)shouldAutorotate{
return NO;
}
- (UIInterfaceOrientationMask)supportedInterfaceOrientations{
return UIInterfaceOrientationMaskLandscape;
}
- (UIInterfaceOrientation)preferredInterfaceOrientationForPresentation{
return UIInterfaceOrientationLandscapeLeft;
}
Now here is the trick set AppDelegate shouldRotate property to true and false for desired orientation
if you are using Default Presentation for ViewController then
AppDelegate *appDelegate = (AppDelegate *)[UIApplication sharedApplication].delegate;
[appDelegate setShouldRotate:true];// Remember first update the value then present the ViewController
[self presentViewController:yourViewController animated:YES completion:nil];
Same as when you dismiss
AppDelegate *appDelegate = (AppDelegate *)[UIApplication sharedApplication].delegate;
[appDelegate setShouldRotate:false];
[self dismissViewControllerAnimated:YES completion:nil];
If you are using storyBoards then add CustomNavViewController directly on Identity Inspector Custom class section
And after that follow above steps. Hope it's working
When you say "When the user comes back, the view controller should change back to portrait", do you mean that the user is hitting the back button on a navigation controller? If so, I saw this issue before and posted a solution that worked for me in another SO post: A: Locking device orientation on a view fails when going back in NavBar. I remember the transition being rough but it worked.
I also wrote a blog post a while back that looks at some other situations around view controller orientation locking.
See this link, in particular, I think you should check the conditions of your view controllers, that they meet Apple recommendations
e.g. check supportedInterfaceOrientations method of the top-most full-screen view controller
Try adding all your rotation changing code inside this block
dispatch_async(dispatch_get_main_queue(),
{
//changing orientation code + isSignButtonClicked = true (or false)
});
You need not use shouldAutorotate and shouldAutorotateToInterfaceOrientation.
As for the view frames getting wrong, you need to use autolayout constraints for each and every view you are using in this viewController even if you are creating views programmativally
At iOS8 i used
- (BOOL)shouldAutorotate
{
return NO;
}
-(UIInterfaceOrientationMask)supportedInterfaceOrientations{
return UIInterfaceOrientationMaskPortrait | UIInterfaceOrientationMaskPortraitUpsideDown;
}
- (UIInterfaceOrientation)preferredInterfaceOrientationForPresentation{
return UIInterfaceOrientationPortrait;
}
but not working at iOS9 iPad Air2,
Also, I find another solution but not working either,
override the function below in custom UINavigationController:
-(UIInterfaceOrientationMask)supportedInterfaceOrientations
{
return [self.viewControllers.lastObject supportedInterfaceOrientations];
}
-(UIInterfaceOrientation)preferredInterfaceOrientationForPresentation
{
return [self.viewControllers.lastObject preferredInterfaceOrientationForPresentation];
}
-(BOOL)shouldAutorotate{
return self.visibleViewController.shouldAutorotate;
}
Can someone help me? Thanks!
You certainly had defined the allowed orientations in info.plist which overrides anything you do anywhere else throughout the project.
To correct the issue you can removed the entries from info.plist and defined them in the project settings.
try this in viewDidAppear:
NSNumber *orientationValue = [NSNumber numberWithInt:UIInterfaceOrientationLandscapeLeft];
[[UIDevice currentDevice] setValue: orientationValue forKey:#"orientation"];
it can be flicker in this answer. if you don't want flicker, try this option it will work:
- (NSUInteger)application:(UIApplication *)application supportedInterfaceOrientationsForWindow:(UIWindow *)window
{
if ([self.window.rootViewController.presentedViewController isKindOfClass: [SecondViewController class]])
{
SecondViewController *secondController = (SecondViewController *) self.window.rootViewController.presentedViewController;
return UIInterfaceOrientationMaskLandscapeRight;
}
return UIInterfaceOrientationMaskPortrait;
}
First of all, I would like to apologize for asking the same question again which has been asked in this forum many times. But, my problem is that I've tried all the suggested solutions but still I haven't got a solution to my problem.
I have a ViewControllerA in Potrait mode and ViewControllerB in landscape mode. When the device changes from potrait to landscape, i can see ViewControllerB opening in landscape mode, but when the device is rotated back to potrait mode, ViewControllerA is displayed but still in landscape mode. Could anybody help me understand how can I display it back in potrait mode?
I have tried following things but nothing worked for me:
Added following code in ViewControllerA in viewWillAppear:
[[UIApplication sharedApplication] setStatusBarOrientation:UIInterfaceOrientationPortrait];
Have also added following functions in this view controller:
- (BOOL)shouldAutorotate
{
return NO;
}
- (NSUInteger)supportedInterfaceOrientations
{
return UIInterfaceOrientationMaskPortrait;
}
- (UIInterfaceOrientation)preferredInterfaceOrientationForPresentation
{
return UIInterfaceOrientationPortrait;
}
Hope this helps you by using supportedInterfaceOrientationsForWindow
Appdelegate.h
#property () BOOL restrictRotation;
in Appdelegate.m
-(NSUInteger)application:(UIApplication *)application supportedInterfaceOrientationsForWindow:(UIWindow *)window
{
//restrictRotation is BOOL value
if(self.restrictRotation)//set the bool value to view controller which you want to load in landscape
return UIInterfaceOrientationMaskLandscape;
else
return UIInterfaceOrientationMaskAll;
}
//call this where you need
requiredViewController.m
-(void) restrictRotation:(BOOL) restriction
{
appDelegate = (AppDelegate*)[UIApplication sharedApplication].delegate;
appDelegate.restrictRotation = restriction;
}
//In ViewdidLoad()
- (void)viewDidLoad
{
[super viewDidLoad];
[self restrictRotation:YES];//Set YES if required in Landscape mode
}
Please try
[[UIDevice currentDevice] setValue:[NSNumber numberWithInteger:UIInterfaceOrientationPortrait] forKey:#"orientation"];
Use below code
-(void) viewDidAppear:(BOOL)animated
{
[UIViewController attemptRotationToDeviceOrientation];
[super viewDidAppear:animated];
}
& also in viewWIllAppear write
[UIDevice currentDevice] setValue:[NSNumber numberWithInteger:UIInterfaceOrientationPortrait] forKey:#"orientation"]
I want to disable the autorotation of iOS device for few view controllers.Like i have one few controller i want it to be displayed only in portrait mode.Where as others view controller in landscape mode.I have used following code but these delegate methods are never called?
#pragma mark Orientation handling
- (BOOL) shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation {
return (interfaceOrientation == UIInterfaceOrientationPortrait);
}
-(BOOL)shouldAutorotate
{
return NO;
}
-(NSUInteger)supportedInterfaceOrientations
{
return (UIInterfaceOrientationMaskPortrait);
}
I used following method to forcefully set portrait orientation only for some selected view and its work for me, may be it will be help you
1, Create one global flag
Create on Global flag in your AppDelegate Method So you can access it in any View controllers .
In your AppDelegate.h
#property (assign) BOOL flagOrientationAll;
In your AppDelegate.m
#synthesize flagOrientationAll;
Add following method in your AppDelegate.m
- (NSUInteger)application:(UIApplication *)application supportedInterfaceOrientationsForWindow:(UIWindow *)window{
if(flagOrientationAll == YES){
return UIInterfaceOrientationMaskAll; // All orientation support
} else {
return UIInterfaceOrientationMaskPortrait; // Set only one orientation you want
}
}
2, Add following code in ViewController .m for that you want to restrict rotation
// set flag "flagOrientationAll" to rotate only one view in your particular view
#import AppDelegate.h
-(void)viewWillAppear:(BOOL)animated
{
NSLog (#"webViewController -- viewWillAppear");
[super viewWillAppear:animated];
AppDelegate *delegate = (AppDelegate *) [[UIApplication sharedApplication] delegate];
delegate.flagOrientationAll = YES;
}
-(void)viewWillDisappear:(BOOL)animated
{
AppDelegate *delegate = (AppDelegate *)[[UIApplication sharedApplication] delegate];
delegate.flagOrientationAll = NO;
}
Here my POST : How to set one of the screens in landscape mode in iphone?
If you get any trouble let me know!!
Please don't suggest me it is a bad idea to have the rotation at ios 4.3-6.0 in 1 build, because I told to many times and didn't listen to me.
At project settings I have setted all interface orientations to be supported, just to be sure.
Right now I am testing on ios6 with iphone4. Starting at app delegate it is a code, like this:
mainController = [[MainViewController alloc] initWithNibName:nil bundle:nil];
navigationController=[[RotatingNavigationController alloc] initWithRootViewController:mainController];
navigationController.navigationBar.hidden =true;
// ios: 4 and 5
//[window addSubview:navigationController.view];
//ios6:
window.rootViewController = navigationController;
[window makeKeyAndVisible];
So I did 2 custom classes, which are recommended in may cases for autorotations, and for they the problem is solved.
The RotatingNavigationController is a custom UINavigationController has a bit ugly code, but I have collected this parts from this forum, so it should be allowed to post it:
#implementation RotatingNavigationController
- (id)init {
self = [super init];
if (self) {
self.view.autoresizesSubviews = YES;
[self.view setAutoresizingMask:(UIViewAutoresizingFlexibleHeight | UIViewAutoresizingFlexibleWidth)];
}
return self;
}
// ios6 require this method for rotation detection, available from ios5, ios4.3 not available: sux
//- (void)viewWillLayoutSubviews
//{
//UIInterfaceOrientation statusBarOrientation = [UIApplication sharedApplication].statusBarOrientation;
//[[NSNotificationCenter defaultCenter] postNotificationName:UIDeviceOrientationDidChangeNotification object:nil];
// [[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(orientationChanged:) name:UIDeviceOrientationDidChangeNotification object:nil];
/*
if(UIInterfaceOrientationIsLandscape(statusBarOrientation)){
[self willRotateToInterfaceOrientation: statusBarOrientation duration: 0.3 ];
}
else{
[self willRotateToInterfaceOrientation: statusBarOrientation duration: 0.3 ];
}
*/
//}
//ios 4.3 and ios 5.0, at ios6 it isn't called by iOS...sux
- (void)willRotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation duration:(NSTimeInterval)duration{
[self.visibleViewController willRotateToInterfaceOrientation:toInterfaceOrientation duration:duration];
}
// //ios 4.3 and ios 5.0, at ios6 need different methods, which sux
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation {
return YES;
}
//Autorotation is changing in iOS 6. In iOS 6, the shouldAutorotateToInterfaceOrientation: method of UIViewController is deprecated. In its place, you should use the supportedInterfaceOrientationsForWindow: and shouldAutorotate methods.
// ios6
- (NSUInteger)supportedInterfaceOrientationsForWindow:(UIWindow *)window
{
return UIInterfaceOrientationMaskAll;
}
// ios6
- (BOOL)shouldAutorotate
{
return YES;
}
// ios6
- (UIInterfaceOrientation)preferredInterfaceOrientationForPresentation {
return UIInterfaceOrientationMaskPortrait;
}
#end
this should generate the autorotation notifications properly, I think he it does his job.
The MainViewController is a custom UIViewController.
just to be sure I have copy-pasted the code:
// Override to allow orientations other than the default portrait orientation.
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation {
// Return YES for supported orientations
// return (interfaceOrientation == UIInterfaceOrientationPortrait);
return YES;
}
// ios6:
- (NSUInteger)supportedInterfaceOrientationsForWindow:(UIWindow *)window
{
return UIInterfaceOrientationMaskAll;
}
// ios6
- (BOOL)shouldAutorotate
{
return YES;
}
- (UIInterfaceOrientation)preferredInterfaceOrientationForPresentation {
return UIInterfaceOrientationMaskPortrait;
}
His job is to change the different UIViewController based on device state ( rotations )
I have somewhere a Menu screen, which has different xib, but h and m file too ( because has different elements, which doesn't appear in Portait or Landscape. ( I don't have the power to change the whole architecture )
A part of the code - and here should be some problem, I think is below in this Maincontroller:
#pragma mark
#pragma mark Rotation
- (void)orientationChanged:(NSNotification *)notification
{
UIDeviceOrientation deviceOrientation = [UIDevice currentDevice].orientation;
UIInterfaceOrientation statusBarOrientation = [UIApplication sharedApplication].statusBarOrientation;
if(deviceOrientation == UIDeviceOrientationFaceUp || deviceOrientation == UIDeviceOrientationFaceDown){
if(debug){
NSLog(#"Nothing to change because it is gone to Flat");
}
return;
}
NSArray *viewControllers = [self.navigationController viewControllers];
if (UIDeviceOrientationIsLandscape(deviceOrientation)){
//if(debug)
// NSLog(#"Portait -> Landscape size : %3.0fw, %3.0fh", self.view.bounds.size.width, self.view.bounds.size.height);
id lastviewController = viewControllers.lastObject;
// check what is there:
if([lastviewController isKindOfClass:[MenuController class]]){
[self.navigationController popViewControllerAnimated:NO];
[self.navigationController pushViewController:menuLandscape animated:NO];
NSLog(#"poped Menu Portrait, pushed Menu Landscape");
}
...
else if(UIDeviceOrientationIsPortrait(deviceOrientation)){
//else if(UIInterfaceOrientationIsLandscape(statusBarOrientation)){
//if(debug)
// NSLog(#"Landscape -> Portait , size : %3.0fw, %3.0fh", self.view.bounds.size.width, self.view.bounds.size.height);
id lastviewController = viewControllers.lastObject;
// check what is there:
if([lastviewController isKindOfClass:[MenuLandscapeController class]]){
[self.navigationController popViewControllerAnimated:NO];
[self.navigationController pushViewController:menuPortait animated:NO];
}
...
The problem is: the landscape is taken out and is pushed the portait, when is upside down, but that portait aren't rotating and it shows a broken layout.
How can I wake up that controller and tell him is time to rotate, because it isn't in portrait mode?
Thanks any suggestion related to my question of any improvement beside of architecture change.
Update:
at app delgate doesn't helped adding the:
- (NSUInteger)application:(UIApplication *)application supportedInterfaceOrientationsForWindow:(UIWindow *)window{
return UIInterfaceOrientationMaskAll;
}
code from other answer: presented here
Update2:
UIInterfaceOrientation statusBarOrientation = [UIApplication sharedApplication].statusBarOrientation;
doesn't want to take the UIInterfaceOrientationPortraitUpsideDown = UIDeviceOrientationPortraitUpsideDown value for some reason, I think that need to be solved.
Update3:
Read very carefully twice and third the ios6 release notes
The system determines whether an orientation is supported by
intersecting the value returned by the app’s
supportedInterfaceOrientationsForWindow: method with the value
returned by the supportedInterfaceOrientations method of the top-most
full-screen controller.
now read again :)
Add this category to viewcontroller which doesn't rotate
#implementation UINavigationController(Rotation)
-(NSUInteger)supportedInterfaceOrientations {
return UIInterfaceOrientationMaskAll;
}
#end