Eu tenho um aplicativo baseado em navegação e quero alterar a animação das animações push e pop. Como eu faria isso?
Editar 2018
Existem muitas respostas para essa pergunta e já faz um bom tempo que eu escolhi a resposta para o que considero mais relevante agora. Se houver alguém que pense de outra forma, por favor me avise nos comentários
Respostas:
Para 2019, a "resposta final!"
Preâmbulo:
Digamos que você seja novo no desenvolvimento do iOS. Confusamente, a Apple fornece duas transições que podem ser usadas facilmente. São eles: "crossfade" e "flip".
Mas é claro que "crossfade" e "flip" são inúteis. Eles nunca são usados. Ninguém sabe por que a Apple forneceu essas duas transições inúteis!
Assim:
Digamos que você queira fazer uma transição comum e comum, como "slide". Nesse caso, você tem que fazer uma quantidade enorme de trabalho! .
Esse trabalho é explicado neste post.
Só para repetir:
Surpreendentemente: com o iOS, se você deseja as transições diárias mais simples e comuns (como um slide comum), é necessário todo o trabalho de implementar uma transição personalizada completa .
Veja como fazê-lo ...
1. Você precisa de um costume
UIViewControllerAnimatedTransitioning
Você precisa de um bool de sua preferência
popStyle
. (Ele está aparecendo ou aparecendo?)Você deve incluir
transitionDuration
(trivial) e a chamada principal,animateTransition
De fato, você deve escrever duas rotinas diferentes para dentro
animateTransition
. Um para o empurrão e outro para o pop. Provavelmente nomeie-osanimatePush
eanimatePop
. No interioranimateTransition
, basta ramificarpopStyle
para as duas rotinasO exemplo abaixo faz uma simples mudança / remoção
Em suas
animatePush
eanimatePop
rotinas. Você deve obter o "from view" e o "to view". (Como fazer isso, é mostrado no exemplo de código.)e você deve
addSubview
acessar a nova visualização "para".e você deve ligar
completeTransition
no final do seu animeAssim ..
E depois ...
2. Use-o no seu controlador de exibição.
Nota: estranhamente, você só precisa fazer isso no "primeiro" controlador de exibição. (Aquele que está "embaixo".)
Com o que você coloca no topo , não faça nada . Fácil.
Então sua classe ...
torna-se...
É isso aí.
Empurre e pop exatamente como normal, sem alterações. Para impulsionar ...
e para abri-lo, você pode, se quiser, fazer isso na próxima tela:
Ufa.
3. Aproveite também as outras respostas nesta página que explicam como substituir o AnimatedTransitioning
Vá até @AlanZeino e @elias responda para mais discussões sobre como fazer
AnimatedTransitioning
nos aplicativos para iOS hoje em dia!fonte
animatePush
eanimatePop
são .. as duas direções diferentes!Eu fiz o seguinte e funciona bem .. e é simples e fácil de entender ..
E a mesma coisa para empurrar ..
Versão Swift 3.0:
fonte
Animated:NO
peça é vital. SeYES
aprovada, as animações se misturam e causam efeitos engraçados.setViewControllers:
É assim que eu sempre consegui concluir esta tarefa.
Para Push:
Para Pop:
Ainda recebo muito feedback disso, então vou atualizá-lo para usar blocos de animação, que é a maneira recomendada pela Apple de fazer animações de qualquer maneira.
Para Push:
Para Pop:
fonte
super
porself.navigationController
UIViewController
subclasse um nome sem a parte "ViewController". Este nome é mais apropriado para o UIView.para empurrar
para pop
fonte
Resposta @Magnus, só então para Swift (2.0)
Algumas notas laterais:
Você pode fazer isso também com o Segue, basta implementar isso em
prepareForSegue
oushouldPerformSegueWithIdentifier
. No entanto , isso também manterá a animação padrão. Para corrigir isso, você deve ir ao storyboard, clicar no Segue e desmarcar a caixa 'Animates'. Mas isso limitará seu aplicativo para o IOS 9.0 e superior (pelo menos quando o fiz no Xcode 7).Ao fazer um segue, as duas últimas linhas devem ser substituídas por:
Mesmo que eu defina falso, isso meio que o ignora.
fonte
Lembre-se de que em Swift , extensão são definitivamente seus amigos!
fonte
Usar chamadas privadas é uma péssima idéia, pois a Apple não aprova mais os aplicativos que fazem isso. Talvez você possa tentar o seguinte:
fonte
-pushViewController:transition:forceImmediate:
que seria uma má idéia.Como esse é o melhor resultado no Google, pensei em compartilhar o que considero a maneira mais sensata; que é usar a API de transição do iOS 7+. Eu implementei isso no iOS 10 com o Swift 3.
É bem simples combinar isso com como
UINavigationController
anima entre dois controladores de exibição, se você criar uma subclasseUINavigationController
e retornar uma instância de uma classe que esteja em conformidade com oUIViewControllerAnimatedTransitioning
protocolo.Por exemplo, aqui está o meu
UINavigationController
subclasse:Você pode ver que eu defino o valor
UINavigationControllerDelegate
em si e, em uma extensão da minha subclasse, implemento o método emUINavigationControllerDelegate
que permite retornar um controlador de animação personalizado (por exemplo,NavigationControllerAnimation
). Este controlador de animação personalizado substituirá a animação de estoque para você.Você provavelmente está se perguntando por que eu passo a operação para o
NavigationControllerAnimation
instância por meio de seu inicializador. Eu faço isso para que naNavigationControllerAnimation
implementação doUIViewControllerAnimatedTransitioning
protocolo eu saiba qual é a operação (ou seja, 'push' ou 'pop'). Isso ajuda a saber que tipo de animação devo fazer. Na maioria das vezes, você deseja executar uma animação diferente, dependendo da operação.O resto é bastante padrão. Implemente as duas funções necessárias no
UIViewControllerAnimatedTransitioning
protocolo e anime da maneira que desejar:É importante lembrar que, para cada tipo diferente de operação (por exemplo, 'push' ou 'pop'), os controladores de e para a visualização serão diferentes. Quando você estiver em uma operação de envio, o controlador para visualizar será o que está sendo enviado. Quando você está em uma operação pop, o controlador de visualização será aquele que está sendo transferido e o controlador de visualização será o que está sendo exibido.
Além disso, o
to
controlador de exibição deve ser adicionado como uma subvisão docontainerView
no contexto de transição.Quando sua animação terminar, você deve ligar
transitionContext.completeTransition(true)
. Se você estiver fazendo uma transição interativa, será necessário retornar dinamicamenteBool
acompleteTransition(didComplete: Bool)
, dependendo se a transição estiver concluída no final da animação.Finalmente ( leitura opcional ), você pode querer ver como eu fiz a transição em que estava trabalhando. Esse código é um pouco mais hacky e eu o escrevi rapidamente, então não diria que é um ótimo código de animação, mas ainda mostra como fazer a parte da animação.
A minha foi uma transição realmente simples; Eu queria imitar a mesma animação que o UINavigationController normalmente faz, mas, em vez da animação 'próxima página por cima', eu queria implementar uma animação 1: 1 do antigo controlador de exibição ao mesmo tempo que a nova exibição controlador aparece. Isso tem o efeito de fazer com que os dois controladores de exibição pareçam estar presos um ao outro.
Para a operação push, é necessário primeiro definir a
toViewController
origem da vista da tela no eixo x fora da tela, adicionando-a como subvisão docontainerView
, animando-a na tela, definindo-origin.x
a como zero. Ao mesmo tempo, animar afromViewController
vista de fora definindoorigin.x
-a na tela:A operação pop é basicamente o inverso. Adicione a
toViewController
como uma subvisão decontainerView
e animarfromViewController
para a direita como você anima natoViewController
da esquerda:Aqui está uma essência com todo o arquivo rápido:
https://gist.github.com/alanzeino/603293f9da5cd0b7f6b60dc20bc766be
fonte
Existem UINavigationControllerDelegate e UIViewControllerAnimatedTransitioning lá, você pode alterar a animação para o que quiser.
Por exemplo, isso é animação pop vertical para VC:
}
E depois
Tutorial útil https://www.objc.io/issues/5-ios7/view-controller-transitions/
fonte
Com base na resposta atualizada para o swift 4
jordanperry
Para empurrar
UIViewController
Para Pop
fonte
Aqui está como eu fiz o mesmo no Swift:
Para Push:
Para Pop:
Na verdade, fiz isso de maneira um pouco diferente para algumas das respostas acima - mas como sou novo no desenvolvimento do Swift, pode não estar certo. Eu substituí
viewWillDisappear:animated:
e adicionei o código pop lá:fonte
Resposta de @Luca Davanzo no Swift 4.2
fonte
Recentemente, eu estava tentando fazer algo semelhante. Decidi que não gostava da animação deslizante do UINavigationController, mas também não queria fazer as animações que o UIView oferece para você como curl ou algo assim. Eu queria fazer um cross fade entre as vistas quando empurro ou pop.
O problema envolve o fato de que a visualização está literalmente removendo ou exibindo uma sobre a parte superior da atual, para que o desbotamento não funcione. A solução que encontrei envolveu pegar minha nova visão e adicioná-la como uma sub-visão à visão superior atual na pilha do UIViewController. Eu o adiciono com um alfa de 0 e depois faço um crossfade. Quando a sequência de animação termina, empurro a vista para a pilha sem a animar. Volto ao antigo topView e limpo as coisas que eu havia mudado.
É um pouco mais complicado que isso, porque você tem os itens de navegação que precisa ajustar para fazer a transição parecer correta. Além disso, se você fizer uma rotação, precisará ajustar os tamanhos dos quadros à medida que adiciona as visualizações como subvisões para que elas apareçam corretamente na tela. Aqui está um pouco do código que eu usei. Subclassifiquei o UINavigationController e substitui os métodos push e pop.
Como mencionei no código, sempre tenho um item de botão de barra esquerdo, portanto não verifico se é nulo antes de colocá-lo na matriz que passo como contexto para o representante da animação. Se você fizer isso, convém fazer essa verificação.
O problema que encontrei foi que, se você travar no método delegado, ele não travará o programa. Isso apenas impede o delegado de concluir, mas você não recebe nenhum tipo de aviso.
Então, como eu estava fazendo minha limpeza nessa rotina de delegados, estava causando um comportamento visual estranho, pois não estava terminando a limpeza.
O botão voltar criado por mim chama um método "goBack", e esse método chama apenas a rotina pop.
Além disso, aqui está minha rotina pop.
É praticamente isso. Você precisará de algum código adicional se desejar implementar rotações. Você precisará definir o tamanho do quadro de suas vistas que você adiciona como subvisões antes de mostrá-las. Caso contrário, você terá problemas em que a orientação é paisagem, mas a última vez que viu a vista anterior era em retrato. Então, você o adiciona como uma subvisualização e a desvanece, mas ele aparece como retrato; depois, quando exibimos sem animação, a mesma visualização, mas a que está na pilha, agora é paisagem. A coisa toda parece um pouco estranha. A implementação de rotação de todos é um pouco diferente, então não incluí meu código aqui.
Espero que ajude algumas pessoas. Procurei em todo o mundo algo assim e não encontrei nada. Eu não acho que essa seja a resposta perfeita, mas está funcionando muito bem para mim neste momento.
fonte
Agora você pode usar
UIView.transition
. Note issoanimated:false
. Isso funciona com qualquer opção de transição, pop, push ou pilha substituída.fonte
Usando a resposta da iJordan como inspiração, por que não simplesmente criar uma categoria no UINavigationController para usar em todo o aplicativo em vez de copiar / colar esse código de animação em todo o lugar?
UINavigationController + Animation.h
UINavigationController + Animation.m
Em seguida, basta importar o arquivo UINavigationController + Animation.h e chamá-lo normalmente:
fonte
É muito simples
fonte
Dê uma olhada no ADTransitionController , uma substituição do UINavigationController com animações de transição personalizadas (sua API corresponde à API do UINavigationController) que criamos no Applidium.
Você pode usar diferentes animações predefinidas para ações push e pop , como deslizar , Fade , Cube , Carrousel , Zoom e assim por diante.
fonte
Embora todas as respostas aqui sejam ótimas e a maioria funcione muito bem, existe um método um pouco mais simples que obtém o mesmo efeito ...
Para Push:
Para Pop:
fonte
Não conheço nenhuma maneira de alterar publicamente a animação de transição.
Se o botão "voltar" não for necessário, você deve usar os controladores de exibição modal para fazer as transições "empurrar de baixo" / "virar" / "desaparecer" / (≥3,2) "curvatura da página".
No lado privado , o método
-pushViewController:animated:
chama o método não documentado-pushViewController:transition:forceImmediate:
; portanto, se você deseja uma transição flip da esquerda para a direita, pode usarVocê não pode alterar a transição "pop" dessa maneira, no entanto.
fonte
Veja minha resposta a esta pergunta para uma maneira de fazê-lo em muito menos linhas de código. Esse método permite animar um pseudo- "Push" de um novo controlador de exibição da maneira que você quiser, e quando a animação é concluída, ele configura o Navigation Controller como se você tivesse usado o método Push padrão. Meu exemplo permite animar um slide-in da esquerda ou da direita. Código repetido aqui por conveniência:
fonte
No aplicativo de amostra, confira esta variação. https://github.com/mpospese/MPFoldTransition/
fonte
Apenas use:
fonte
Perceber que essa é uma pergunta antiga. Eu ainda gostaria de postar esta resposta, pois tive alguns problemas ao exibir várias
viewControllers
com as respostas propostas. Minha solução é subclassificarUINavigationController
e substituir todos os métodos pop e push.FlippingNavigationController.h
FlippingNavigationController.m:
fonte
Eu sei que esse tópico é antigo, mas pensei em colocar meus dois centavos. Você não precisa criar uma animação personalizada, existe uma maneira simples (talvez hacky) de fazê-lo. Em vez de usar push, crie um novo controlador de navegação, torne o novo controlador de visualização o controlador de visualização raiz desse controlador nav e, em seguida, apresente o controlador nav a partir do controlador nav original. O presente é facilmente personalizável com vários estilos e não é necessário criar uma animação personalizada.
Por exemplo:
E você pode alterar o estilo de apresentação como quiser.
fonte
Eu encontrei uma maneira levemente recursiva de fazer isso que funciona para meus propósitos. Eu tenho uma variável de instância BOOL que eu uso para bloquear a animação popping normal e substituir minha própria mensagem pop não animada. A variável é inicialmente definida como NÃO. Quando o botão Voltar é pressionado, o método delegado o define como SIM e envia uma nova mensagem pop não animada para a barra de navegação, chamando novamente o mesmo método delegado, desta vez com a variável definida como YES. Com a variável definida como YES, o método delegate a define como NO e retorna YES para permitir a ocorrência de pop não animado. Após o retorno da segunda chamada de delegado, terminamos novamente na primeira, onde NO é retornado, bloqueando o pop animado original! Na verdade, não é tão confuso quanto parece. Meu método shouldPopItem se parece com isso:
Funciona para mim.
fonte