Pergunta

UPDATE: Veja a minha resposta a esta pergunta em primeiro lugar. Este parece ser um bug. Um caso de teste mínimo foi criado e um relatório foi arquivado com a Apple. (Fixo a partir de iPhone OS 3.1.)

Aqui está um quebra-cabeças do "Eu estou tão perto!" departamento.

Eu tenho um iPhone app baseado em Bar Tab. Cada guia apresenta uma UINavigationController com os suspeitos do costume (nav bar, exibição de tabela ... que por sua vez pode levar a outra VC, etc.).

Agora, um desses VCs de nível mais baixo é para ser usado em portait e modos paisagem. Mas há um problema. Nossa paisagem-amigável VC do shouldAutorotateToInterfaceOrientation: não vai obter chamado out-of-the-box! O que fazer?

Aqui está o que fazer. Na minha Tab Bar Controller, que tenho implementado em seu próprio arquivo, eu tenho este:

- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation {
     return [self.selectedViewController shouldAutorotateToInterfaceOrientation:interfaceOrientation];
}

Isso acaba propagar o pedido para o meu amigável-paisagem VC, que também responde a esta mensagem. Todos os meus outros VCs não implementar este método, então eles simplesmente ir com a orientação retrato padrão.

Problema resolvido !!! Yay!

