在利用iOS 6的新自动布局功能同时仍能与iOS早期版本上的旧设备兼容的最佳方式是什么?
在利用iOS 6的新自动布局功能同时仍能与iOS早期版本上的旧设备兼容的最佳方式是什么?
Answers:
可以在每个.storyboard或.xib文件上启用或禁用自动布局。只需选择特定文件,然后使用Xcode中的文件检查器修改“使用自动布局”属性即可:
在将部署目标设置为6.0之前的iOS版本中使用启用了自动布局的界面文件会导致编译错误,例如:
MainStoryboard.storyboard中的错误:3:iOS 6.0之前的版本上的自动版式
在项目中使用自动布局并仍保持与iOS4-5兼容性的一种选择是创建两个目标:一个用于部署目标iOS 6.0,一个用于早期iOS版本,例如:
您还可以为每个故事板和XIB文件创建两个版本,并使用对6.0目标启用的自动布局,以及对旧目标启用的自动布局,例如:
然后,您将MainStoryBoardAutoSize添加到iOS6目标的Build阶段,并将另一个文件添加到iOS4目标。您可以在此处了解有关使用多个目标的更多信息。
编辑:正如marchinram的答案所指出的,如果您从代码加载情节提要文件,并且不使用Xcode中的“主情节提要”设置来设置初始情节提要,则可以使用单个目标。
对我来说,维护多个目标和接口文件的复杂性增加的成本似乎超过了使用自动布局的好处。除了一些特殊情况,如果需要iOS4-5兼容性,最好只使用普通的旧自动调整大小(或代码中的layoutSubViews)。
您真的需要两个目标吗?我像这样工作,我有2个故事板,如ImreKelényi所说,一个启用了自动布局,另一个没有启用,然后在应用程序委托中,我只是检查他们使用的是哪个版本,然后选择正确的故事板:
#import "AppDelegate.h"
#define SYSTEM_VERSION_GREATER_THAN_OR_EQUAL_TO(v) ([[[UIDevice currentDevice] systemVersion] compare:(v) options:NSNumericSearch] != NSOrderedAscending)
@interface AppDelegate ()
@property (strong, nonatomic) UIViewController *initialViewController;
@end
@implementation AppDelegate
@synthesize window = _window;
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
UIStoryboard *mainStoryboard = nil;
if (SYSTEM_VERSION_GREATER_THAN_OR_EQUAL_TO(@"6.0")) {
mainStoryboard = [UIStoryboard storyboardWithName:@"iPhone_iOS6" bundle:nil];
} else {
mainStoryboard = [UIStoryboard storyboardWithName:@"iPhone_iOS5" bundle:nil];
}
self.initialViewController = [mainStoryboard instantiateInitialViewController];
self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
self.window.rootViewController = self.initialViewController;
[self.window makeKeyAndVisible];
return YES;
}
@end
有2个目标也可以,但对我来说似乎太过分了
SYSTEM_VERSION_GREATER_THAN_OR_EQUAL_TO
太过分了。只需针对nil测试仅适用于iOS 6的类。见developer.apple.com/library/mac/#documentation/developertools/...
如果布局差异不大,则使用Springs和Struts定位元素会容易得多。
受到@marchinram的一个目标构想的启发,这是我最终想到的解决方案。两个情节提要板,一个用于支柱和弹簧,一个用于自动布局。在目标摘要中,我将自动版式情节提要板设置为默认值。然后,在appDelegate中,检查是否毕竟需要加载6.0之前的struts-springs故事板:
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
Class cls = NSClassFromString (@"NSLayoutConstraint");
if (cls == nil) {
NSString *mainStoryboardName = nil;
if ([[UIDevice currentDevice] userInterfaceIdiom] == UIUserInterfaceIdiomPad) {
mainStoryboardName = @"MainStoryboard_iPad_StrutsAndSprings";
} else {
mainStoryboardName = @"MainStoryboard_iPhone_StrutsAndSprings";
}
UIStoryboard *mainStoryboard = [UIStoryboard storyboardWithName:mainStoryboardName bundle:nil];
UIViewController *initialViewController = [mainStoryboard instantiateInitialViewController];
self.window.rootViewController = initialViewController;
[self.window makeKeyAndVisible];
}
另外,我将struts-springs情节提要的部署目标设置为iOS 5.1,将自动布局情节提要的部署目标设置为Project SDK(iOS 6.0)。
我真的很想在将故事板中的默认值加载到willFinishLaunchingWithOptions中之前进行切换:但这会导致“ NSInvalidUnarchiveOperationException”,原因:无论我如何尝试,都无法实例化名为NSLayoutConstraint的类。
尝试使用RRAutoLayout:https : //github.com/RolandasRazma/RRAutoLayout 这是iOS6 AutoLayout向iOS5的反向移植。