Segmentos adaptativos no storyboard Xcode 6. O push foi descontinuado?

121

Por padrão, o construtor de interfaces do Xcode 6 possui uma nova caixa de seleção "use classes de tamanho". Torna as visualizações adaptáveis. insira a descrição da imagem aqui

Quando tento fazer segue entre duas visualizações no meu storyboard, tenho novas opções: insira a descrição da imagem aqui

em vez antigo:

insira a descrição da imagem aqui

Agora temos "show" e "present modally" em vez de "push" e "modal". As opções antigas estão marcadas como obsoletas. Eu escolhi a opção "show", porque nas configurações a seguir chamava "show (por exemplo, push)

insira a descrição da imagem aqui

Mas isso não faz força. A animação de segmentos parece um slide da parte inferior (modal) e a barra de navegação desaparece.

A pergunta é: como posso fazer o "show" funcionar como push? É possível ou devo usar "push (obsoleto)" em vez disso? Onde posso encontrar informações sobre novos tipos de segue? A única coisa que encontrei na biblioteca de desenvolvedores do iOS8 é o Storyboards, que ajuda você a criar sua interface do usuário, mas não há informações sobre "show".

ATUALIZAR

Eu tentei criar um novo projeto e "show" é realmente funciona como "push". Acho que o problema no meu projeto pode ser porque reutilizo o controlador de navegação com código como este, mas não sei como corrigi-lo.

if ( [segue isKindOfClass: [SWRevealViewControllerSegue class]] ) {
    SWRevealViewControllerSegue *swSegue = (SWRevealViewControllerSegue*) segue;
    
    swSegue.performBlock = ^(SWRevealViewControllerSegue* rvc_segue, UIViewController* svc, UIViewController* dvc) {
        
        UINavigationController* navController = (UINavigationController*)self.revealViewController.frontViewController;
        [navController setViewControllers: @[dvc] animated: NO ];
        [self.revealViewController setFrontViewPosition: FrontViewPositionLeft animated: YES];
    };
    
}

Depois disso, tento empurrar NewViewController após MainViewController insira a descrição da imagem aqui

ATUALIZAÇÃO 2:

Parece ser apenas o iOS 7, o iOS 7.1.

John Kakon
fonte

Respostas:

97

Sim, use 'Show' em vez de 'Push'

Como posso fazer o "show" funcionar como push? É possível ou devo usar "push (privar)" em vez disso?

Deveria; faz por mim. Estou usando o Xcode 6 beta 2 e, para testar, usei o modelo de visualização única (chamando o controlador de visualização pré-criado no IB 'VC_A'). Adicionei outro controlador de exibição ('VC_B'). Em seguida, adicionei um botão no VC_A para mostrar o VC_B e outro de VC_B de volta ao VC_A. Quando adiciono um controlador de navegação como o controlador de exibição inicial no storyboard e faço do VC_A o rootViewController, 'push' e 'show' têm o mesmo efeito. Se eu não tiver um controlador de navegação inicial e usar 'show', entendo o que você descreveu, pois o VC_B faz um deslize de cima para baixo. Se eu tentar 'empurrar', recebo uma falha, pois para fazer o empurrão, preciso ter um controlador de navegação.

Onde posso encontrar informações sobre novos tipos de segue?

Então, encontrei algumas informações na sessão 'What's New in Interface Builder' aqui . Se você olhar para os slides, verá um slide (41) mencionar a alteração. Ao assistir ao vídeo da sessão, você pode pular para o minuto 38:00, onde eles começam a falar sobre sequências adaptativas. Eles explicam que o segue adaptativo 'show', por exemplo, leva em consideração o contexto ao decidir como fazer a apresentação de um novo controlador de exibição.

