Habilitar el diseño automático en iOS 6 mientras sigue siendo compatible con iOS 5

153

¿Cuál es la mejor manera de aprovechar las nuevas características de diseño automático de iOS 6 y al mismo tiempo proporcionar compatibilidad con dispositivos más antiguos en versiones anteriores de iOS?

sglantz
fuente
+1. ¿Dónde puedes resolver esto? Cualquier pista ?
Janak Nirmal
@Jennis Todavía no. iOS 6 se lanzará oficialmente mañana (19/09/2012). Esperemos que eso incluya documentación adicional sobre el tema.
sglantz
No he encontrado nada todavía. ¡A las mentes inquisitivas les gustaría saber!
Ben Kreeger
No creo que eso sea posible. Al igual que los guiones gráficos no eran posibles en iOS4.
Leo Natan
Fuera de proporcionar dos archivos plumín, no veo cómo eso sería posible. Pero estoy de acuerdo contigo.
Leo Natan

Respuestas:

120

Autolayout se puede habilitar o deshabilitar en cada archivo .storyboard o .xib. Simplemente seleccione el archivo en particular y modifique la propiedad "Usar Autolayout" usando el inspector de archivos en Xcode:

propiedad autolayout en el inspector de archivos

El uso de archivos de interfaz habilitados para autolayout con el objetivo de implementación establecido en una versión de iOS anterior a 6.0 produce errores de compilación, por ejemplo:

Error en MainStoryboard.storyboard: 3: Diseño automático en versiones de iOS anteriores a 6.0

Una de sus opciones para usar la distribución automática en un proyecto y aún preservar la compatibilidad con iOS4-5 es crear dos objetivos : uno para el objetivo de implementación de iOS 6.0 y otro para una versión anterior de iOS, por ejemplo:

ingrese la descripción de la imagen aquí

También puede crear dos versiones para cada uno de sus archivos de guión gráfico y XIB y utilizar la distribución automática habilitada con el objetivo 6.0 y la otra con el objetivo heredado, por ejemplo:

ingrese la descripción de la imagen aquí

Luego agrega MainStoryBoardAutoSize a las fases de compilación del objetivo iOS6 y el otro archivo al objetivo iOS4. Puede obtener más información sobre el uso de múltiples objetivos aquí .

EDITAR: Como señala la respuesta de marchinram , si carga los archivos del guión gráfico desde el código y no usa la configuración "Guión gráfico principal" en Xcode para establecer el guión gráfico inicial, puede usar un solo objetivo.

Para mí, el costo de la complejidad adicional de mantener múltiples objetivos y archivos de interfaz parece superar los beneficios del uso de la distribución automática. Excepto por algunos casos especiales, probablemente sea mucho mejor utilizar el tamaño automático antiguo (o layoutSubViews del código) exclusivamente si se requiere compatibilidad con iOS4-5.

Imre Kelényi
fuente
29
El diseño automático requiere iOS 6 o posterior. ¡No funciona con iOS 5! Verifique sus reclamos antes de publicar. iOS 5 simplemente no tiene las API requeridas (como la clase NSLayoutConstraint). Si no me cree, vea lo que experimentan otros usuarios cuando intentan usar Autolayout con iOS 5: stackoverflow.com/questions/11252057/… stackoverflow.com/questions/11198981/…
Imre Kelényi
1
Sí, creo que tienes razón, creo que lo escuché en algunos videos de wwdc, pero ahora lo probé en un dispositivo iOS 5.0 y se bloqueó. Revisaré estos videos y comprobaré dónde lo escuché. Sin embargo, tienes razón, se bloquea en iOS 5.0
Asad Khan
@ ImreKelényi ¿Cómo enviarías esto a la tienda de aplicaciones? No estoy muy familiarizado con el proceso, pero pensé que enviarías un archivo comprimido de tu archivo .app. ¿Tener dos objetivos hace que ese proceso sea más difícil? Gracias.
Cristal
47

¿Realmente necesitas dos objetivos? Lo hice funcionar así, tengo 2 guiones gráficos como dijo Imre Kelényi, uno con diseños automáticos habilitados y el otro sin ellos, luego en el delegado de la aplicación solo verifico qué versión están usando y selecciono el guión gráfico correcto:

#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

Tener 2 objetivos también funciona, pero me parece excesivo

marchinram
fuente
1
Tienes razón. Esto funciona siempre que cargue guiones gráficos desde el código y no use el ajuste "Guión gráfico principal" del objetivo en Xcode. Agrego una referencia a su respuesta de mi publicación.
Imre Kelényi
SYSTEM_VERSION_GREATER_THAN_OR_EQUAL_TOEs exagerado. Simplemente pruebe una clase solo para iOS 6 contra cero. Ver developer.apple.com/library/mac/#documentation/developertools/…
mate
Sí puntos buenos, no era realmente pensar en la restauración cuando me contestó inicialmente
marchinram
Ejem, no uses willFinishLaunchingWithOptions - Obtuve una "Aplicación finalizada debido a la excepción no detectada 'NSInvalidUnarchiveOperationException', razón: 'No se pudo crear una instancia de la clase llamada NSLayoutConstraint'" que ejecuta el simulador en iOS 5.1. El problema no ocurre con didFinishLaunchingWithOptions.
Elise van Looij
4

Si las diferencias de diseño no son grandes, es mucho más fácil usar resortes y puntales para colocar elementos.

Rich Apodaca
fuente
3

Inspirada en la única idea objetivo de @marchinram, esta es la solución que finalmente se me ocurrió. Dos guiones gráficos, uno para struts-and-springs y otro para autolayout. En el resumen de destino, configuré el guión gráfico de distribución automática como predeterminado. Luego, en appDelegate, verifico si necesito cargar el guión gráfico anterior de 6.0 struts-and-springs después de todo:

    - (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];
    }

Además, configuré el objetivo de implementación del guión gráfico struts-and-springs en iOS 5.1, y el del guión gráfico de distribución automática en Project SDK (iOS 6.0).

Realmente quería hacer el cambio antes de que se cargue el valor predeterminado en storyboard, en willFinishLaunchingWithOptions: pero eso da como resultado una 'NSInvalidUnarchiveOperationException', razón: 'No se pudo crear una instancia de la clase llamada NSLayoutConstraint' sin importar lo que intenté.

Elise van Looij
fuente
0

He encontrado que configurar el tamaño de la vista principal de Xibs en Freeform y luego usar Autosizing funciona de maravilla. No perder el tiempo en el código por un problema de vista.

Anónimo
fuente