ios5 - 在iOS 6中启用自动布局,同时保持向后兼容iOS 5




backwards-compatibility ios6 autolayout (6)

利用iOS 6新的自动布局功能的最佳方式是什么,同时仍然能够在早期版本的iOS上提供旧设备的兼容性?


Answers

受@ marchinram的一个目标想法的启发,这是我终于想出的解决方案。 两个故事板,一个用于支柱和弹簧,一个用于自动布局。 在目标摘要中,我将自动布局故事板设置为默认值。 然后,在appDelegate中,我检查是否需要加载6.0之前的struts-and-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-and-springs故事板的部署目标设置为iOS 5.1,将自动布局故事板设置为Project SDK(iOS 6.0)。

我真的希望在故事板的默认加载之前执行切换,在willFinishLaunchingWithOptions中:但是会导致'NSInvalidUnarchiveOperationException',原因是:'无法尝试我所尝试的,无法实例化名为NSLayoutConstraint的类。



如果布局差异不大,使用Springs和Struts来定位元素会更容易。


你真的需要两个目标吗? 我有这样的工作,我有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个目标的作品,但似乎是矫枉过正给我


Autolayout可以在每个.storyboard或.xib文件中启用或禁用。 只需选择特定文件并使用Xcode中的文件检查器修改“使用Autolayout”属性:

将部署目标设置为iOS版本6.0之前的自动布局启用接口文件会导致编译错误,例如:

MainStoryboard.storyboard中的错误:3:iOS版本6.0之前的自动布局

在项目中使用自动布局并保持与iOS4-5兼容性的选项之一是创建两个targets :一个用于部署目标iOS 6.0,另一个用于较早的iOS版本,例如:

您还可以为每个故事板和XIB文件创建两个版本,并使用6.0目标启用的自动布局,而另一个则使用传统目标,例如:

然后将MainStoryBoardAutoSize添加到iOS6目标的Build阶段,将另一个文件添加到iOS4目标。 你可以here了解更多关于使用多个目标的here

编辑:正如marchinram的答案指出的那样,如果您从代码加载故事板文件并且不使用Xcode中的“Main Storyboard”设置设置初始故事板,则可以使用单个目标。

对我而言,维护多个目标和接口文件所增加复杂性的成本似乎超过了使用自动布局的好处。 除了一些特殊情况外,如果需要iOS4-5兼容性,您可能会更好地使用纯旧的自动调整大小(或代码中的layoutSubViews)。


a:以下行

 [[UITableView appearance] setBackgroundColor:[UIColor blueColor]];

将每张桌子都看成蓝色! 刚刚在iOS 5模拟器上测试过。

b:UIAppearance应该适用于UIView每个属性。 UIView所有子类都符合UIAppearance Protocol

c:我认为大部分会创建一个类和/或方法来自定义外观并将其调用:

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions

类似的东西: [ApplicationAppearance setApplicationSchemaTo:ASchemaBlue];

编辑:

例如,UIBarButtonItem定义了以下方法:

@property(非原子,保留)UIColor * tintColor UI_APPEARANCE_SELECTOR;

来自UIAppearanceContainer Protocol Reference

UIBarButtonItem类引用中定义了tintColor

@property(非原子,保留)UIColor * tintColor

但是在UIBarButtonItem.h中定义了:

@property(nonatomic,retain) UIColor *tintColor __OSX_AVAILABLE_STARTING(__MAC_NA,__IPHONE_5_0) UI_APPEARANCE_SELECTOR;

我认为文档不是最新的。





ios ios5 backwards-compatibility ios6 autolayout