2015-10-13 19:12:55 z15083415803 阅读数 207

iOS屏幕旋转

首先iPhone中屏幕分为状态栏方向和设备方向

typedef NS_ENUM(NSInteger, UIDeviceOrientation) {
    UIDeviceOrientationUnknown,
    UIDeviceOrientationPortrait,            // Device oriented vertically, home button on the bottom
    UIDeviceOrientationPortraitUpsideDown,  // Device oriented vertically, home button on the top
    UIDeviceOrientationLandscapeLeft,       // Device oriented horizontally, home button on the right
    UIDeviceOrientationLandscapeRight,      // Device oriented horizontally, home button on the left
    UIDeviceOrientationFaceUp,              // Device oriented flat, face up
    UIDeviceOrientationFaceDown             // Device oriented flat, face down
};

typedef NS_ENUM(NSInteger, UIInterfaceOrientation) {
    UIInterfaceOrientationUnknown            = UIDeviceOrientationUnknown,
    UIInterfaceOrientationPortrait           = UIDeviceOrientationPortrait,
    UIInterfaceOrientationPortraitUpsideDown = UIDeviceOrientationPortraitUpsideDown,
    UIInterfaceOrientationLandscapeLeft      = UIDeviceOrientationLandscapeRight,
    UIInterfaceOrientationLandscapeRight     = UIDeviceOrientationLandscapeLeft
};

系统提供两个地方来设置设备的方向,取两个地方的交集是最后的设备所支持的方向

-(NSUInteger)application:(UIApplication *)application supportedInterfaceOrientationsForWindow:(UIWindow *)window;
-(NSUInteger)supportedInterfaceOrientations;

这里需要注意的是返回的时下面的枚举

typedef NS_OPTIONS(NSUInteger, UIInterfaceOrientationMask) {
    UIInterfaceOrientationMaskPortrait = (1 << UIInterfaceOrientationPortrait),
    UIInterfaceOrientationMaskLandscapeLeft = (1 << UIInterfaceOrientationLandscapeLeft),
    UIInterfaceOrientationMaskLandscapeRight = (1 << UIInterfaceOrientationLandscapeRight),
    UIInterfaceOrientationMaskPortraitUpsideDown = (1 << UIInterfaceOrientationPortraitUpsideDown),
    UIInterfaceOrientationMaskLandscape = (UIInterfaceOrientationMaskLandscapeLeft | UIInterfaceOrientationMaskLandscapeRight),
    UIInterfaceOrientationMaskAll = (UIInterfaceOrientationMaskPortrait | UIInterfaceOrientationMaskLandscapeLeft | UIInterfaceOrientationMaskLandscapeRight | UIInterfaceOrientationMaskPortraitUpsideDown),
    UIInterfaceOrientationMaskAllButUpsideDown = (UIInterfaceOrientationMaskPortrait | UIInterfaceOrientationMaskLandscapeLeft | UIInterfaceOrientationMaskLandscapeRight),
};

在转动屏幕的时候会触发下面方法

-(BOOL)shouldAutorotate;

在该方法返回真,自动调用上面的两个方法得到方向。

修改状态栏方向的方法
1、使用私有API setOrientation;
2、修改状态栏的方向,并通过设置View的transform来达到伪旋转的结果,但是设备方向并没有改变
3、主动出发系统支持的方法,就相当于让这个vc在重新出来的时候系统判断所支持的方向的机制重新走一遍。

- (void)awakeSupportInterOrtation:(UIViewController *)showVC completion:(void(^)(void))block
{
    UIViewController *vc = [[UIViewController alloc] init];
    void(^completion)() = ^() {
        [showVC dismissViewControllerAnimated:NO completion:^{
            if (block)
            {
                block();
            }
        }];
    };

    // This check is needed if you need to support iOS version older than 7.0
    BOOL canUseTransitionCoordinator = [showVC respondsToSelector:@selector(transitionCoordinator)];

    if (canUseTransitionCoordinator)
    {
        [showVC presentViewController:vc animated:NO completion:nil];
        [showVC.transitionCoordinator animateAlongsideTransition:nil completion:^(id<UIViewControllerTransitionCoordinatorContext> context) {
            completion();
        }];
    }
    else
    {
        [showVC presentViewController:vc animated:NO completion:completion];
    }
}

-(NSUInteger)supportedInterfaceOrientations
{
        return UIInterfaceOrientationMaskPortrait;
}

-(BOOL)shouldAutorotate
{
    return YES;
}