Bem, não completamente :. (

Parece que as coisas não vão tão bem quando minha paisagem-friendly VC é invocado a partir de dentro das profundezas do controlador de barra de guia MoreNavigationController .

Eu decidi comparar / contraste entre a VC chamado de dentro um do quatro primeiros barra de guia UINavigationControllers ... e que mesmo VC chamado de dentro do MoreNavigationController . Este vai ser um pouco ultra-detalhado, para ter comigo. Esperemos que o jogo pelo jogo comprova útil para sleuthing as coisas.

Quando as cargas de aplicativos, há várias chamadas iniciais para shouldAutorotate ... método do controlador bar na guia. Nestes casos iniciais, selectedViewController é nulo. No entanto, nós finalmente terminar o carregamento, o item de guia inicial é selecionada, e está tudo bem.

Right. Primeiro, vamos escolher um dos quatro primeiros itens da barra de guia e detalhamento para a nossa VC.

Nós vamos buscá terceiro item barra de navegação, de modo que é o terceiro controlador nav. Nós detalhar ao nosso VC que suporta rotação. A confirma inspeção rápida que o pai é realmente o terceiro controlador nav da lista controlador de vista da nossa barra de abas. Bom!

Vamos rodar o dispositivo. O controlador de barra de abas é convidado a autorotate (veja o código acima). Observamos que selectedViewController é também aquele terceiro controlador nav, além de Vista superior e visível controladores do controlador nav estão definidos para o nosso fiel VC que suporta rotação.

Assim, o controlador de barra de guia irá encaminhar o shouldAutorotate Mensagem para o terceiro controlador nav ... mas nossa VC amigável rotação de última instância recebe a mensagem. (Eu não estou fazendo nada de especial aqui. Talvez o VC desejado recebe a mensagem, porque é a parte superior e / ou VC visível?) Em qualquer caso, começamos a rodar a paisagem, as coisas são redimensionados, e está tudo bem. "Grande sucesso!"

Agora, vamos pressionar o botão de volta e pop a pilha VC, deixando o modo paisagem no processo. O controlador de barra de abas é consultado novamente.

O tempo para um pouco de lado aqui. O topViewController para o nosso controlador nav ainda é que VC amigável rotação, mas visibleViewController já está definido para UISnapshotModalViewController ! Heh. Nunca vi isso antes ... mas Erica Sadun tem . Parece que é para "desaparecer controladores de vista" (que neste caso é certamente verdade - é desaparecendo tudo bem).

Como eu continuo percorrendo, as estadias VC visíveis como Snapshot, mas o top VC, eventualmente, muda para o próximo VC na pilha, desde a minha VC especial é finalmente ido. bastante justo.

Assim, é o wh cenárioere tudo funciona bem.

Agora vamos tentar o mesmo teste, só que desta vez nós estamos indo para ir ao MoreNavigationController (o mais item da barra de guia) e detalhamento para a mesma classe VC como antes. No meu caso, passa a ser a 7ª um em VC lista de controlador de barra da guia.

Nós entramos a rotação-aware VC e ... desta vez ele é convidado a rodar diretamente ! O Bar Controlador Tab é não pediu permissão para rodar em tudo. Hmm.

Uma verificação rápida do pai mostra VC é um MoreNavigationController . OK, isso faz sentido.

Agora vamos tentar girar o dispositivo. nada é chamado . Nenhum dos nossos pontos de interrupção ser atingido. Não em nosso VC. Não em nosso controlador de barra de abas. (Huh?!?!)

O-kaaaay. Vamos estourar a pilha, volte para o mesmo VC e tentar girar novamente. Esquisito. Agora temos uma chamada no Bar Controlador Tab pedindo permissão auto-rotação. Aqui, o controlador selecionado é o nosso controlador de Nav fiel (# 7), mas desta vez a sua visibleViewController e topViewController SET TO NIL !

Uma vez que continuamos a partir daqui, uma mensagem misteriosa aparece no console do depurador:

Usando animação de rotação de dois estágios. Para usar o único estágio mais suave animação, este pedido deve remover método de duas fases implementações.

porque Mysterious Não estou usando dois estágios rotação animação ! Não SecondHalf variantes do método estão em qualquer lugar do jogo no meu código-fonte.

Ai, meu VC rotação de consciência nunca é dito que a rotação está ocorrendo (mesmo que a rotação ocorre na tela), então é claro meu ponto de vista é tudo estragou como resultado. Mayhem e seguirá tristeza. : (

Vamos não se incomodam mesmo popping da pilha neste momento.

Eu acho que as dicas doc View Controller no possível problema:

Se você deseja executar personalizado animações durante uma orientação mudança, você pode fazê-lo em um dos dois maneiras. mudanças de orientação usado para ocorre em duas etapas, com notificações ocorrendo no início, no meio, e terminar a pontos de rotação. No entanto, em iPhone OS 3.0, o apoio foi adicionada para a realização de orientação muda em um passo. Usando um de uma etapa mudança de orientação tende a ser mais rápido que o processo de duas etapas mais velho e é geralmente recomendado para qualquer novo código.

Gostaria de saber se MoreNavigationController ainda está respondendo ao processo em duas etapas, e é assim tropeçar qualquer tentativa de usar o processo de uma etapa? Note-se que, se você responder às mensagens de duas etapas, a variante de uma etapa não vai funcionar (novamente, per os docs). Eu não estou respondendo a eles, mas eu tenho uma suspeita de algo esgueirando por trás das cenas é.

Na verdade, se eu comentar o método de etapa única, e tentar responder a willAnimateSecondHalfOfRotationFromInterfaceOrientation: Duração: , I do o memorando! Mas ele ainda não saltam da pilha muito limpa (em termos de recursos visuais). Ainda mais estranho: willAnimateFirstHalfOfRotationFromInterfaceOrientation: Duração: não é chamado, mesmo quando tentei roubar um apelo à auto (usando a mensagem FirstHalf) em shouldAutorotateToInterfaceOrientation: . Ele retorna imediatamente durante um traçado, como se eu nunca sequer definiu. Suspiro.

Então esse é o play-by-play.

Em resumo, se qualquer tratado com sucesso rotação do dispositivo de uma etapa para um VC chamado de dentro MoreNavigationController um Bar Controlador Tab? mentes inquiring querem saber!

Foi útil?

Solução

Apple desaconselha subclasse UITabBarController, então eu encontrei uma maneira fácil de auto-rotação punho usando categorias vez. Ele não corrige o bug com os controladores mais ... Veja, mas eu acho que é uma maneira mais a Apple-friendly de começar o trabalho feito (e meios menos subclassificação para você).

Para fazer cada guia na minha autorotate aplicação corretamente, eu defini -shouldAutorotateToInterfaceOrientation: em meus controladores de vista personalizado, mas todos eles são UINavigationControllers dentro dentro de um UITabBarController, então a mensagem não será enviado para baixo da cadeia para o meu VC até que os dois também respondem. Então eu adicionei as seguintes linhas para meus arquivos delegado do aplicativo:

Adicionado ao fundo do MyAppDelegate.h

@interface UITabBarController (MyApp)
@end

@interface UINavigationController (MyApp)
@end

Adicionado ao fundo do MyAppDelegate.m

@implementation UITabBarController (MyApp) 
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation {
    return YES;
}
@end

@implementation UINavigationController (MyApp) 
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation {
    return YES;
}
@end

Outras dicas

Parece que temos um bug. Eu criei um caso de teste reproduzível, mínimo, e relatou que via Reporter Bug Apple ( RADAR Problema 7.139.857 ) .

Update:. Isso foi corrigido a partir de iPhone OS 3.1

O problema essencial é:

View já controladores em um Controlador de navegação pilha não fazer receber willAnimateRotationToInterfaceOrientation: Duração: mensagens quando um Bar Controlador Tab 'Mais Navigation Controller' está em uso.

Este problema faz não ocorrer quando os controladores de vista guia item da barra são controladores básicos vista. Só quando eles são controladores de navegação e única quando o "Mais" hierarquia de navegação está em uso.

A mensagem de console (sobre animação de rotação de dois estágios) sugere que algo no quadro (o mais Controlador de navegação?) Ainda está usando uma animação de dois estágios, embora estágio único agora é recomendado a partir de iPhone OS 3.0.

Isso poderia explicar por que willAnimateRotationToInterfaceOrientation: não é chamado nesse caso particular. Por documentação controler vista da Apple, esta mensagem não será chamado quando em duas fases, primeiro / mensagens de orientação no segundo tempo estão sendo respondeu a vez.

Uma versão ligeiramente modificada do de Victorb resposta que permite que cada controlador de exibição para decidir se permite a rotação.

Aqui, como uma essência para cópia mais fácil e bifurcação

AppDelegate.h

@interface UITabBarController (MyApp)
@end

@interface UINavigationController (MyApp)
@end

AppDelegate.m

@implementation UITabBarController (MyApp) 
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation {
    UIViewController *selectedVC = [self selectedViewController];
    if ([selectedVC respondsToSelector:@selector(shouldAutorotateToInterfaceOrientation:)]) {
        return [selectedVC shouldAutorotateToInterfaceOrientation:toInterfaceOrientation];
    }

    //optimistic return - if you want no rotation, you have to specifically tell me!
    return YES;
}
@end

@implementation UINavigationController (MyApp) 
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation {
    UIViewController *visibleVC = [self visibleViewController];
    if ([visibleVC respondsToSelector:@selector(shouldAutorotateToInterfaceOrientation:)]) {
        return [visibleVC shouldAutorotateToInterfaceOrientation:toInterfaceOrientation];
    }

    //optimistic return - if you want no rotation, you have to specifically tell me!
    return YES;
}
@end
Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top