Włączenie automatycznego układu w iOS 6 przy zachowaniu kompatybilności wstecznej z iOS 5

153

Jaki jest najlepszy sposób, aby skorzystać z nowych funkcji automatycznego układu iOS 6, jednocześnie zapewniając kompatybilność ze starszymi urządzeniami we wcześniejszych wersjach iOS?

sglantz
źródło
+1. Gdzie możesz to rozgryźć? Jakaś wskazówka?
Janak Nirmal
@Jennis Jeszcze nie. iOS 6 zostanie oficjalnie wydany jutro (19.09.2012). Mam nadzieję, że obejmuje to dodatkową dokumentację na ten temat.
sglantz
Jeszcze nic nie znalazłem. Dociekliwe umysły chcą wiedzieć!
Ben Kreeger,
Nie sądzę, żeby to było możliwe. Podobnie jak scenorysy nie były możliwe na iOS4.
Leo Natan
Poza dostarczeniem dwóch plików nib nie widzę, jak to byłoby możliwe. Ale ja się z tobą zgadzam.
Leo Natan,

Odpowiedzi:

120

Autoukładanie można włączyć lub wyłączyć w każdym pliku .storyboard lub .xib. Po prostu zaznacz konkretny plik i zmodyfikuj właściwość „Użyj automatycznego układu” za pomocą Inspektora plików w Xcode:

autolayout w Inspektorze plików

Korzystanie z plików interfejsu z włączoną funkcją automatycznego układania z celem wdrożenia ustawionym na wersję systemu iOS starszą niż 6.0 powoduje błędy kompilacji, np .:

Błąd w MainStoryboard.storyboard: 3: Auto Layout w wersjach iOS wcześniejszych niż 6.0

Jedną z opcji użycia autoukładu w projekcie przy zachowaniu zgodności z iOS4-5 jest utworzenie dwóch celów : jednego dla celu wdrożenia iOS 6.0 i jednego dla wcześniejszej wersji iOS, np .:

wprowadź opis obrazu tutaj

Możesz również utworzyć dwie wersje dla każdego ze swoich scenorysów i plików XIB i użyć autoukładu włączonego z celem 6.0, a drugą ze starszym celem, np .:

wprowadź opis obrazu tutaj

Następnie dodajesz MainStoryBoardAutoSize do faz kompilacji elementu docelowego iOS6, a drugi plik do elementu docelowego iOS4. Możesz dowiedzieć się więcej o używaniu wielu celów tutaj .

EDYCJA: Jak odpowiedź marchinram , jeśli załadujesz pliki scenorysu z kodu i nie użyjesz ustawienia „Główna plansza” w Xcode, aby ustawić początkową scenorys, możesz użyć jednego celu.

Wydaje mi się, że koszt dodatkowej złożoności obsługi wielu celów i plików interfejsu wydaje się przeważać nad korzyściami wynikającymi z używania autoukładu. Z wyjątkiem kilku specjalnych przypadków, prawdopodobnie znacznie lepiej jest używać zwykłego starego automatycznego rozmiaru (lub layoutSubViews z kodu) wyłącznie, jeśli wymagana jest zgodność z iOS4-5.

Imre Kelényi
źródło
29
Układ automatyczny wymaga systemu iOS 6 lub nowszego. Nie działa z iOS 5! Sprawdź swoje roszczenia przed wysłaniem. iOS 5 po prostu nie ma wymaganych interfejsów API (takich jak klasa NSLayoutConstraint). Jeśli mi nie wierzysz, sprawdź, czego doświadczają inni użytkownicy, gdy próbują korzystać z funkcji Autolayout w iOS 5: stackoverflow.com/questions/11252057/… stackoverflow.com/questions/11198981/…
Imre Kelényi
1
Tak, myślę, że masz rację, myślę, że słyszałem to w niektórych filmach wwdc, ale teraz przetestowałem to na urządzeniu z iOS 5.0 i się zawiesiło. Przejdę przez te filmy i sprawdzę, gdzie je słyszałem. Mimo to masz rację, awarie na iOS 5.0
Asad Khan,
@ ImreKelényi Jak można to przesłać do sklepu z aplikacjami? Nie jestem zbyt zaznajomiony z tym procesem, ale pomyślałem, że prześlesz jedno spakowane archiwum swojego pliku .app. Czy posiadanie dwóch celów w ogóle utrudnia ten proces? Dzięki.
Crystal
47

Czy naprawdę potrzebujesz dwóch celów? Mam to w ten sposób, mam 2 scenorysy, jak powiedział Imre Kelényi, jeden z włączonymi układami automatycznymi, a drugi bez, a następnie w delegacie aplikacji po prostu sprawdzam, której wersji używają i wybieram odpowiednią scenorys:

#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

Posiadanie 2 celów działa równie dobrze, ale wydaje mi się to przesada

marchinram
źródło
1
Masz rację. Działa to tak długo, jak ładujesz scenorysy z kodu i nie używasz ustawienia „Main Storyboard” celu w Xcode. Dodaję odniesienie do Twojej odpowiedzi z mojego postu.
Imre Kelényi
SYSTEM_VERSION_GREATER_THAN_OR_EQUAL_TOto przesada. Po prostu przetestuj klasę tylko dla iOS 6 pod kątem zera. Zobacz developer.apple.com/library/mac/#documentation/developertools/…
mat
tak dobre punkty, tak naprawdę nie myślałem o przywróceniu, kiedy odpowiedziałem na początku
marchinram
Ahem, nie używaj willFinishLaunchingWithOptions - otrzymałem komunikat „Zamykanie aplikacji z powodu niezłapanego wyjątku„ NSInvalidUnarchiveOperationException ”, powód:„ Nie można utworzyć instancji klasy o nazwie NSLayoutConstraint ”” podczas uruchamiania symulatora w systemie iOS 5.1. Problem nie występuje z didFinishLaunchingWithOptions.
Elise van Looij
4

Jeśli różnice w układzie nie są duże, znacznie łatwiej jest używać sprężyn i rozpórek do pozycjonowania elementów.

Rich Apodaca
źródło
3

Zainspirowany pomysłem na jeden cel @ marchinram, jest to rozwiązanie, które w końcu wymyśliłem. Dwie plansze, jedna dla rozpórek i sprężyn, a druga dla autoukładu. W podsumowaniu docelowym ustawiam scenorys autoukładu jako domyślny. Następnie w appDelegate sprawdzam, czy mimo wszystko muszę załadować storyboard pre-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];
    }

Ponadto ustawiłem cel wdrożenia scenorysu struts-and-springs na iOS 5.1, a scenorysu autoukładu na Project SDK (iOS 6.0).

Naprawdę chciałem dokonać przełączenia przed załadowaniem domyślnej w scenorysie, w willFinishLaunchingWithOptions: ale to skutkuje `` NSInvalidUnarchiveOperationException '', powód: `` Nie można utworzyć wystąpienia klasy o nazwie NSLayoutConstraint '' bez względu na to, co próbowałem.

Elise van Looij
źródło
0

Zauważyłem, że ustawienie głównego rozmiaru widoku Xibs na Freeform, a następnie użycie Autodopasowania działa świetnie. Żadnego zamieszania w kodzie problemu z widokiem.

Anonimowy
źródło