How to constrain autorotation to a single orientation for some views, while allowing all orientations on others?

后端 未结 5 1318
孤街浪徒
孤街浪徒 2020-12-01 03:44

This question is about iOS device rotation and multiple controlled views in a UINavigationController. Some views should be constrained to portrait orientation, and

相关标签:
5条回答
  • 2020-12-01 04:03

    The short answer is that you're using UINavigationController, and that won't work like you want it to. From Apple's docs:

    Why won't my UIViewController rotate with the device?

    All child view controllers in your UITabBarController or UINavigationController do not agree on a common orientation set.

    To make sure that all your child view controllers rotate correctly, you must implement shouldAutorotateToInterfaceOrientation for each view controller representing each tab or navigation level. Each must agree on the same orientation for that rotate to occur. That is, they all should return YES for the same orientation positions.

    You can read more about view rotation issues here.

    You'll have to roll your own view/controller stack management for what you want to do.

    0 讨论(0)
  • 2020-12-01 04:10

    In iOS 6, this has become a very simple issue. Simply create a special class for the views you want to autorotate. Then, in your rootVC, add this.

    -(BOOL)shouldAutorotate{
           BOOL should = NO;
    
           NSLog(@"%@", [self.viewControllers[self.viewControllers.count-1] class]);
           if ([self.viewControllers[self.viewControllers.count-1] isKindOfClass:[YourAutorotatingClass class]]) {
                 should = YES;
           }
    
    
           return should;
    }
    

    I know this is an old question, but I thought it worthwhile to mention.

    0 讨论(0)
  • 2020-12-01 04:11

    Make a bolean in App delegate to control which orientation you want for example make a bool to enable Portrait and in your view controller you want to allow Portrait enable it by shared application

    in your view controller,where you want to enable or disable what ever orientation you want.

    ((APPNAMEAppDelegate *)[[UIApplication sharedApplication] delegate]).enablePortrait= NO;
    

    in App Delegate.

    - (NSUInteger)application:(UIApplication *)application supportedInterfaceOrientationsForWindow:(UIWindow *)window
    {
        NSLog(@"Interface orientations");
        if(!enablePortrait)
            return UIInterfaceOrientationMaskLandscape;
        return UIInterfaceOrientationMaskLandscape|UIInterfaceOrientationMaskPortrait;
    }
    

    These method will be fired each time you rotate the device, Based on these BOOL enable the orientation you want.

    0 讨论(0)
  • 2020-12-01 04:16

    DO NOT USE THIS HACK, APPLE WILL REJECT THE APP BASED ON THE USE OF 'PRIVATE API'

    For the sake of reference, I will leave my answer here, but the use of private API will not slip past the review board. I learnt something today :D As @younce quoted the Apple docs correctly, what I want cannot be achieved with the UINavigationController.

    I had two options. First, I could have written my own navigation controller substitute, with all the horrors that one would have encountered while doing it. Secondly, I could have hacked the rotation into the view controllers, using an undocumented feature of UIDevice called setOrientation:animated:

    Because the second was temptingly easy, I went for that one. This is what I did. You'll need a category to suppress compiler warnings about the setter not existing:

    @interface UIDevice (UndocumentedFeatures) 
    -(void)setOrientation:(UIInterfaceOrientation)orientation animated:(BOOL)animated;
    -(void)setOrientation:(UIInterfaceOrientation)orientation;
    @end
    

    Then you need to check for the supported orientations on viewWillAppear:. Next to the UIDevice methods used here, you could also force portrait orientation by presenting a modal view controller, but that will happen instantly and not animated, so this is my preferred way:

    -(void)viewWillAppear:(BOOL)animated {
        UIDevice *device = [UIDevice currentDevice];
        UIDeviceOrientation realOrientation = device.orientation;
    
        if ([self shouldAutorotateToInterfaceOrientation:realOrientation]) {
            if (realOrientation != [UIApplication sharedApplication].statusBarOrientation) {
    
                // Resetting the orientation will trigger the application to rotate
                if ([device respondsToSelector:@selector(setOrientation:animated:)]) {
                    [device setOrientation:realOrientation animated:animated];
                } else {
                    // Yes if Apple changes the implementation of this undocumented setter,
                    // we're back to square one.
                }
            }
        } else if ([self shouldAutorotateToInterfaceOrientation:UIInterfaceOrientationPortrait]) {
            if ([device respondsToSelector:@selector(setOrientation:animated:)]) {
    
                // Then set the desired orientation
                [device setOrientation:UIDeviceOrientationPortrait animated:animated];
    
                // And set the real orientation back, we don't want to truly mess with the iPhone's balance system.
                // Because the view does not rotate on this orientation, it won't influence the app visually.
                [device setOrientation:realOrientation animated:animated];
            }
        }
    }
    

    The trick is to always keep the internal device orientation to the 'real' orientation of the device. If you start changing that, the rotation of your app will be out of balance.

    But as I know now, this is just a sure way to get your app rejected. So option number two is just a bad option. Rewrite that NavigationController, or just have all your views support the same orientation set.

    Cheers, EP.

    0 讨论(0)
  • 2020-12-01 04:29

    There was a similar question a few years ago with a number of answers. Here is a recent answer from someone to that question:
    Is there a documented way to set the iPhone orientation?

    From what I understand, this is a problem a lot of people have and mostly hacks are the only way to fix it. Look through that thread if you haven't seen it before and see if anything works for you.

    On a side note, I had a similar problem a while back when I was calling something in shouldAutorotate and I added some code to viewWillAppear to try to fix it. I honestly can't remember if it worked and I don't have a Mac anymore to try it out, but I found the code and I'll paste it here in case it gives any inspiration.

    - (void)viewWillAppear:(BOOL)animated{
      UIInterfaceOrientation o;
      switch ([UIDevice currentDevice].orientation) {
        case UIDeviceOrientationPortrait:
            o = UIInterfaceOrientationPortrait;
            break;
        case UIDeviceOrientationLandscapeLeft:
            o = UIInterfaceOrientationLandscapeLeft;
            break;
        case UIDeviceOrientationLandscapeRight:
            o = UIInterfaceOrientationLandscapeRight;
            break;
        default:
            break;
      }
    
      [self shouldAutorotateToInterfaceOrientation:o];
    }
    
    0 讨论(0)
提交回复
热议问题