首页 > 代码库 > iOS手动控制界面旋转

iOS手动控制界面旋转

      条条大道通罗马,解决同一个问题的手段也是多种多样的。对于《iOS 6及以上控制个别视图旋转案例》中提到的案例,我们是利用系统自带的旋转机制来解决问题的。同样地,我们也可以自己coding解决问题,且最终效果同系统的旋转动画效果是一模一样的。废话不多说,下面来大概讲解一下。


       手动控制界面旋转的核心思路就是利用UIView的transform属性,旋转App的根视图。何为根视图?如果你的App的window.rootViewController是UINavigationController,那么根视图就是navigationController.view。为了旋转的效果和系统的一致,我们还需要为它添加一个UIView动画。


       接着我们来具体操作一下,首先,建立一个测试工程,工程结构如下图。测试工程的根视图控制器是一个UINavigationController,在这个UINavigationController的栈中有视图控制器a(FirstViewController的一个实例)和控制器b(SecondViewController的一个实例),控制器b通过在控制器a中点击按钮push进入。

在SecondViewController.h文件中添加代码,如下

#import <UIKit/UIKit.h>

@interface SecondViewController : UIViewController

@property (nonatomic,assign) BOOL isLandscape;

- (IBAction)rotateBtnClicked:(id)sender;

@end
在SecondViewController.m文件中添加代码,如下

#import "SecondViewController.h"

@implementation SecondViewController

#pragma mark - view life cycle
- (void)viewDidLoad
{
    [super viewDidLoad];
    self.title = @"Second";
    self.isLandscape = NO;
    [[NSNotificationCenter defaultCenter] addObserver:self
                                             selector:@selector(changeFrames:)
                                                 name:UIDeviceOrientationDidChangeNotification
                                               object:nil];
}

- (void)didReceiveMemoryWarning
{
    [super didReceiveMemoryWarning];
    // Dispose of any resources that can be recreated.
}


#pragma mark - methods
- (void)rotateToLandscapeLeft
{
    NSTimeInterval duration = [[UIApplication sharedApplication] statusBarOrientationAnimationDuration];
    [UIView animateWithDuration:duration animations:^{
        [[UIApplication sharedApplication] setStatusBarOrientation:UIInterfaceOrientationLandscapeLeft];
        self.navigationController.view.transform = CGAffineTransformMakeRotation(- M_PI/2);
        self.navigationController.view.bounds = CGRectMake(0, 0, [self screenHeight], 320);
    } completion:^(BOOL finished) {
        self.isLandscape = YES;
    }];
}

- (void)rotateToLandscapeRight
{
    NSTimeInterval duration = [[UIApplication sharedApplication] statusBarOrientationAnimationDuration];
    [UIView animateWithDuration:duration animations:^{
        [[UIApplication sharedApplication] setStatusBarOrientation:UIInterfaceOrientationLandscapeRight];
        self.navigationController.view.transform = CGAffineTransformMakeRotation(M_PI/2);
        self.navigationController.view.bounds = CGRectMake(0, 0, [self screenHeight], 320);
    } completion:^(BOOL finished) {
        self.isLandscape = YES;
    }];
}

- (void)rotateToPortrait
{
    NSTimeInterval duration = [[UIApplication sharedApplication] statusBarOrientationAnimationDuration];
    [UIView animateWithDuration:duration animations:^{
        [[UIApplication sharedApplication] setStatusBarOrientation:UIInterfaceOrientationPortrait];
        self.navigationController.view.transform = CGAffineTransformMakeRotation(0);
        self.navigationController.view.bounds = CGRectMake(0, 0, 320, [self screenHeight]);
    } completion:^(BOOL finished) {
        self.isLandscape = NO;
    }];
}

- (CGFloat)screenHeight
{
    if (iPhone5) {
        return 568.0;
    }
    else {
        return 480.0;
    }
}


#pragma mark - actions
- (IBAction)rotateBtnClicked:(id)sender
{
    if (!self.isLandscape) {
        [self rotateToLandscapeRight];
    }
    else {
        [self rotateToPortrait];
    }
}


#pragma mark - handle notification
- (void)changeFrames:(NSNotification *)notification
{
    UIDeviceOrientation deviceOrientation = [[UIDevice currentDevice] orientation];
    if (deviceOrientation == UIDeviceOrientationLandscapeRight) {
        [self rotateToLandscapeLeft];
    }
    else if (deviceOrientation == UIDeviceOrientationLandscapeLeft) {
        [self rotateToLandscapeRight];
    }
    else if (deviceOrientation == UIDeviceOrientationPortrait){
        [self rotateToPortrait];
    }
}

@end
其中,rotateToLandscapeLeft/rotateToLandscapeRight/rotateToPortrait是视图旋转的核心方法。我们在viewDidLoad方法中注册了一个事件通知,当设备的物理旋转方向发生改变时,我们将调用方法changeFrames:来对视图进行相应的旋转,也可以通过点击某个按钮来旋转界面。可以看到,测试项目中还有一个UINavigationController的类别。类别中添加

#import "UINavigationController+Ext.h"

@implementation UINavigationController (Ext)

- (BOOL)shouldAutorotate
{
    return NO;
}

@end

为什么要添加UINavigationController类别?因为旋转的时候我们需要同时去旋转statusBar(状态栏),要旋转statusBar必须在shouldAutorotate方法中返回NO。


       运行测试项目并旋转设备,能看到我们已经成功手动控制界面旋转,且旋转的动画效果与系统默认的旋转效果是一模一样的。和之前那篇文章中提到的解决方法相比,有了更高的自由度,开发者能够随性控制界面的旋转。

     测试工程:下载