Spencer Hall
fonte
Obrigado pela sua resposta. Eu tentei criar um novo projeto e "show" é realmente funciona como push com o controlador de navegação. No meu projeto, eu tenho uma estrutura complicada com a barra lateral desta lição appcoda.com/ios-programming-sidebar-navigation-menu e push works, show não. Pode ser o motivo pelo qual eu reutilizo o controlador de navegação. Atualizei minha pergunta com o código de reutilização.
John Kakon
Portanto, a primeira coisa que vejo ao olhar para a sua atualização é que você está usando a expectativa de segue personalizado: 'SWRevealViewControllerSegue', então sim, provavelmente não faz sentido usar 'show' ou 'push' no seu caso, uma vez que eles estão embutidos enquanto você deseja executar seu próprio código personalizado. Quando faço o download do projeto de amostra, ele até mostra a seleção de 'personalizado' nas etapas seguintes no arquivo de storyboard.
Spencer Municipal
Não quis dizer isso. Eu estava falando sobre a criação de um novo UIViewController ao lado de "MainViewController" (possui o Navigation Controller, e minha "atualização" mostra apenas como faço para chegar lá) e tenta inserir o novo View no MainViewController. Screenshot do Storyboard Ficarei grato se você habilitar "use classes de tamanho" no projeto de amostra, criar NewViewController e tentar fazer segue entre MainViewController e NewViewController por "show". Você verá do que estou falando.
John Kakon
Fiz isso agora e pelo menos para mim o "show" funcionou como "push".
Spencer Hall
9
Você pode contornar o bug, certificando-se de que todas as formas do seu controlador de exibição tenham um UINavigationController na raiz. Mesmo que isso signifique colocar um UINavigationController em seu storyboard que nunca será acessado. Parece que a fiação é usada para inferir comportamento.
Scott Robertson
33

Já existe uma resposta aceita, mas eu queria fornecer um pouco mais de informação, possivelmente informações que não estavam disponíveis antes.

Como mencionado anteriormente, os itens "push" e "modal" foram descontinuados e foram substituídos por "show" e "present modally", respectivamente. De acordo com a documentação da Apple, os novos itens foram divididos em itens que se adaptam às classes de tamanho. As mais antigas devem ser usadas apenas para suportar versões do iOS anteriores ao iOS 8.

O documento no link a seguir explica isso e a descrição de todos os itens disponíveis, antigos e novos.

Adicionando um segmento entre cenas em um storyboard

Caso o URL mude no futuro, esta é a explicação dada para cada novo segue:

mostrar

Apresente o conteúdo na área de detalhes ou mestre, dependendo do conteúdo da tela. Se o aplicativo estiver exibindo uma visualização principal e de detalhes, o conteúdo será enviado para a área de detalhes. Se o aplicativo estiver exibindo apenas o mestre ou os detalhes, o conteúdo será colocado na parte superior da pilha atual do controlador de exibição.

Mostrar detalhes

Apresente o conteúdo na área de detalhes. Se o aplicativo estiver exibindo uma exibição principal e de detalhes, o novo conteúdo substituirá os detalhes atuais. Se o aplicativo estiver exibindo apenas o mestre ou os detalhes, o conteúdo substituirá a parte superior da pilha atual do controlador de exibição.

Present Modally

Apresente o conteúdo de forma modal. Existem opções para escolher um estilo de apresentação (UIModalPresentationStyle) e um estilo de transição (UIModalTransitionStyle).

Presente como Popover

Apresente o conteúdo como um popover ancorado a uma visualização existente. Há uma opção para especificar as direções possíveis da seta mostrada em uma borda da exibição popover (UIPopoverArrowDirection). Há também uma opção para especificar a vista da âncora.

alondono
fonte
24

tldr; Exclua o Segue que não está pressionando corretamente e recrie-o no storyboard arrastando de um UIView / UIControl para o controlador de exibição de destino.

Não há nada errado com as outras respostas, mas esta explica o que está acontecendo, como você pode verificar se está acontecendo e como mitigar o problema no futuro.

fundo

No meu caso, nenhum dos meus Show Segues estava funcionando, embora eu já tivesse um UINavigationController como meu controlador de exibição inicial (com meu conteúdo UIViewController como raiz).

