http://www.jianshu.com/p/650ba0ff626b
很多时候,项目中都有这样的需求:APP中以竖屏为主,个别界面会要求横屏显示,或者要根据用户的手机朝向自动切换横竖屏;下面就来详细讲解,在项目中怎么使用代码来控制APP的界面转换.
首先,要想APP支持多个方向,需要在工程进行设置支持的朝向:
在General-->Deployment Info-->Device Orientation
中进行设置
这样,就可以在项目中使用代码来控制页面的朝向了,在这之前,需要知道控制视图是否能够自动旋转,以及支持的朝向,是通过哪些方法来控制的?
其实,主要使用的是下面三个方法:
/ New Autorotation support.
//是否自动旋转,返回YES可以自动旋转
- (BOOL)shouldAutorotate NS_AVAILABLE_IOS(6_0) __TVOS_PROHIBITED;
//返回支持的方向
- (UIInterfaceOrientationMask)supportedInterfaceOrientations NS_AVAILABLE_IOS(6_0) __TVOS_PROHIBITED;
// Returns interface orientation masks.
//这个是返回优先方向
- (UIInterfaceOrientation)preferredInterfaceOrientationForPresentation NS_AVAILABLE_IOS(6_0) __TVOS_PROHIBITED;
- (BOOL)shouldAutorotate{
return NO;
}
那么,在整个项目中,无论你如何设置,都不会有自动旋转屏幕的效果.
这种情况最简单,直接在控制器中重写上面的方法,设置是否支持自动旋转,以及支持的方向即可:
- (BOOL)shouldAutorotate{
return YES;
}
#if __IPHONE_OS_VERSION_MAX_ALLOWED < __IPHONE_9_0
- (NSUInteger)supportedInterfaceOrientations
#else
- (UIInterfaceOrientationMask)supportedInterfaceOrientations
#endif
{
return UIInterfaceOrientationMaskAll;
}
像上面我设置为支持自动旋转,支持所有的朝向;但是这种情况很少见...
这种情况比较常见,也很简单;一般使用的导航的时候,都不会去直接使用系统的UINavigationController,而会定义一个他的子类,做一些公共的设置:
#import
@interface BaseNaviViewController : UINavigationController
@end
然后在导航的viewController里面重写上面的三个方法,这里也有两种方式来控制:
这种方式,主要是用在,当push到某个视图控制器时,要求他能够支持自动旋转,或者强制转为横屏;这里主要用到了导航的viewControllers
属性,这是一个数组,数组的最后一个元素,就是最后push进去的viewController,所以,实现代码如下:
-(BOOL)shouldAutorotate
{
return [[self.viewControllers lastObject] shouldAutorotate];
}
#if __IPHONE_OS_VERSION_MAX_ALLOWED < __IPHONE_9_0
- (NSUInteger)supportedInterfaceOrientations
#else
- (UIInterfaceOrientationMask)supportedInterfaceOrientations
#endif
{
return [[self.viewControllers lastObject] supportedInterfaceOrientations];
}
- (UIInterfaceOrientation)preferredInterfaceOrientationForPresentation {
return [[self.viewControllers lastObject] preferredInterfaceOrientationForPresentation];
}
到这里还没有结束,这里只是获取到了最后一个push的viewController,然后用它去调用了相应的方法,具体的方法实现,还是需要在哪个viewController里进行设置的,也就是在需要特殊设置的viewController里重写上面的方法:
-(BOOL)shouldAutorotate
{
return YES;
}
#if __IPHONE_OS_VERSION_MAX_ALLOWED < __IPHONE_9_0
- (NSUInteger)supportedInterfaceOrientations
#else
- (UIInterfaceOrientationMask)supportedInterfaceOrientations
#endif
{
return UIInterfaceOrientationMaskPortraitUpsideDown;
}
- (UIInterfaceOrientation)preferredInterfaceOrientationForPresentation {
return UIInterfaceOrientationPortraitUpsideDown;
}
其实这样也就是告诉跟视图控制器,这个界面我要特殊设置一下;
第一种方法是,只要push进去一个视图控制器,都可以进行相应的设置,而这种方法是只针对特定的控制器进行设置,例如这里,我需要把SecondViewController
单独设置为支持横屏,只需要将第一种方法中的导航里的相应代码做如下修改:
-(BOOL)shouldAutorotate
{
if ([[self.viewControllers lastObject]isKindOfClass:[SecondViewController class]]) {
return YES;
}
return NO;
}
#if __IPHONE_OS_VERSION_MAX_ALLOWED < __IPHONE_9_0
- (NSUInteger)supportedInterfaceOrientations
#else
- (UIInterfaceOrientationMask)supportedInterfaceOrientations
#endif
{
if ([[self.viewControllers lastObject]isKindOfClass:[SecondViewController class]]) {
return UIInterfaceOrientationMaskLandscapeLeft;
}
return UIInterfaceOrientationMaskPortrait;
}
- (UIInterfaceOrientation)preferredInterfaceOrientationForPresentation {
if ([[self.viewControllers lastObject]isKindOfClass:[SecondViewController class]]) {
return UIInterfaceOrientationLandscapeLeft;
}
return UIInterfaceOrientationPortrait;
}
这样的好处是,可以控制指定的视图控制器,也不用在指定的视图控制器内再重写上面的方法;
这种情况比较常见,项目的跟视图控制器是一个UITabBarController
,这种情况的实现相对来说要复杂一些,但是,明白了原理,总是有方法来实现的.归根结底,也就是告诉跟视图,我这个界面需要支持旋转了;
由于,在UITabBarController
里直接获取到UIViewController
比较困难,所以这里我采用通知的形式,来获取相应的设置状态;
首先,设置一个全局的BOOL值,用于接收通知发送的参数:
#import
@interface BaseTabBar : UITabBarController
{
BOOL shouldAutorotate;
}
@end
然后注册一个通知:
//注册旋转屏幕的通知
[[NSNotificationCenter defaultCenter]addObserver:self selector:@selector(autorotateInterface:) name:@"InterfaceOrientationNotification" object:nil];
实现通知方法:
-(void)autorotateInterface:(NSNotification *)notifition
{
shouldAutorotate = [notifition.object boolValue];
}
然后在重写的方法里加入判断:
/**
*
* @return 是否支持旋转
*/
-(BOOL)shouldAutorotate
{
NSLog(@"======%d",shouldAutorotate);
if (!shouldAutorotate) {
return NO;
}else{
return YES;
}
}
/**
* 适配旋转的类型
*
* @return 类型
*/
-(UIInterfaceOrientationMask)supportedInterfaceOrientations
{
if (!shouldAutorotate) {
return UIInterfaceOrientationMaskPortrait;
}
return UIInterfaceOrientationMaskAllButUpsideDown;
}
这里我直接将支持的方向写死了,只是判断了一下是否支持自动旋转屏幕,如果需要将支持的方向传过来,可以修改通知携带的参数;
最后在需要自动转屏的控制器内发送通知:
[[NSNotificationCenter defaultCenter] postNotificationName:@"InterfaceOrientationNotification" object:@"YES"];
到此,对于控制屏幕的旋转及方向,基本就介绍完了,如果有不足或者不对的地方,还请指正;如果你有更好的方式实现同样的效果,还请不吝赐教...
//强制旋转屏幕
- (void)orientationToPortrait:(UIInterfaceOrientation)orientation {
SEL selector = NSSelectorFromString(@"setOrientation:");
NSInvocation *invocation = [NSInvocation invocationWithMethodSignature:[UIDevice instanceMethodSignatureForSelector:selector]];
[invocation setSelector:selector];
[invocation setTarget:[UIDevice currentDevice]];
int val = orientation;
[invocation setArgument:&val atIndex:2];//前两个参数已被target和selector占用
[invocation invoke];
}
使用的时候,只需要把你需要旋转的方向传过去即可!
有一点需要注意:从A进入B的时候,把B强制转换成横屏,返回的时候,需要在A出现的时候再转换为原来的方向,不然会有问题;个人建议可以在B的viewWillAppear调用这个方法,转换屏幕(例如转换为横屏),然后在A的viewWillAppear中转换回来;