在需要转为竖屏的时候调用一个方法,在后面两个方法中如上实现,第二个方法中返回的是你最终要转向的方向。

2012-12-03 12:14:37 zzfsuiye 阅读数 53628

转自:http://blog.csdn.net/cococoolwhj/article/details/8208991

概述:

在iOS6之前的版本中,通常使用 shouldAutorotateToInterfaceOrientation 来单独控制某个UIViewController的方向,需要哪个viewController支持旋转,只需要重写shouldAutorotateToInterfaceOrientation方法。

但是iOS 6里屏幕旋转改变了很多,之前的 shouldAutorotateToInterfaceOrientation 被列为 DEPRECATED 方法,查看UIViewController.h文件也可以看到:

  1. // Applications should use supportedInterfaceOrientations and/or shouldAutorotate..  
  2. - (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation NS_DEPRECATED_IOS(2_0, 6_0);  

程序将使用如下2个方法来代替:

  1. - (BOOL)shouldAutorotate;  
  2. - (NSUInteger)supportedInterfaceOrientations;  
除了重写这个2个方法,IOS6里面要旋转还有一些需要注意的地方,下面会细述。另外还有一个硬性条件,需要在Info.plist文件里面添加程序支持的所有方向,可以通过以下2种方式添加

1.



2.



另外要兼容IOS6之前的系统,要保留原来的 shouldAutorotateToInterfaceOrientation 方法,还有那些 willRotateToInterfaceOrientation 等方法。


IOS6自动旋转设置:

IOS6里面,控制某个viewController旋转并不是像IOS5或者IOS4一样在这个viewController里面重写上面那2个方法,而是需要在这个viewController的rootViewController(根视图控制器)里面重写,怎么解释呢?就是最前面的那个viewController,直接跟self.window接触的那个controller,比如以下代码:
  1. UIViewController *viewCtrl = [[UIViewController alloc] init];  
  2. UINavigationController *navCtrl = [[UINavigationController alloc] initWithRootViewController:viewCtrl];  
  3. if ([window respondsToSelector:@selector(setRootViewController:)]) {  
  4.     self.window.rootViewController = navCtrl;  
  5. else {  
  6.     [self.window addSubview:navCtrl.view];  
  7. }  
如果需要设置viewCtrl的旋转,那么不能在UIViewController里面重写shouldAutorotate和supportedInterfaceOrientations方法,而是需要在navCtrl里面设置,又因为UINavigationController是系统控件,所以这里需要新建一个UINavigationController的子navigationController的子类,然后在里面实现shouldAutorotate和supportedInterfaceOrientations方法,比如:
  1. -(NSUInteger)supportedInterfaceOrientations{  
  2.     return UIInterfaceOrientationMaskAllButUpsideDown;  
  3. }  
  4.   
  5. - (BOOL)shouldAutorotate{  
  6.     return YES;  
  7. }  
eg1:如果上面的例子是self.window.rootViewController = viewCtrl,而不是navCtrl,那么上面的那2个控制旋转的方法就应该写在UIViewController里面!

eg2:如果viewCtrl又pushViewController到viewCtrl2,需要设置viewCtrl2的旋转,怎么办呢? 还是在navCtrl里面控制,因为viewCtrl和viewCtrl2的rootViewController都是navCtrl,一般的写法都是
  1. UIViewController *viewCtrl2 = [[UIVewController alloc] init];  
  2. [self.navigationController.navigationController pushViewController:viewCtrl2 animated:YES];  
所以要控制一个UINavigationController push到的所有viewController的旋转,那么就得在navCtrl里面区分是哪个viewController,以便对他们一一控制!同样如果rootViewController是UITabbarController,那么需要在子类化的UITabbarController里面重写那2个方法,然后分别控制!

但是有时候我初始化UINavigationController的时候,并不知道所有我所有需要push到的viewController,那么这里有一个通用的方法,就是让viewController自己来控制自己,首先在navCtrl里面的实现方法改为以下方式:
  1. - (BOOL)shouldAutorotate    
  2. {    
  3.     return self.topViewController.shouldAutorotate;    
  4. }    
  5.     
  6. - (NSUInteger)supportedInterfaceOrientations    
  7. {    
  8.     return self.topViewController.supportedInterfaceOrientations;    
  9. }  
全部调用self.topViewController,就是返回当前呈现出来的viewController里面的设置,然后在viewCtrl、viewCtrl2等等这些viewController里面重写shouldAutorotate和supportedInterfaceOrientations,以方便设置每个viewController的旋转

eg3:如果viewCtrl 是 
presentModalViewController 到 viewCtrl3,那么viewCtrl3的旋转设置就不在navCtrl里面了!如果presentModalViewController的viewController是navController、tabbarController包装过的viewCtrl3,那么就应在新包装的navController、tabbarController里面设置,如果是直接presentModalViewController到viewCtrl3,那么就在viewCtrl3里面设置


IOS5、IOS4自动旋转设置

这个简单很多,没有上面的硬性条件,只需要在需要旋转的viewController里面重写 shouldAutorotateToInterfaceOrientation 方法就行

手动旋转

手动旋转也有2种方式,一种是直接设置 UIDevice 的 orientation,但是这种方式不推荐,上传appStore有被拒的风险:

  1. if ([[UIDevice currentDevice] respondsToSelector:@selector(setOrientation:)]) {  
  2.     [[UIDevice currentDevice] performSelector:@selector(setOrientation:) withObject:(id)UIInterfaceOrientationPortrait];  
  3. }  
第二种是假旋转,并没有改变 UIDevice 的 orientation,而是改变某个view的 transform,利用 CGAffineTransformMakeRotation 来达到目的,比如:
  1. self.view.transform = CGAffineTransformMakeRotation(M_PI/2)  

下面讲解采用第二种方式的各版本手动旋转:

思想是首先设置 statusBarOrientation,然后再改变某个view的方向跟 statusBarOrientation 一致!


IOS6手动旋转:

1. 那既然是旋转,最少也得有2个方向,那么还是少不了上面说的那个硬性条件,先在plist里面设置好所有可能需要旋转的方向。既然是手动旋转,那么就要关闭自动旋转:

  1. - (BOOL)shouldAutorotate{  
  2.         return NO;  
  3. }  
2.手动触发某个按钮,调用方法,这个方法的实现如下:
  1. [[UIApplication sharedApplication] setStatusBarOrientation:UIInterfaceOrientationLandscapeRight];  
  2. self.view.transform = CGAffineTransformMakeRotation(M_PI/2);  
  3. self.view.bounds = CGRectMake(0, 0, kScreenHeight, 320);  
注意:
1. 只需要改变self.view.transform,那么self.view的所有subview都会跟着自动变;其次因为方向变了,所以self.view的大小需要重新设置,不要使用self.view.frame,而是用bounds。
2. 如果shouldAutorotate 返回YES的话,下面设置setStatusBarOrientation 是不管用的!setStatusBarOrientation只有在shouldAutorotate 返回NO的情况下才管用!

IOS5、IOS4手动旋转:

1.在需要手动旋转的viewController里的 shouldAutorotateToInterfaceOrientation 方法设置 interfaceOrientation == [UIApplicationsharedApplication].statusBarOrientation
  1. - (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation{  
  2.     return (interfaceOrientation == [UIApplication sharedApplication].statusBarOrientation);  
  3. }  
2.手动触发某个按钮,调用方法,这个方法的实现如下:
  1. [[UIApplication sharedApplication] setStatusBarOrientation:UIInterfaceOrientationLandscapeRight];  
  2. self.view.transform = CGAffineTransformMakeRotation(M_PI/2);  
  3. self.view.bounds = CGRectMake(0, 0, kScreenHeight, 320);  
注意:只需要改变self.view.transform,那么self.view的所有subview都会跟着自动变;其次因为方向变了,所以self.view的大小需要重新设置,不要使用self.view.frame,而是用bounds。


经验分享:

1.IOS6里面,如果一个项目里面需要各种旋转支持,有自动,有手动,那么我们可以新建2个navController或者tabbarController的子类,一个是不旋转,一个旋转,那么所有需要旋转的UINavigationController都可以用这个子类来代替!包括我们可以定制短信呀、邮件呀的旋转!
2.supportedInterfaceOrientations 方法一般是写UIInterfaceOrientationMask方向,但是如果程序要兼容4.3以下的SDK(4.3以下的SDK必须是4.5以下的Xcode,不支持IOS6),那么在用4.5以下的Xcode编译的时候通不过!所以可以用statusBarOrientation代替或者直接写死数字!
  1. -(NSUInteger)supportedInterfaceOrientations{  
  2.     return [UIApplication sharedApplication].statusBarOrientation;  
  3. }  
3.一般都不建议在程序里面直接调用 UIDeviceOrientation 的方向,而是用 UIInterfaceOrientation,他们之间是不同的!
  1. UIInterfaceOrientationLandscapeLeft = UIDeviceOrientationLandscapeRight,  
  2. UIInterfaceOrientationLandscapeRight = UIDeviceOrientationLandscapeLeft  
看到吗,左右是反的!Xcode图形化设置方向也是以 UIInterfaceOrientation 为准,就是home按键所在的方向

参考:
http://blog.csdn.net/totogogo/article/details/8002173
http://stackoverflow.com/questions/13200220/how-to-change-keyboard-orientation-in-ios6
http://blog.csdn.net/yiyaaixuexi/article/details/8035014
2016-04-21 18:04:15 u012884714 阅读数 2061

闲来无事研究了一下屏幕旋转的问题

说到屏幕旋转问题不得先说一句,做项目尽量还是优先使用storyboard、IB因为有了autolayout的约束布局为基础再去做屏幕旋转需要的视图布局适配就相对来说简单容易很多。

好了,闲话不多说,开始今天要说的问题。

首先,想要实现单个屏幕旋转有两个重要的方法需要在viewcontroller里重写

// New Autorotation support.

//是否支持自动旋转

- (BOOL)shouldAutorotateNS_AVAILABLE_IOS(6_0)__TVOS_PROHIBITED;

//支持自动旋转的模式

- (UIInterfaceOrientationMask)supportedInterfaceOrientationsNS_AVAILABLE_IOS(6_0)__TVOS_PROHIBITED;


使用模式如下:

//支持设备自动旋转

- (BOOL)shouldAutorotate{

    returnYES;

}

//支持横竖屏显示

- (UIInterfaceOrientationMask)supportedInterfaceOrientations{

    returnUIInterfaceOrientationMaskAll; 

}

如果你以为这样就会实现屏幕的旋转,那么你还是too young.


如果你想要在项目中使用屏幕旋转,需要注意一下几点

1、首先确保总开关打开,要不然有可能项目崩溃。 例如你想让某个视图支持横屏,然后你这样写道

- (UIInterfaceOrientationMask)supportedInterfaceOrientations{

    returnUIInterfaceOrientationMaskLandscape;    

}

这样就崩溃了,因为你项目根本就不支持横屏,言归正传,首先打开总开关(项目默认是打开的)
target -> General -> device oriention

打开开关你的项目就具备了屏幕旋转的权限。
2、当你做了第一步后发现确实可以屏幕确实可以旋转了,但是好像屏幕旋转不受你控制,你需要的仅仅是某个或某几个页面能旋转,但是现在全都能旋转,这怎么办呢,现在我们需要了解一下旋转的机制。
如果你想要支持屏幕旋转的controllerrootcontroller 那这样用,没毛病,但是一般情况下不会这样。
如果你想要controller支持旋转,那么你需要保证它的上一级也支持相应的旋转,通常情况下我们的controller都是在NavController 的栈里边,所以一般的我们的controller的上一级都是NavController,所以我们要设置NavController屏幕旋转

//支持设备自动旋转

- (BOOL)shouldAutorotate{

    return YES;

}

//支持横竖屏显示

- (UIInterfaceOrientationMask)supportedInterfaceOrientations{

    return UIInterfaceOrientationMaskAll; 

}


但是问题来了,有这么一种场景,NavController栈里边有好几个controller,可能你只需要某一个controller支持,而其他的不支持,最好的办法是获取栈最顶端的controller对旋转的支持状态,修改后如下

//支持横竖屏

- (BOOL)shouldAutorotate

{

    return [self.viewControllers.lastObjectshouldAutorotate];

}


- (UIInterfaceOrientationMask)supportedInterfaceOrientations

{

    return [self.viewControllers.lastObjectsupportedInterfaceOrientations];

}


由于controller默认是开启的状态,所以每一个不需要旋转的屏幕的controller都要写上这么一句

//屏幕旋转

//支持设备自动旋转

- (BOOL)shouldAutorotate{

    returnNO;

}

是不是麻烦?简单一点都办法就是创建一个controller的基类BaseViewController每个controller都继承BaseViewController ,在BaseViewController中重写- (BOOL)shouldAutorotate 方法默认关闭,这样做的坏处就是增加了项目代码的耦合度,因为BaseViewController是比较基础的,稍有改动就可能会对项目有很大的影响,利弊自己权衡。


到这里你可能会想那项目中是以TabbarController 为Root controller的话怎么办?思考一下,其实TabbarController即为NavController 的上一级,根据NavController的逻辑我们可以写出下面的代码,一举解决这个问题。

//支持横竖屏

- (BOOL)shouldAutorotate

{

    returnself.selectedViewController.shouldAutorotate;

}


- (UIInterfaceOrientationMask)supportedInterfaceOrientations

{

    return [self.selectedViewControllersupportedInterfaceOrientations];

}


说了这么多其实最主要的就是想清楚项目中controller的层层之间的关系,然后再去做相应的设置,最终你会实现你想要的。

3、最后附上,进入某controller就让它旋转到某个方向的利器,经本人验证,可用,客官放心用

   

 NSNumber *value = [NSNumbernumberWithInt:UIInterfaceOrientationLandscapeRight];

    [[UIDevicecurrentDevice]setValue:valueforKey:@"orientation"];


暂时就这么多内容,以后有新的内容会继续更新。


有问题欢迎指正以及互相探讨 -- LC.West




2017-03-13 11:55:58 yao_shaobin 阅读数 709

1、手动旋转屏幕函数

- (void)setOrientation: (UIInterfaceOrientation)orientation {
    if([[UIDevice currentDevice] respondsToSelector:@selector(setOrientation:)]) {
        SEL selector = NSSelectorFromString(@"setOrientation:");
        NSInvocation*invocation = [NSInvocationinvocationWithMethodSignature:[UIDevice instanceMethodSignatureForSelector:selector]];
        [invocation setSelector:selector];
        [invocation setTarget: [UIDevice currentDevice]];
        intval = orientation;
        [invocation setArgument:&val atIndex:2];
        [invocation invoke];
    }
}

在AppDelegate.h中定义一个变量:

BOOL allowRotation;

再定义一个宏:

#define ApplicationDelegate ((AppDelegate *)[UIApplication sharedApplication].delegate)

然后在AppDelegate.m文件中 实现允许屏幕的方向函数

-(UIInterfaceOrientationMask)application:(UIApplication *)application supportedInterfaceOrientationsForWindow:(UIWindow *)window {
    if(self.allowRotation) {
        returnUIInterfaceOrientationMaskAll;
    }
    returnUIInterfaceOrientationMaskPortrait;
}

2、自动旋转屏幕

1)在控制器中实现允许屏幕旋转的方法
- (BOOL)shouldAutorotate{      
returnApplicationDelegate.allowRotation;
}
2)当想要旋转屏幕的时候,就去修改ApplicationDelegate.allowRotation的值,默认是NO,是不支持旋转的,所以满足我们的需求当我们从首页进入播放界面的时候在页面将要出现的时候 设置为YES在页面将要消失的时候 设置为NO:
- (void)viewDidDisappear:(BOOL)animated{
    [superviewDidDisappear:animated];
    ApplicationDelegate.allowRotation==NO;
}

- (void)viewDidAppear:(BOOL)animated{
    [superviewDidAppear:animated];
    ApplicationDelegate.allowRotation==YES;
}
3)控制器下添加一个通知,用来监听手机方向是否改变
[[NSNotificationCenterdefaultCenter] addObserver:self  selector:@selector(changeFrames) name:UIDeviceOrientationDidChangeNotification   object:nil];
2013-07-03 23:08:23 ran0809 阅读数 1973