Por que e como o segmento de exibição é interrompido

O Show segue quebra quando tem uma ação associada ao segue no xml de origem do storyboard. Um cenário típico que causa isso pode ser se você redefiniu uma sequência de uma sequência manual chamada anteriormente no código. Isso deixa os seguintes bits no xml do storyboard.

<connections>
    <segue destination="85t-Z1-hxf" kind="show" identifier="ToOptions" action="showDetailViewController:sender:" id="gdZ-IX-KcN">
</connections>

Nota Bene Para visualizar o storyboard como xml; Clique com o botão direito do mouse no arquivo do storyboard e escolha Abrir como> Código-fonte . Para reverter, use Abrir como> Interface Builder - Storyboard

Para acomodar qualquer ação personalizada ao usar as instruções do storyboard, basta tocar em prepareForSegue e interceptar o controlador de exibição de destino e chamar qualquer método desse local. De qualquer forma, o efeito colateral desse pequeno bug (o bug é o fato de que, quando você redefine as seguições, elas não são configuradas corretamente em xml ~ ou seja, a ação permanece mesmo após a alteração das seguidas para uma que opera a partir de um UIView (ou UIControl) para um controlador de exibição de destino).

Infelizmente, a solução mais direta falha. Portanto, apenas remover o atributo xml da ação no Storyboard NÃO resolverá o problema. Em vez disso, é preciso simplesmente excluir e recriar as instruções no storyboard.

Quando recriado, o xml do storyboard não terá mais uma ação associada a segue específico e o Show será executado como um Push.

Amostra de XML para o segmento de exibição correto

  <connections>
    <segue destination="RbV-Au-WV9" kind="show" identifier="ToOptions" id="5dm-os-bcS"/>
  </connections>

Mitigação

Para evitar a recorrência, basta seguir as sequências não manuais do storyboard, se possível, usando o prepareForSegue para adicionar ações necessárias com base no controlador de exibição de destino. Ou, se você precisar misturar e combinar, tome as precauções para verificar se as etapas Mostrar não têm nenhuma ação anexada no xml do storyboard. Se você estiver lidando com projetos mais antigos, deve dar atenção especial ao código-fonte do Storyboard, pois descobri alguns problemas.

Tommie C.
fonte
3
Depois de horas, isso me salvou provavelmente algumas outras horas. Aqui está o que eu sugeriria com base no exposto acima: Abra o storyboard como código-fonte , pesquise kind = "show" e verifique se a linha contém algo como action = "showDetailViewController: sender:" ; se houver, exclua tudo da ação = até o fechamento " . Eu tenho um storyboard realmente grande e o seque afetado não continha esse parâmetro de ação, mas outra linha não relacionada. Depois que eu excluí a ação, todos os seques adaptáveis ​​funcionaram novamente conforme o esperado. Apenas excluir o seque afetado ' t trabalho.
Marcus
Isso me salvou também.
Adam Bardon
1
A exclusão do atributo action no XML funcionou para meu amigo.
Brent Royal-Gordon
me salvou também
Jimmy George Thomas
Excluído o atributo action no arquivo xml, e pronto, ele funciona. Nunca teria encontrado o problema sem este post.
Krizzzn
20

Como Scott Robertson comentou aqui , isso parece um bug no iOS 7.

Parece que no iOS 8 a transição é inferida em tempo de execução (comportamento correto), enquanto no iOS 7 a transição é inferida em tempo de design (comportamento de buggy).

A solução mais simples é adicionar um controlador de navegação não utilizado ao storyboard e vinculá-lo para que o controlador de exibição em questão faça parte desse controlador de navegação. Na verdade, você não precisa instanciar o controlador de navegação, você só precisa do controlador de exibição com erros para saber se ele está incorporado a um controlador de navegação.

Nota: Simular uma barra de navegação não é suficiente para esses propósitos; você deve realmente ter um controlador de navegação em sua pilha de envio.

