Forced orientation change does not work sometimes
Asked Answered
A

5

6

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.

Anu answered 4/3, 2016 at 11:18 Comment(3)
Is this method for changing orientation even documented or is it a hack?Sonstrom
Fairly certain "credible and/or official sources" would recommend against doing this.Rasberry
it is in document @Sulthan.Anu
F
2

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.

Frontpage answered 19/3, 2016 at 9:58 Comment(1)
I already done this all except the present and dismiss the VC because i am not using new VC for it i only present the ViewAnu
M
1

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

customNav And after that follow above steps. Hope it's working

Meritorious answered 19/3, 2016 at 11:59 Comment(1)
I already done this all except the present and dismiss the VC because i am not using new VC for it i only present the ViewAnu
E
1

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.

Ebeneser answered 20/3, 2016 at 5:2 Comment(0)
W
0

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

Wheaton answered 14/3, 2016 at 13:4 Comment(0)
S
0

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

Sherrer answered 18/3, 2016 at 22:13 Comment(3)
it is very old code so autolayout not implement in it. I already used dispatch in code but not get success.Anu
I too had old code, but id had to change it to autolayout to get the frames correctly. It isn't much of a pain. You can autolayout programmatically where you set frames in code. Also you need to add ViewControllerBasedOrientation in info.plist to YESSherrer
There is no option for "ViewControllerBasedOrientation" in info.plistAnu

© 2022 - 2024 — McMap. All rights reserved.