Quel est le meilleur moyen de tirer parti des nouvelles fonctionnalités de disposition automatique d'iOS 6 tout en assurant la compatibilité avec les appareils plus anciens des versions antérieures d'iOS?
Autolayout peut être activé ou désactivé sur chaque fichier .storyboard ou .xib. Il suffit de sélectionner le fichier et de modifier la propriété "Use Autolayout" à l'aide de l'inspecteur de fichier dans Xcode:
L'utilisation de fichiers d'interface activés par autolayout avec la cible de déploiement définie sur une version iOS antérieure à 6.0 entraîne des erreurs de compilation, par exemple:
Erreur dans MainStoryboard.storyboard: 3: Mise en page automatique sur les versions iOS antérieures à 6.0
Une de vos options pour utiliser autolayout dans un projet tout en préservant la compatibilité avec iOS4-5 consiste à créer deux cibles : une pour la cible de déploiement iOS 6.0 et une pour une version iOS antérieure, par exemple:
Vous pouvez également créer deux versions pour chaque storyboard et vos fichiers XIB et utiliser l'autolayout activé avec la cible 6.0 et l'autre avec la cible héritée, par exemple:
Vous ajoutez ensuite MainStoryBoardAutoSize aux phases de construction de la cible iOS6 et l'autre fichier à la cible iOS4. Vous pouvez en apprendre plus sur l'utilisation de plusieurs cibles here .
EDIT: Comme la réponse de marchinram fait remarquer, si vous chargez des fichiers de storyboard à partir de code et n'utilisez pas le paramètre "Storyboard principal" dans Xcode pour définir le storyboard initial, vous pouvez utiliser une cible unique.
Pour moi, le coût de la complexité supplémentaire liée à la gestion de plusieurs cibles et fichiers d'interface semble l'emporter sur les avantages de l'utilisation de l'autolayout. À l'exception de quelques cas particuliers, il est probablement préférable d'utiliser le dimensionnement automatique pur et simple (ou layoutSubViews à partir du code) exclusivement si la compatibilité avec iOS4-5 est requise.
Avez-vous vraiment besoin de deux cibles? Je travaille comme ça. J'ai 2 scénarimages comme Imre Kelényi, l'un avec les mises en page automatiques activées et l'autre sans, puis dans le délégué de l'application, je vérifie simplement la version qu'ils utilisent et sélectionne le bon scénarimage:
#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
Avoir 2 cibles fonctionne aussi mais me semble exagéré
Si les différences de présentation ne sont pas importantes, il est beaucoup plus facile d’utiliser Ressorts et jambes de force pour positionner des éléments.
Inspirée par l’idée unique de @ marchinram, c’est la solution que j’ai finalement trouvée. Deux story-boards, un pour les jambes de force et les ressorts et un pour l'autolayout. Dans le résumé de la cible, j'ai défini le storyboard autolayout comme valeur par défaut. Ensuite, dans l'appDelegate, je vérifie si j'ai besoin de charger le storyboard antérieur à 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];
}
De plus, j'ai défini la cible de déploiement du storyboard struts-and-springs sur iOS 5.1, et celle du storyboard autolayout sur Project SDK (iOS 6.0).
Je voulais vraiment faire le changement avant que le storyboard par défaut ne soit chargé, dans willFinishLaunchingWithOptions: mais cela donne une 'NSInvalidUnarchiveOperationException', raison: 'Je n'ai pas pu instancier la classe nommée NSLayoutConstraint', peu importe ce que j'ai essayé.
Essayez d'utiliser RRAutoLayout: https://github.com/RolandasRazma/RRAutoLayout Il s'agit d'un backport iOS6 AutoLayout sur iOS5.
J'ai trouvé la définition de la taille de la vue principale de Xibs sur Freeform, puis l'utilisation d'Autosizing est un régal. Pas de déconner dans le code pour un problème de vue.