Para reproduzir o erro:

  1. Crie um novo storyboard que use classes de tamanho.
  2. Crie dois controladores de exibição (sem controladores de navegação).
  3. Faça o primeiro controlador de exibição mostrar o segundo controlador de exibição por meio de um Show (por exemplo, Push) segue vinculado a um botão, por exemplo.
  4. No código, mostre o primeiro controlador de exibição, mas incorpore-o em um controlador de navegação por meio do initWithRootViewController:método
  5. Execute o aplicativo no iOS 7.
  6. Toque no botão que deve executar o empurrão.
  7. Você obterá uma transição modal em vez de um push no iOS 7. No iOS 8, você obterá o comportamento correto de push.

insira a descrição da imagem aqui

Para corrigir o erro:

  1. Adicione um controlador de navegação ao storyboard e defina o primeiro controlador de visualização como o controlador de visualização raiz. (Nota: adicionar o segundo como o controlador de visualização raiz NÃO corrigirá esse erro.)
  2. Dê a ele um identificador de lixo eletrônico para suprimir o aviso de que o controlador de navegação está inacessível e para documentar para si mesmo que ele existe apenas como uma solução alternativa. (por exemplo workaround for show segues in iOS 7).

insira a descrição da imagem aqui

Observe como o controlador de navegação foi adicionado na segunda figura e como ele não possui nenhuma flecha de entrada (ou seja, não há como instancia-lo além de usar o identificador do controlador de exibição).

Sensível
fonte
1
Graças, o truque com o NavigationController fez isso por mim quando estou Trocar a raiz NavigationControllers ViewController-Stack
Peter Pint
1
Melhor solução. Obrigado
Илья Голованов
13

Sei que estou atrasado, mas queria compartilhar o que aprendi. Na verdade, isso é um bug e ainda está presente hoje (18/12/2014).

Eu escrevi um artigo sobre isso aqui .

É facilmente reproduzível; no iOS8 funcionará bem e até no iOS7.x, desde que você não insira um controlador de exibição programaticamente na pilha antes de chamar o Showsegue.

Se você empurrar apenas para a pilha usando conexões de storyboard, ele funcionará; mas, aparentemente, se você enviar via código de alguma forma, a navigationControllerpropriedade do envio UIViewControllerserá nile, quando você o chamar Show, assumirá um modal porque não há navegação para controlar a pilha.

Somente a solução alternativa até agora não é enviada por código (não é viável) ou usa o agora descontinuado Push.

Arquivei um radar (link no artigo). Sinta-se à vontade para arquivar duplicatas com a esperança de que a Apple resolva esse problema.

esttorhe
fonte
3
Esse foi exatamente o meu problema, obrigado! usar push obsoleto parece ser a solução mal menor nesse caso.
Moshe Gottlieb
Outra solução alternativa é adicionar um controlador de navegação (não utilizado) ao storyboard. Veja stackoverflow.com/questions/24184003/…
Sensuous
Nop! Está acontecendo aqui e a causa não é um empurrão programaticamente. No meu caso Show, realizo um segue, e no segundo Showsegue é apresentado de forma modal, Solution?
Frade
@Frade, você pode criar um link para um repositório no Github, onde isso é reproduzível? Você está executando em qual versão do iOS?
esttorhe
projeto particular .. Isso acontece ao tentar executar um (segundo) Showde um viewController no iOS 7
Frade
2

Eu tive o mesmo problema com segues no Xcode 7 e iOS 7.1.2. Mostrar segues (novo recurso do iOS 8) funciona como segues modais no iOS 7 e não permite que você coloque seus View Controllers na pilha do Navigation Controller ao definir o tipo de segue com o Xcode no Storyboard. É por isso que seu self.navigationController retornará nulo, porque o View Controller não foi enviado à pilha e você não pode abri-lo.

Não entendo por que a Apple não adicionou nenhuma notificação para este caso no Xcode quando você precisa que o aplicativo funcione no iOS 7. Eles dizem que o método Push está obsoleto, mas o Show não funciona corretamente no iOS 7.

