Is there a documented way to set the iPhone orientation?

后端 未结 17 1045
清歌不尽
清歌不尽 2020-11-22 11:09

I have an app where I would like to support device rotation in certain views but other don\'t particularly make sense in Landscape mode, so as I swapping the views out I wou

相关标签:
17条回答
  • 2020-11-22 11:44

    Josh's answer works fine for me.

    However, I prefer posting an "orientation did change, please update UI" notification. When this notification is received by a view controller, it calls shouldAutorotateToInterfaceOrientation:, allowing you to set any orientation by returning YES for the orientation you want.

    [[NSNotificationCenter defaultCenter] postNotificationName:UIDeviceOrientationDidChangeNotification object:nil];
    

    The only problem is that this forces a re-orientation without an animation. You would need to wrap this line between beginAnimations: and commitAnimations to achieve a smooth transition.

    Hope that helps.

    0 讨论(0)
  • 2020-11-22 11:49

    FWIW, here's my implementation of manually setting orientation (to go in your app's root view controller, natch):

    -(void)rotateInterfaceToOrientation:(UIDeviceOrientation)orientation{
    
        CGRect bounds = [[ UIScreen mainScreen ] bounds ];
        CGAffineTransform t;
        CGFloat r = 0;
        switch ( orientation ) {
            case UIDeviceOrientationLandscapeRight:
                r = -(M_PI / 2);
                break;
            case UIDeviceOrientationLandscapeLeft:
                r  = M_PI / 2;
                break;
        }
        if( r != 0 ){
            CGSize sz = bounds.size;
            bounds.size.width = sz.height;
            bounds.size.height = sz.width;
        }
        t = CGAffineTransformMakeRotation( r );
    
        UIApplication *application = [ UIApplication sharedApplication ];
    
        [ UIView beginAnimations:@"InterfaceOrientation" context: nil ];
        [ UIView setAnimationDuration: [ application statusBarOrientationAnimationDuration ] ];
        self.view.transform = t;
        self.view.bounds = bounds;
        [ UIView commitAnimations ];
    
        [ application setStatusBarOrientation: orientation animated: YES ];     
    }
    

    coupled with the following UINavigationControllerDelegate method (assuming you're using a UINavigationController):

    -(void)navigationController:(UINavigationController *)navigationController willShowViewController:(UIViewController *)viewController animated:(BOOL)animated{
        // rotate interface, if we need to
        UIDeviceOrientation orientation = [[ UIDevice currentDevice ] orientation ];
        BOOL bViewControllerDoesSupportCurrentOrientation = [ viewController shouldAutorotateToInterfaceOrientation: orientation ];
        if( !bViewControllerDoesSupportCurrentOrientation ){
            [ self rotateInterfaceToOrientation: UIDeviceOrientationPortrait ];
        }
    }
    

    That takes care of rotating the root view according to whether an incoming UIViewController supports the current device orientation. Finally, you'll want to hook up rotateInterfaceToOrientation to actual device orientation changes in order to mimic standard iOS functionality. Add this event handler to the same root view controller:

    -(void)onUIDeviceOrientationDidChangeNotification:(NSNotification*)notification{
        UIViewController *tvc = self.rootNavigationController.topViewController;
        UIDeviceOrientation orientation = [[ UIDevice currentDevice ] orientation ];
        // only switch if we need to (seem to get multiple notifications on device)
        if( orientation != [[ UIApplication sharedApplication ] statusBarOrientation ] ){
            if( [ tvc shouldAutorotateToInterfaceOrientation: orientation ] ){
                [ self rotateInterfaceToOrientation: orientation ];
            }
        }
    }
    

    Finally, register for UIDeviceOrientationDidChangeNotification notifications in init or loadview like so:

    [[ NSNotificationCenter defaultCenter ] addObserver: self
                                               selector: @selector(onUIDeviceOrientationDidChangeNotification:)
                                                   name: UIDeviceOrientationDidChangeNotification
                                                 object: nil ];
    [[ UIDevice currentDevice ] beginGeneratingDeviceOrientationNotifications ];
    
    0 讨论(0)
  • 2020-11-22 11:50

    This is what I use. (You get some compile warnings but it works in both the Simulator and the iPhone)

    [[UIApplication sharedApplication] setStatusBarOrientation:UIInterfaceOrientationLandscapeRight];
    [[UIDevice currentDevice] setOrientation:UIInterfaceOrientationLandscapeRight];
    
    0 讨论(0)
  • 2020-11-22 11:52

    I've been digging and digging looking for a good solution to this. Found this blog post that does the trick: remove your outermost view from the key UIWindow and add it again, the system will then re-query the shouldAutorotateToInterfaceOrientation: methods from your viewcontrollers, enforcing the correct orientation to be applied. See it : iphone forcing uiview to reorientate

    0 讨论(0)
  • 2020-11-22 11:56

    I solved this quite easily in the end. I tried every suggestion above and still came up short, so this was my solution:

    In the ViewController that needs to remain Landscape (Left or Right), I listen for orientation changes:

        [[NSNotificationCenter defaultCenter] addObserver:self
                                             selector:@selector(didRotate:)
                                                 name:UIDeviceOrientationDidChangeNotification object:nil];
    

    Then in didRotate:

    - (void) didRotate:(NSNotification *)notification
    {   if (orientationa == UIDeviceOrientationPortrait) 
        {
            if (hasRotated == NO) 
            {
                NSLog(@"Rotating to portait");
                hasRotated = YES;
                [UIView beginAnimations: @"" context:nil];
                [UIView setAnimationDuration: 0];
                self.view.transform = CGAffineTransformIdentity;
                self.view.transform = CGAffineTransformMakeRotation(DEGREES_TO_RADIANS(-90));
                self.view.bounds = CGRectMake(0.0f, 0.0f, 480.0f, 320.0f);
                self.view.frame = CGRectMake(0.0f, 0.0f, 480.0f, 320.0f);
                [UIView commitAnimations];
    
        }
    }
    else if (UIDeviceOrientationIsLandscape( orientationa))
    {
        if (hasRotated) 
        {
            NSLog(@"Rotating to lands");
            hasRotated = NO;
            [UIView beginAnimations: @"" context:nil];
            [UIView setAnimationDuration: 0];
            self.view.transform = CGAffineTransformIdentity;
            self.view.transform = CGAffineTransformMakeRotation(DEGREES_TO_RADIANS(0));
            self.view.bounds = CGRectMake(0.0f, 0.0f, 320.0f, 480.0f);
            self.view.frame = CGRectMake(0.0f, 0.0f, 320.0f, 480.0f);
            [UIView commitAnimations];
    
        }
    }
    

    Keep in mind any Super Views/Subviews that use autoresizing, as the view.bounds/frame are being reset explicitly...

    The only caveat to this method for keeping the view Landscape, is the inherent animation switching between orientations that has to occur, when it would be better to have it appear to have no change.

    0 讨论(0)
  • 2020-11-22 11:58

    I have an app where I would like to support device rotation in certain views but other don't particularly make sense in Landscape mode, so as I swapping the views out I would like to force the rotation to be set to portrait.

    I realise that the above original post in this thread is very old now, but I had a similar problem to it - ie. all of the screens in my App are portrait only, with the exception of one screen, which can be rotated between landscape and portrait by the user.

    This was straightforward enough, but like other posts, I wanted the App to automatically return to portrait regardless of the current device orientation, when returning to the previous screen.

    The solution I implemented was to hide the Navigation Bar while in landscape mode, meaning that the user can only return to previous screens whilst in portrait. Therefore, all other screens can only be in portrait.

    - (void)didRotateFromInterfaceOrientation:(UIInterfaceOrientation)pInterfaceOrientation {
        BOOL lHideNavBar = self.interfaceOrientation == UIInterfaceOrientationPortrait ? NO : YES;
        [self.navigationController setNavigationBarHidden:lHideNavBar animated:YES];
    }
    

    This also has the added benefit for my App in that there is more screen space available in landscape mode. This is useful because the screen in question is used to display PDF files.

    Hope this helps.

    0 讨论(0)
提交回复
热议问题