Ativando o layout automático no iOS 6, permanecendo compatível com versões anteriores do iOS 5


153

Qual é a melhor maneira de tirar proveito dos novos recursos de layout automático do iOS 6 e ainda oferecer compatibilidade com dispositivos mais antigos em versões anteriores do iOS?


+1. Onde você é capaz de descobrir isso? Qualquer pista ?
— Janak Nirmal

@Jennis Ainda não. O iOS 6 será lançado oficialmente amanhã (19/9/2012). Espero que isso inclua alguma documentação extra sobre o assunto.
— Sglantz

Ainda não encontrei nada. Mentes curiosas gostariam de saber!
— Ben Kreeger

Eu não acho que isso seria possível. Assim como os storyboards não eram possíveis no iOS4.
— 21812 Leo Natan

Além de fornecer dois arquivos de ponta, não vejo como isso seria possível. Mas eu concordo com você.
— Leo Natan

Respostas:


120

A execução automática pode ser ativada ou desativada em cada arquivo .storyboard ou .xib. Basta selecionar o arquivo em particular e modificar a propriedade "Use Autolayout" usando o Inspetor de arquivos no Xcode:

propriedade autolayout no inspetor de arquivos

O uso de arquivos de interface habilitados para autolayout com o destino de implantação definido para uma versão do iOS anterior à 6.0 resulta em erros de compilação, por exemplo:

Erro no MainStoryboard.storyboard: 3: Layout automático nas versões do iOS anteriores à 6.0

Uma de suas opções para usar o autolayout em um projeto e ainda preservar a compatibilidade com o iOS4-5 é criar dois destinos : um para o destino de implantação iOS 6.0 e outro para uma versão anterior do iOS, por exemplo:

insira a descrição da imagem aqui

Você também pode criar duas versões para cada um dos seus arquivos storyboard e XIB e usar o autolayout ativado com o destino 6.0 e a outra com o destino herdado, por exemplo:

insira a descrição da imagem aqui

Você adiciona MainStoryBoardAutoSize às fases de criação do destino iOS6 e o ​​outro arquivo ao destino iOS4. Você pode aprender mais sobre o uso de vários destinos aqui .

EDIT: Como a resposta do marchinram indica, se você carregar arquivos de storyboard a partir do código e não usar a configuração "Main Storyboard" no Xcode para definir o storyboard inicial, poderá usar um único destino.

Para mim, o custo da complexidade adicional de manter vários destinos e arquivos de interface parece compensar os benefícios do uso do programa automático. Exceto em alguns casos especiais, é provavelmente muito melhor usar o dimensionamento automático antigo simples (ou layoutSubViews do código) exclusivamente se a compatibilidade com iOS4-5 for necessária.


29
O layout automático requer o iOS 6 ou posterior. Não funciona com o iOS 5! Verifique suas reivindicações antes de postar. O iOS 5 simplesmente não possui as APIs necessárias (como a classe NSLayoutConstraint). Se você não acredita em mim, confira o que a experiência de outros usuários quando eles tentam usar AutoLayout com iOS 5: stackoverflow.com/questions/11252057/... stackoverflow.com/questions/11198981/...
— Imre Kelényi

1
Sim, acho que você está certo, acho que o ouvi em alguns vídeos wwdc, mas agora testei no dispositivo iOS 5.0 e ele travou. Vou ver esses vídeos e verificar onde eu ouvi. No entanto, você está certo, ele trava no iOS 5.0
— Asad Khan

@ ImreKelényi Como você enviaria isso para a loja de aplicativos? Não estou muito familiarizado com o processo, mas achei que você enviasse um arquivo compactado do seu arquivo .app. Ter dois objetivos dificulta esse processo? Obrigado.
— Crystal

47

Você realmente precisa de dois alvos? Eu consegui funcionar assim, eu tenho 2 storyboard como Imre Kelényi disse, um com layouts automáticos habilitados e o outro sem, então no delegado do aplicativo eu apenas verifico qual versão eles estão usando e seleciono o storyboard certo:

#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

Ter dois alvos funciona bem, mas parece um exagero para mim


1
Você está certo. Isso funciona desde que você carregue storyboards do código e não use a configuração "Main Storyboard" do destino no Xcode. Eu adiciono uma referência à sua resposta do meu post.
— Imre Kelényi 26/09/12

SYSTEM_VERSION_GREATER_THAN_OR_EQUAL_TOé um exagero. Basta testar uma classe somente do iOS 6 contra zero. Veja developer.apple.com/library/mac/#documentation/developertools/…
— matt

sim pontos bons, não foi realmente pensa sobre a restauração quando eu respondeu inicialmente
— marchinram

Ah, não use willFinishLaunchingWithOptions - recebi um "Aplicativo de encerramento devido à exceção não capturada 'NSInvalidUnarchiveOperationException', motivo: 'Não foi possível instanciar a classe denominada NSLayoutConstraint'" executando o simulador no iOS 5.1. O problema não ocorre com didFinishLaunchingWithOptions.
— Elise van Looij


3

Inspirada na idéia de um único objetivo da @ marchinram, esta é a solução que finalmente surgiu. Dois storyboards, um para molas e molas e outro para o layout automático. No resumo do destino, defino o storyboard de autolayout como padrão. Em seguida, no appDelegate, verifico se preciso carregar o storyboard de molas e molas anteriores à 6.0:

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

Além disso, defino o destino de implantação do storyboard struts-and-springs como iOS 5.1 e o do storyboard de layout automático como Project SDK (iOS 6.0).

Eu realmente queria fazer a troca antes que o padrão no storyboard fosse carregado, em willFinishLaunchingWithOptions: mas isso resulta em um 'NSInvalidUnarchiveOperationException', motivo: 'Não foi possível instanciar a classe denominada NSLayoutConstraint', independentemente do que eu tentasse.



0

Descobri definir o tamanho da visualização principal do Xibs como Forma livre e, em seguida, usar o dimensionamento automático é um prazer. Não é necessário mexer no código para um problema de exibição.

Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.