Abilitazione del layout automatico in iOS 6 pur rimanendo compatibile con iOS 5


153

Qual è il modo migliore per sfruttare le nuove funzionalità di layout automatico di iOS 6 pur garantendo la compatibilità con i dispositivi più vecchi su versioni precedenti di iOS?


+1. Dove sei riuscito a capirlo? Qualche idea?
Janak Nirmal,

@Jennis Non ancora. iOS 6 uscirà ufficialmente domani (19/09/2012). Speriamo che includa della documentazione aggiuntiva sull'argomento.
Sglantz,

Non ho ancora trovato niente. Le menti indagatrici vorrebbero sapere!
Ben Kreeger,

Non penso che sarebbe possibile. Proprio come gli storyboard non erano possibili su iOS4.
Leo Natan,

A parte fornire due file di pennini, non vedo come sarebbe possibile. Ma sono d'accordo con te.
Leo Natan,

Risposte:


120

Il layout automatico può essere abilitato o disabilitato su ogni file .storyboard o .xib. Basta selezionare il file specifico e modificare la proprietà "Usa autolayout" utilizzando la finestra di ispezione File in Xcode:

proprietà autolayout nella finestra di ispezione File

L'uso di file di interfaccia abilitati per il completamento automatico con la destinazione di distribuzione impostata su una versione iOS precedente alla 6.0 provoca errori di compilazione, ad esempio:

Errore in MainStoryboard.storyboard: 3: Layout automatico su versioni iOS precedenti alla 6.0

Una delle opzioni per utilizzare il layout automatico in un progetto e preservare la compatibilità con iOS4-5 è quella di creare due target : uno per destinazione di distribuzione iOS 6.0 e uno per una versione precedente di iOS, ad esempio:

inserisci qui la descrizione dell'immagine

Puoi anche creare due versioni per ciascuno dei tuoi storyboard e file XIB e utilizzare il autolayout abilitato con la destinazione 6.0 e l'altra con la destinazione legacy, ad esempio:

inserisci qui la descrizione dell'immagine

Quindi aggiungi MainStoryBoardAutoSize alle fasi di costruzione della destinazione iOS6 e l'altro file alla destinazione iOS4. Puoi saperne di più sull'uso di più target qui .

EDIT: Come sottolinea la risposta di marchinram , se carichi i file dello storyboard dal codice e non usi l'impostazione "Main Storyboard" in Xcode per impostare lo storyboard iniziale, puoi utilizzare un singolo target.

Per me, il costo della complessità aggiunta di mantenere più target e file di interfaccia sembra superare i vantaggi dell'utilizzo del layout automatico. Fatta eccezione per alcuni casi speciali, è probabilmente molto meglio utilizzare il vecchio dimensionamento automatico semplice (o layoutSubVista dal codice) esclusivamente se è richiesta la compatibilità con iOS4-5.


29
Il layout automatico richiede iOS 6 o versioni successive. Non funziona con iOS 5! Verifica i reclami prima di pubblicare. iOS 5 semplicemente non ha le API richieste (come la classe NSLayoutConstraint). Se non mi credete, verificare che cosa l'esperienza di altri utenti quando tentano di usare Autolayout con iOS 5: stackoverflow.com/questions/11252057/... stackoverflow.com/questions/11198981/...
Imre Kelényi

1
Sì, penso che tu abbia ragione, penso di averlo sentito in alcuni video WWDC, ma ora l'ho testato su un dispositivo iOS 5.0 e si è bloccato. Esaminerò questi video e verificherò dove l'ho sentito. Tuttavia hai ragione, si blocca su iOS 5.0
Asad Khan,

@ ImreKelényi Come lo invieresti all'app store? Non ho molta familiarità con il processo, ma ho pensato di inviare un archivio zippato del tuo file .app. Avere due obiettivi rende questo processo più difficile? Grazie.
Crystal,

47

Hai davvero bisogno di due obiettivi? Ho funzionato in questo modo, ho 2 storyboard come ha detto Imre Kelényi, uno con layout automatici abilitati e l'altro senza, quindi nel delegato dell'app controllo solo quale versione stanno usando e seleziono lo storyboard giusto:

#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

Avere 2 bersagli funziona bene ma mi sembra eccessivo


1
Hai ragione. Funziona finché si caricano gli storyboard dal codice e non si utilizza l'impostazione "Main Storyboard" del target in Xcode. Aggiungo un riferimento alla tua risposta dal mio post.
Imre Kelényi,

SYSTEM_VERSION_GREATER_THAN_OR_EQUAL_TOè eccessivo. Basta testare una classe solo per iOS 6 contro zero. Vedi developer.apple.com/library/mac/#documentation/developertools/…
matt

Sì, punti
positivi

Ahem, non usare willFinishLaunchingWithOptions - Ho ottenuto un'app "Terminazione a causa dell'eccezione non rilevata" NSInvalidUnarchiveOperationException ", motivo:" Impossibile creare un'istanza della classe denominata NSLayoutConstraint "" che esegue il simulatore su iOS 5.1. Il problema non si verifica con didFinishLaunchingWithOptions.
Elise van Looij,


3

Ispirata all'unica idea target di @ marchinram, questa è la soluzione che ho finalmente trovato. Due storyboard, uno per montanti e molle e uno per autolayout. Nel riepilogo di destinazione, ho impostato lo storyboard di autolayout come predefinito. Quindi, in AppDelegate, controllo se devo caricare lo storyboard struts-and-springs pre-6.0 dopo tutto:

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

Inoltre, ho impostato il target di distribuzione dello storyboard struts-and-springs su iOS 5.1 e quello dello storyboard di autolayout su Project SDK (iOS 6.0).

Volevo davvero fare il passaggio prima che venisse caricato il valore predefinito nello storyboard, in willFinishLaunchingWithOptions: ma questo si traduce in un "NSInvalidUnarchiveOperationException", motivo: "Impossibile creare un'istanza della classe denominata NSLayoutConstraint", indipendentemente da ciò che ho provato.



0

Ho trovato che l'impostazione delle dimensioni della vista principale di Xibs su Freeform, e quindi l'uso del ridimensionamento automatico è un piacere. Nessun problema con il codice per un problema di visualizzazione.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.