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?

sglantz
fonte
+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.

Imre Kelényi
fonte
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

marchinram
fonte
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
4

Se as diferenças de layout não forem grandes, é muito mais fácil usar Molas e Suportes para posicionar elementos.

Rich Apodaca
fonte
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.

Elise van Looij
fonte
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.

Anônimo
fonte