O que eu fiz para resolver o problema:

Eu criei a classe MYShowSegue com .h

#import <UIKit/UIKit.h>

@interface MYShowSegue : UIStoryboardSegue

@end

E arquivo .m com apenas um método de execução :

#import "MYShowSegue.h"

@implementation MYShowSegue

- (void) perform {

    if ([[[self sourceViewController] navigationController] respondsToSelector:@selector(showViewController:sender:)]) {

        id sender = nil;
        [[[self sourceViewController] navigationController] showViewController:[self destinationViewController] sender:sender];
    }else{

        [[[self sourceViewController] navigationController] pushViewController:[self destinationViewController] animated:YES];
    }
}

@end

Do que você precisa definir um tipo personalizado para cada segue no seu Storyboard e selecionar uma nova classe para ele, no meu caso era MYShowSegue.

Exemplo de segmento personalizado

Esta solução ajudará você a obter um suporte completo de seus aplicativos para iOS 7, eles usarão o método pushViewController para enviar suas Views e para o iOS 8,9 etc. suas seguidas funcionarão com o novo método (iOS 8) showViewController

Não se esqueça de fazer o mesmo com todos os seus seguidores no seu Storyboard.

Igor Tikhonov
fonte
Solução Nice - trabalhou para mim (em vez de adicionar um controlador de navegação "não utilizado" ...
Laurenz Glück
1

Isso ainda está acontecendo no iOS 10.x

Excluir e reinstalar segues não resolveu nada para mim:

Problema: A funcionalidade exigida foi de 7 passos, que funcionam apenas como 'push' (na verdade, um detalhe do programa), mas, na verdade, apenas os primeiros passos que adicionei foram enviados, os outros se comportariam de maneira modal. Isso ocorre apesar do Interface Builder descrever cada uma das etapas de forma idêntica.

Solução: tive que adicionar a ação às 6 etapas que não a possuíam.

XML do Storyboard original

<connections>
  <segue destination="tIr-4a-WfZ" kind="showDetail" identifier="A" action="showViewController:sender:" id="8yd-Ne-7KA"/>
  <segue destination="4mB-YE-5dM" kind="showDetail" identifier="B" id="Uod-JC-786"/>
  <segue destination="Qh5-bJ-KcE" kind="showDetail" identifier="C" id="3PW-nV-hWl"/>
  <segue destination="EI6-f4-QBB" kind="showDetail" identifier="D" id="WUK-ju-KDm"/>
  <segue destination="nTz-N4-fpW" kind="showDetail" identifier="E" id="Id6-bW-Huc"/>
  <segue destination="JEp-CH-6dW" kind="showDetail" identifier="F" id="G0L-XW-7f4"/>
  <segue destination="AET-S1-O6h" kind="showDetail" identifier="G" id="3NK-93-wTy"/>
</connections>

Eu mudei isso adicionando showViewController: remetente

<connections>
  <segue destination="tIr-4a-WfZ" kind="showDetail" identifier="A" action="showViewController:sender:" id="8yd-Ne-7KA"/>
  <segue destination="4mB-YE-5dM" kind="showDetail" identifier="B" action="showViewController:sender:" id="Uod-JC-786"/>
  <segue destination="Qh5-bJ-KcE" kind="showDetail" identifier="C" action="showViewController:sender:" id="3PW-nV-hWl"/>
  <segue destination="EI6-f4-QBB" kind="showDetail" identifier="D" action="showViewController:sender:" id="WUK-ju-KDm"/>
  <segue destination="nTz-N4-fpW" kind="showDetail" identifier="E" action="showViewController:sender:" id="Id6-bW-Huc"/>
  <segue destination="JEp-CH-6dW" kind="showDetail" identifier="F" action="showViewController:sender:" id="G0L-XW-7f4"/>
  <segue destination="AET-S1-O6h" kind="showDetail" identifier="G" action="showViewController:sender:" id="3NK-93-wTy"/>
</connections>
Damo
fonte