在IOS6以前,设置转屏需要用到方法

- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)x

在6以后,取代它的是

- (BOOL)shouldAutorotate

- (NSUInteger)supportedInterfaceOrientations


在论坛上看到个问题,如何用按钮控制自动转屏

可以在相应的Controller中加入一个属性,一个BOOL型的变量autorotation


应用的界面是


然后再初始化的时候初始为YES,在自动转屏方法中return这个变量即可

- (void)viewDidLoad
{
    [super viewDidLoad];

    self.autorotation = YES;
}

- (BOOL)shouldAutorotate
{
    return self.autorotation;
}

- (NSUInteger)supportedInterfaceOrientations
{
    return UIInterfaceOrientationMaskAll;
}

这个项目允许的转屏模式主要由项目信息中的设置决定的



然后开始实现按钮的方法

- (IBAction)changeFlag:(id)sender {
    if (_autorotation) {
        self.autorotation = NO;
        self.textLabel.text = @"Autorotation: No";
    } else {
        self.autorotation = YES;
        self.textLabel.text = @"Autorotation: Yes";
    }
}

这样就可以在点击按钮时更改是否允许转屏,以及Label中的text了。


另外,在IOS6以后自动缩放的方框默认不显示了,是因为加入了autolayout且默认为勾选状态的

取消勾选后Autosizing就显示出来了



iOS屏幕旋转

阅读数 157

没有更多推荐了,返回首页