Eu tenho um problema e o descrevo abaixo.
Estou usando UIViewControllerContextTransitioning
para transições personalizadas.
Eu tenho 2 controladores de visualização, o primeiro controlador de visualização e o segundo controlador de visualização.
Agora, quero adicionar o segundo controlador de visualização no primeiro controlador de visualização com uma animação. Eu consegui isso, agora o segundo controlador de exibição é transparente, então podemos ver o primeiro controlador de exibição abaixo do segundo controlador de exibição.
Mas não consigo ver o primeiro controlador de visualização e só consigo ver a tela preta abaixo do segundo controlador de visualização.
-(void)animateTransition:(id<UIViewControllerContextTransitioning>)transitionContext{
self.transitionContext = transitionContext;
if(self.isPresenting){
[self executePresentationAnimation:transitionContext];
}
else{
[self executeDismissalAnimation:transitionContext];
}
}
-(void)executePresentationAnimation:(id<UIViewControllerContextTransitioning>)transitionContext{
UIView* inView = [transitionContext containerView];
UIViewController* toViewController = [transitionContext viewControllerForKey:UITransitionContextToViewControllerKey];
UIViewController* fromViewController = [transitionContext viewControllerForKey:UITransitionContextFromViewControllerKey];
CGRect offScreenFrame = inView.frame;
offScreenFrame.origin.y = inView.frame.size.height;
toViewController.view.frame = offScreenFrame;
toViewController.view.backgroundColor = [UIColor clearColor];
fromViewController.view.backgroundColor = [UIColor clearColor];
inView.backgroundColor = [UIColor clearColor];
[inView insertSubview:toViewController.view aboveSubview:fromViewController.view];
// [inView addSubview:toViewController.view];
CFTimeInterval duration = self.presentationDuration;
CFTimeInterval halfDuration = duration/2;
CATransform3D t1 = [self firstTransform];
CATransform3D t2 = [self secondTransformWithView:fromViewController.view];
[UIView animateKeyframesWithDuration:halfDuration delay:0.0 options:UIViewKeyframeAnimationOptionCalculationModeLinear animations:^{
[UIView addKeyframeWithRelativeStartTime:0.0f relativeDuration:0.5f animations:^{
fromViewController.view.layer.transform = t1;
}];
[UIView addKeyframeWithRelativeStartTime:0.5f relativeDuration:0.5f animations:^{
fromViewController.view.layer.transform = t2;
}];
} completion:^(BOOL finished) {
}];
[UIView animateWithDuration:duration delay:(halfDuration - (0.3*halfDuration)) usingSpringWithDamping:0.7f initialSpringVelocity:6.0f options:UIViewAnimationOptionCurveEaseIn animations:^{
toViewController.view.frame = inView.frame;
} completion:^(BOOL finished) {
[self.transitionContext completeTransition:YES];
}];
}
Quando [self.transitionContext completeTransition:YES];
chamado, de repente o primeiro controlador de visualização desaparece e uma tela preta é exibida abaixo do segundo controlador de visualização.
Alguém tem ideia? Obrigado.
fonte
modalPresentationStyle = UIModalPresentationFullScreen
. É claro que você ainda terá sua animação de transição personalizada.Acho que o raciocínio por trás disso deve ser explicado melhor.
A visualização desaparece porque você retira a visualização do controlador de visualização de apresentação de seu local original (hierarquia de visualização), coloca-a dentro da containerView que seu animador fornece, mas nunca a retorna de volta após o término da animação. Assim, a visão do controlador de visão é removida com sua super visão (containerView) da janela completamente.
No iOS 7, o sistema sempre retornava as visualizações dos controladores de visualização que estão envolvidos na apresentação (apresentando e apresentados) para seus lugares originais após a transição terminar a animação automaticamente. Isso não acontece mais com alguns estilos de apresentação no iOS 8.
A regra é muito simples: o animador só deve manipular a visualização do controlador de visualização de apresentação se a visualização desse controlador de visualização for ser ocultada (removida da hierarquia de visualização) completamente no final da transição . Em outras palavras, isso significa que após a conclusão da animação da apresentação inicial, apenas a visualização do controlador de visualização apresentada estará visível e não a visualização do controlador de visualização presente. Por exemplo, se você definir a opacidade da visualização do controlador de visualização apresentada para 50% e usar UIModalPresentationFullScreen, você não será capaz de ver a visualização do controlador de visualização apresentada abaixo da apresentada, mas se você usar UIModalPresentationOverFullscreen - você o fará (o
shouldRemovePresentersView
método de UIPresentationController é responsável por especificar isso).Por que não permitir que o animador manipule a visualização do controlador de visualização de apresentação o tempo todo? Em primeiro lugar, se a visualização do controlador da visualização de apresentação vai permanecer visível após o término da animação durante todo o ciclo de vida da apresentação, não há necessidade de animá-la - ela apenas permanece onde está. Em segundo lugar, se a propriedade desse controlador de visualização for transferida para o controlador de apresentação, o controlador de apresentação provavelmente não saberá como fazer o layout dessa visualização do controlador de visualização quando necessário, por exemplo, quando a orientação muda, mas o proprietário original do controlador de visualização de apresentação sabe .
No iOS 8, o
viewForKey:
método foi introduzido para obter visualizações que o animador manipula. Primeiro, ajuda a seguir a regra descrita acima, retornando nil sempre que o animador não deve tocar a vista. Em segundo lugar, pode retornar uma visão diferente para o animador animar. Imagine que você está implementando uma apresentação semelhante a um formulário. Neste caso, você deseja adicionar alguma sombra ou decoração ao redor da visualização do controlador de visualização apresentado. Em vez disso, o animador animará aquela decoração e a visualização do controlador de visualização apresentada será filha da decoração.viewControllerForKey:
não desaparece, ele ainda pode ser usado se um acesso direto aos controladores de visualização for necessário, mas o animador não deve fazer suposições sobre as visualizações que precisa animar.Há várias coisas que você pode fazer para corrigir corretamente um problema com o desaparecimento da visualização do controlador de visualização de apresentação ao colocá-lo explicitamente dentro da visualização do contêiner do animador:
Se não precisar animar a visualização do controlador de visualização de apresentação, use
viewForKey:
para obter visualizações para animar em vez de alcançar as visualizações do controlador de visualização diretamente.viewForKey:
pode retornar nulas ou até mesmo visões completamente diferentes.Se você deseja animar a visualização dos controladores de visualização de apresentação, você deve considerar o uso de
UIModalPresentationFullScreen
estilo ou continuar usandoUIModalPresentationCustom
e implementar sua própria subclasse de UIPresentationController comshouldRemovePresentersView
retornoYES
. Na verdade, a implementação deste método é a principal diferença entre os controladores de apresentação internos definidos por estilosUIModalPresentationFullScreen
e,UIModalPresentationCustom
além do fato de que o último permite que você use controladores de apresentação personalizados.Em todos os outros casos raros, você terá que retornar a visualização do controlador de visualização de apresentação ao seu local original, conforme outras respostas sugeridas.
fonte
viewControllerForKey:
'sview
s apenas quandoviewForKey:
retorna nil, e eu ainda tive que re-adicioná-lo para a janela manualmente. Você tem um exemplo de código funcionando sem essa solução alternativa?viewForKey:
retornar nil, com certeza você terá que adicionar novamente a visualização do controlador de visualização de apresentação à janela se removê-la em seu animador. No caso de viewForKey retornar a visão real do controlador de visão, é seguro mover essa visão porque o UIKit a moveria de volta para sua posição original após o ciclo de vida da apresentação terminar.No iOS 8, você deve manipular as visualizações retornadas por, em
viewForKey:
vez da.view
propriedade dos controladores de visualização retornados porviewControllerForKey:
. Isso não está muito claro na documentação beta, mas se você olhar a fonte de UIViewControllerTransitioning.h, verá este comentário acimaviewControllerForKey:
:Portanto, em vez de ajustar os quadros etc. de
toViewController.view
, use o valor de retorno de[transitionContext viewForKey:UITransitionContextToViewKey]
.Se seu aplicativo precisa ser compatível com iOS7 e / ou Xcode 5, você pode usar um método de categoria simples no UIViewController como o seguinte:
Em seguida, pegue seu
toViewController
efromViewController
como de costume, mas obtenha as visualizações usando[toViewController viewForTransitionContext:transitionContext]
.Editar: parece haver um bug, onde a visualização do controlador de visualização de apresentação é nula quando retornada
viewForKey
, o que impede você de fazer transições modais que animam a visualização de apresentação (como deslizar para fora ou virar na horizontal). Registrei um bug para iOS8 em rdar: // 17961976 ( http://openradar.appspot.com/radar?id=5210815787433984 ). Veja também o projeto de amostra em http://github.com/bcherry/TransitionBugEdit 2: Obrigado a graveley pela sugestão, usar UIModalPresentationFullScreen corrige o problema. Talvez isso não seja um bug. A Apple pode pretender que UIModalPresentationCustom modifique apenas a visualização do modal de entrada. Se você deseja modificar a exibição de saída, você precisa garantir a apresentação em tela inteira da nova exibição? Em qualquer caso, você deve usar
viewForKey
e UIModalPresentationFullScreen.fonte
manipulating
as visualizações dos VCs ou não ...viewForKey
bug no GM também. Outros também? Você encontrou uma solução alternativa razoável para isso?- viewForKey
// viewForKey: pode retornar nil, o que indica que o animador não deve manipular a visualização do controlador de visualização associado. Retornarnil
não é um bug.viewForKey
retorna a partir da visualização e a partir da visualização. Portanto, talvez seja intencional que ele retorne nulo para UIModalPresentationCustom. Estou atualizando meu relatório de bug e postarei aqui se receber uma resposta da Apple sobre isso.Não definir
modalPresentationStyle
como UIModalPresentationCustom corrigiu o problema para mim.Em outras palavras, deixar o padrão de UIModalPresentationFullScreen em vez de especificar UIModalPresentationCustom corrigiu o problema de exibição de desaparecimento. Observe que o protocolo UIViewControllerTransitioningDelegate ainda parece ser seguido, mesmo quando o deixa como padrão. Se bem me lembro, uma vez UIModalPresentationCustom era um requisito.
Funciona até agora, tentei isso apenas para animações não interativas.
fonte
viewForKey:
vez de.view
noviewControllerForKey:
corrige todos os problemas para mim.Achei esta resposta extremamente útil em um tópico relacionado de Lefteris: https://stackoverflow.com/a/27165723/3709173
Resumindo:
+1 em sua transição personalizada, não adicione toView quando a animação de dispensa estiver acontecendo.
Demonstrado aqui:
https://www.dropbox.com/s/7rpkyamv9k9j18v/CustomModalTransition.zip?dl=0 sem quaisquer hacks! é como mágica! :)
fonte
No iOS 8, você precisa criar um UIPresentationController e implementar o método abaixo, no UIViewControllerTransitioningDelegate.
Para mais informações, assista ao vídeo WWDC 2014:
https://developer.apple.com/videos/wwdc/2014/?include=228
Há também um código de amostra da WWDC chamado "LookInside: Adaptabilidade dos controladores de apresentação e objetos de animação personalizados", que você pode baixar da página de código de amostra da WWDC 2014.
Pode ser necessário alterar um pouco o código de amostra. O método de inicialização UIPresentationController mudou para:
Antes fazia apresentações e depois era apresentado. Basta trocá-los e deve funcionar.
fonte
em vez de [inView insertSubview: toViewController.view aboveSubview: fromViewController.view]; basta adicionar: [inView addSubview: toViewController.view];
Você pode ver um exemplo aqui: link e funciona no iOS 7 e iOS 8
fonte
Aqui está uma versão Objective C da correção de Ash.
Tive que trocar a ordem e chamar o método [transactionContext completeTransition:] depois de adicionar a visualização de volta para conseguir apresentar um novo controlador de visualização do bloco de conclusão de dispensa de outro controlador de visualização para funcionar corretamente.
Não sei se isso vai consertar para todos, mas funciona no meu aplicativo. Felicidades!
fonte
Achei que funcionou bem para Obj-C:
Parece funcionar bem em iOS7 e iOS8.
fonte
Descobri que
viewForKey:UITransitionContextToViewKey
retorna zero em iOS8. Portanto, se for nulo, pego a visualização do controlador de visualização 'para'.No entanto, isso parece resultar na visualização 'para' não ser movida do contêiner para a janela quando
completeTransition:YES
é chamada. Portanto, seviewForKey:UITransitionContextToViewKey
retorna nil, eu caio paratoVC.view
e mantenho o controle do fato de que ele retornou nil e, após a conclusão, movo-o para a supervisão inicial do contêiner (que por acaso é a janela).Portanto, este código funciona no iOS7 e também no iOS8, e deve funcionar no iOS9 também, mesmo que eles consertem ou não.
fonte
Descobri que esse bug (e muitos mais!) Desaparece se você definir
modalPresentationStyle = UIModalPresentationFullScreen
. É claro que você ainda terá sua animação de transição personalizada.fonte
Eu também fiquei preso nessa questão. Eu estava tentando criar uma transição personalizada com um fundo semitransparente onde eu ainda pudesse ver o controlador de visualização de onde estava vindo, mas só consegui um fundo preto. Descobri que a resposta de Mark Aron neste tópico me ajudou, mas está escrito em Objective C, então aqui está uma versão Swift 3 dessa resposta que testei para iOS 9 e iOS 10:
Crie uma subclasse de UIPresentationController. Substitua shouldRemovePresentersView por false da seguinte forma:
No local em que você está instanciando o novo controlador de visualização e definindo seu delegado de transição, indique que deseja que ele mostre um estilo de apresentação modal personalizado da seguinte maneira:
Agora substitua o método presentationController de seu UIViewControllerTransitioningDelegate e retorne seu UIPresentationController personalizado. Eu tive o meu como uma extensão da minha classe atual:
Outra coisa a ser observada é que você não deve tentar fazer referência a fromView na classe presentAnimator. Isso será nulo e você obterá um erro em tempo de execução. Além disso, se você implementar coisas como coisas, você obterá sua transição personalizada com sua animação e um fundo semitransparente, se fizer um.
fonte
presentationController(forPresented presented UIViewController,...
porque a API anterior do swift não incomodava o compilador, mas não era chamada.Depois de encontrar esse problema, fiquei muito confuso, porque escrevi algo quase idêntico não muito tempo atrás que funcionou bem. Vim aqui em busca de respostas para encontrar soluções que pareçam muito hackeadas e não entendam a causa raiz ... na verdade, é muito fácil de consertar.
Algumas respostas mencionam a mudança
modalPresentationStyle
para.overFullScreen
. Isso está correto,.overCurrentContext
funcionaria também. Isso é esperado, e os documentos de comportamento da Apple. Mas por que isso não está funcionando para todos? Por que todo o código hackeado, e combinações disso com outra coisa, e coisas malucas que você não deveria estar fazendo?Acontece que você precisa definir o estilo de apresentação ANTES DO VIEW LOADS . Não após. Faça isso no init, ou no controlador anterior, ou como quiser - contanto que seja antes de carregar a visualização.
fonte
.overCurrentContext
antes de carregar a visualização (no doinit
controlador de visualização) e o problema ainda aconteceUsar o novo UIModalPresentationOverCurrentContext corrigiu para mim. Minha transição original no iOS 7 foi apenas para ter um fundo desfocado da visão abaixo do modal.
fonte
Ok, pessoal, acho que resolvi um caso em que 'um animador funcional' para de funcionar corretamente quando você constrói um aplicativo no iOS 13 e superior.
Env Xcode 11.1, iOS 13.1
Problema
O que eu quero fazer é muito simples: eu tenho uma visão de coleção, quando uma célula é tocada, ela segue para uma visão de detalhes. Em vez de usar o estilo padrão chato de 'apresentar modalmente', quero torná-lo mais interessante, então escrevi um animador para a transição do controlador de visualização.
Eu configurei a segue no IB arrastando e soltando da minha coleção VC para o detalhe VC. O estilo de segue é 'Apresentar modalmente' e a apresentação é definida como 'Tela inteira'.
Quando mostra a visualização de detalhes, tudo funciona conforme o esperado. No entanto, quando eu dispenso a visualização de detalhes e volto para a visualização de coleção, só consigo ver a visualização de detalhes animada, a visualização de coleção simplesmente desaparece. Eu cutuquei aqui e ali e tenho algumas descobertas
1. Logo após a linha a seguir ser chamada a partir da função 'animateTransition ()', a visualização da coleção é retomada e exibida
2. Contanto que a visualização de detalhes não cubra totalmente a visualização da coleção, a visualização da coleção não desaparecerá quando voltar da visualização de detalhes
Solução
Para ser honesto, sei pouco sobre como funciona a transição animada. Portanto, só posso acompanhar este post e o outro , experimentar cada uma das respostas. Infelizmente, nenhum deles funciona para mim. Finalmente, cheguei a um ponto em que a única coisa que posso ajustar é o estilo de apresentação do segue no IB (o que eu deveria ter feito desde o início). Quando defino a apresentação para 'Tela inteira', um milagre acontece e meu problema é resolvido. A visualização de detalhes pode ser exibida em tela inteira com animação e, quando for descartada, posso ver a visualização da coleção como plano de fundo e a visualização de detalhes animada.
Então, mais uma descoberta ao longo da estrada
3. Para se referir a 'toView' e 'fromView', ambos os métodos a seguir funcionam
Indiretamente:
Diretamente:
Mas quando mudei o estilo segue para 'Over Full Screen', a forma direta retorna 'nil' para 'toView' e 'fromView' e funciona apenas indiretamente, este problema também é mencionado em outro post , então acho que vale a pena para postar minha pequena descoberta aqui.
Espero que isso seja útil para alguém no futuro.
fonte
Eu estava tendo o mesmo problema ao descartar um controlador de visualização de conteúdo.
Meu aplicativo tem este controlador de visualização pai mostrando um controlador de visualização filho (apresentando vc) modalmente. Então, quando uma subvisualização no childVC é tocada, ela mostra outro vc (que estou chamando de controlador de visualização de conteúdo (apresentado vc))
Meu problema é que, ao descartar o contentVC (agora o VC de apresentação), ele deve ir para o VC filho (agora o VC apresentado), mas assim que minha transição personalizada termina, o childVC desaparece repentinamente, mostrando o VC pai.
O que fiz para resolver esse problema foi
.modalPresentationStyle
do childVC apresentado por parentVC do padrão.automatic
para.fullscreen
..modalPresentationStyle
de contentVC para.fullscreen
também.Isso resolve o problema. mas não mostrará o VC do seu filho como uma folha de estilo de cartão sobre o CV pai (ao usar
.overCurrentContext
ou automático), que é novo no iOS 13.Adoraria saber se há alguma solução que retenha a folha de estilo do cartão para o childVC quando apresentada pelos pais.
fonte
adiciona um controlador de visualização como filho de outro controlador de visualização.
verifique e me avise.
fonte