今天Boss跟我说,要我准备去适配ios6,于是我去鸟哥的博客看了下,然后有请教了别人,但是没达到效果,一直不知道问题在哪,后来看文档,google才发现问题关键所在。现在大致说下:
在ios6.0中shouldAutorotateToInterfaceOrientation:不再起作用了,ios使用shouldAutorotate和supportedInterfaceOrientations来控制旋转效果。
我试了几次,发现ios6.0真正起作用的旋转有三种:
1.在info.plist这里设置来控制,还可以在appDelegate的这个函数里面设置- (NSUInteger)application:(UIApplication *)application supportedInterfaceOrientationsForWindow:(UIWindow *)window,在这个里面设置了,那么info.plist里面设置的就会失效;
2.直接把视图加在window上,(如:[self.window addSubview:vc.view])这种方法可以脱离info.plist的控制,shouldAutorotate和supportedInterfaceOrientations来控制方向;
3.使用rootViewController(如:self.window.rootViewController = rootVC) , 添加shouldAutorotate方法,但是受info.plist的限制。
相信大多数人都是使用的第三种,但是这个要特别注意:当window的rootViewController设置为UINavigationController的时候,你需要自定义UINavigationController,因为你需要在这里面,写shouldAutorotate和supportedInterfaceOrientations方法。如果你不这样做,那么如果你有的界面需要转屏的话,可能会有问题。
上面的这些方法都限制于顶层视图控制,这也是ios6与之前的ios版本不同的地方,如果要想在子视图中添加旋转效果,则需要在顶层视图中开启shouldAutorotate方法,在子视图控制器中就可以使用supportedInterfaceOrientations方法。
一些示例代码:
首先
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
self.window = [[[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]] autorelease];
// Override point for customization after application launch.
RootViewController *vc = [[RootViewController alloc] init];
self.window.rootViewController = vc;
[vc release];
[self.window makeKeyAndVisible];
// 直接添加视图来控制
// RootViewController *vc = [[RootViewController alloc] init];
// [self.window addSubview:vc.view];
return YES;
}
然后在顶层视图上开启旋转和控制
//在RootViewController中开启旋转
- (BOOL)shouldAutorotate
{
return YES;
}
-(NSUInteger)supportedInterfaceOrientations
{
return UIInterfaceOrientationMaskLandscape;
}
最后在子视图控制器中直接使用
//- (BOOL)shouldAutorotate
//{
// return YES;
//}
//在FirstViewController中直接使用
-(NSUInteger)supportedInterfaceOrientations
{
return UIInterfaceOrientationMaskPortrait;
}
总结:
在ios4 and 5 , 都是由具体的ViewController来决定对应的view的orientation设置,但是在ios6,则是由top-most controller,即顶层视图控制器来决定view的orientation设置。
在iOS 4 and 5,都是由具体的view controller来决定对应的view的orientation设置。而在iOS 6,则是由top-most controller来决定view的orientation设置。
就像我们刚才说的那个:如果你的app的window的rootViewController是UINavigationController的nav,那么在nav里的stack依次是:main view ->sub view ->sub sub view, 并且在main view里面可以进入下一个视图model view,是present进去的, 那么在ios4 and 5 ,如果你要这些view只支持横屏orientation,那么你只需要在main view, sub view ,sub sub view ,model view的控制器里面,添加这个函数即可:
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
{
return UIInterfaceOrientationIsLandscape(orientation);
}
但是对于ios6来说,由于是top-most controller来设置方向的,因此如果你单独的在main view ,sub view,sub sub view里面添加下面的代码是没有任何效果的,而应该是在navigationController里添加下列代码,这也是因为我先为什么说,需要你自定义navigationController的原因。而modal view 并不在navigaitonController的控制之下,所以你需要在model view里也添加下面的代码:
- (BOOL)shouldAutorotate
{
return YES;
}
-(NSUInteger)supportedInterfaceOrientations{
return UIInterfaceOrientationMaskLandscape;
}
注意:
*你需要自定义一个UINavigationController的子类,这样才可以添加上述代码。
* 和UINavigationController类似,tab controller里的各个view的orientation设置应该放在tab controller里
对于 ios6的top-most controller决定orientation设置,导致这样一个问题:在 top-most controller里的views无法拥有不相同的orientation设置。例如:在nav controller里,你有main view, sub view and sub sub view,前2个都只能是竖屏,而sub sub view是用来播放视频的,可以横竖屏。那么在ios 4 and 5里可以通过在main view and sub view的shouldAutorotateToInterfaceOrientation里设置只能竖屏,而在sub sub view的shouldAutorotateToInterfaceOrientation设置横竖屏即可。而在ios 6里则无法实现这种效果,因为在main view, sub view and sub sub view的orientation设置是无效的,只能够在nav controller里设置。那么你可能想着用下列代码在nav controller里控制哪个view竖屏,哪个view横屏
-(NSUInteger)supportedInterfaceOrientations{
if([[self topViewController] isKindOfClass:[SubSubView class]])
return UIInterfaceOrientationMaskAllButUpsideDown;
else
return UIInterfaceOrientationMaskPortrait;
}
是的,这样可以使得在main view and sub view里无法横屏,而sub sub view横竖屏都行。但问题来了,如果在sub sub view时横屏,然后back to sub view,那么sub view是横屏显示的!目前想到的解决方法只能是把sub sub view脱离nav controller,以modal view方式来显示。这样就可以在modal view里设置横竖屏,而在nav controller里设置只竖屏。
* 说了那么多,其实如果你的app的所有view的orientation的设置是统一的,那么你可以简单的在plist file里设置即可,不用添加上面的代码。而如果你添加了上面的代码,就会覆盖plist里orientation的设置。
* in iOS 6, 当view controller present时,不会call willRotateToInterfaceOrientation:duration:, willAnimateRotationToInterfaceOrientation:duration:, and didRotateFromInterfaceOrientation: methods,只有在发生rotate的时候才会call
以上资料的参考了别人的博文和自己在适配ios6转屏的一些心得
感谢Tomson Xu
1.在info.plist这里设置来控制,还可以在appDelegate的这个函数里面设置- (NSUInteger)application:(UIApplication *)application supportedInterfaceOrientationsForWindow:(UIWindow *)window,在这个里面设置了,那么info.plist里面设置的就会失效;
2.直接把视图加在window上,(如:[self.window addSubview:vc.view])这种方法可以脱离info.plist的控制,
shouldAutorotate和supportedInterfaceOrientations来控制方向;
3.使用rootViewController(如:self.window.rootViewController = rootVC) , 添加shouldAutorotate方法,但是受info.plist的限制。
上面的这些方法都限制于顶层视图控制,这也是ios6与之前的ios版本不同的地方,如果要想在子视图中添加旋转效果,则需要在顶层视图中开启shouldAutorotate方法,在子视图控制器中就可以使用supportedInterfaceOrientations方法。
一些示例代码:
首先
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
self.window = [[[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]] autorelease];
// Override point for customization after application launch.
RootViewController *vc = [[RootViewController alloc] init];
self.window.rootViewController = vc;
[vc release];
[self.window makeKeyAndVisible];
// 直接添加视图来控制
// RootViewController *vc = [[RootViewController alloc] init];
// [self.window addSubview:vc.view];
return YES;
}
然后在顶层视图上开启旋转和控制
//在RootViewController中开启旋转
- (BOOL)shouldAutorotate
{
return YES;
}
-(NSUInteger)supportedInterfaceOrientations
{
return UIInterfaceOrientationMaskLandscape;
}
最后在子视图控制器中直接使用
//- (BOOL)shouldAutorotate
//{
// return YES;
//}
//在FirstViewController中直接使用
-(NSUInteger)supportedInterfaceOrientations
{
return UIInterfaceOrientationMaskPortrait;
}
总结:
在ios4 and 5 , 都是由具体的ViewController来决定对应的view的orientation设置,但是在ios6,则是由top-most controller,即顶层视图控制器来决定view的orientation设置。
在iOS 4 and 5,都是由具体的view controller来决定对应的view的orientation设置。而在iOS 6,则是由top-most controller来决定view的orientation设置。
就像我们刚才说的那个:如果你的app的window的rootViewController是UINavigationController的nav,那么在nav里的stack依次是:main view ->sub view ->sub sub view, 并且在main view里面可以进入下一个视图model view,是present进去的, 那么在ios4 and 5 ,如果你要这些view只支持横屏orientation,那么你只需要在main view, sub view ,sub sub view ,model view的控制器里面,添加这个函数即可:
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
{
return UIInterfaceOrientationIsLandscape(orientation);
}
但是对于ios6来说,由于是top-most controller来设置方向的,因此如果你单独的在main view ,sub view,sub sub view里面添加下面的代码是没有任何效果的,而应该是在navigationController里添加下列代码,这也是因为我先为什么说,需要你自定义navigationController的原因。而modal view 并不在navigaitonController的控制之下,所以你需要在model view里也添加下面的代码:
- (BOOL)shouldAutorotate
{
return YES;
}
-(NSUInteger)supportedInterfaceOrientations{
return UIInterfaceOrientationMaskLandscape;
}
注意:
*你需要自定义一个UINavigationController的子类,这样才可以添加上述代码。
* 和UINavigationController类似,tab controller里的各个view的orientation设置应该放在tab controller里
对于 ios6的top-most controller决定orientation设置,导致这样一个问题:在 top-most controller里的views无法拥有不相同的orientation设置。例如:在nav controller里,你有main view, sub view and sub sub view,前2个都只能是竖屏,而sub sub view是用来播放视频的,可以横竖屏。那么在ios 4 and 5里可以通过在main view and sub view的shouldAutorotateToInterfaceOrientation里设置只能竖屏,而在sub sub view的shouldAutorotateToInterfaceOrientation设置横竖屏即可。而在ios 6里则无法实现这种效果,因为在main view, sub view and sub sub view的orientation设置是无效的,只能够在nav controller里设置。那么你可能想着用下列代码在nav controller里控制哪个view竖屏,哪个view横屏
-(NSUInteger)supportedInterfaceOrientations{
if([[self topViewController] isKindOfClass:[SubSubView class]])
return UIInterfaceOrientationMaskAllButUpsideDown;
else
return UIInterfaceOrientationMaskPortrait;
}
感谢Tomson Xu