“From View Controller” desaparece usando UIViewControllerContextTransitioning

105

Eu tenho um problema e o descrevo abaixo.

Estou usando UIViewControllerContextTransitioningpara 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.

NiravPatel
fonte

Respostas:

98

Eu estava tendo o mesmo problema aqui - parece um bug no iOS 8. Eu enviei um radar .

Usei o Reveal para inspecionar a hierarquia de visualizações depois que a tela escureceu. A chave UIWindowestá completamente vazia - nenhuma hierarquia de visualizações!

Revelado

Eu brinquei um pouco e parece que existe uma solução fácil, para casos simples. Você pode simplesmente adicionar novamente a toViewControllervisualização de como uma subvisualização da janela principal:

transitionContext.completeTransition(true)
UIApplication.sharedApplication().keyWindow!.addSubview(toViewController.view)

Eu verifiquei e a janela principal rootViewControllerainda está configurada corretamente, então tudo bem. Não tenho certeza do que aconteceria se você apresentasse seu controlador de dentro de um controlador modal já apresentado, portanto, para casos mais complexos, você terá que experimentar.

Sulco de Freixo
fonte
2
Eu também vi esse problema. O iOS 8 apresenta um novo método e chaves para acessar fromView e toView (Nota: controlador não de visualização) Parece que essas referências não são perdidas durante a transição. Você pode adicioná-los à visualização do contêiner como faria normalmente se os tivesse recuperado dos controladores de visualização.
tapi
1
Eu estava vendo uma estranheza semelhante ao iOS 8 ao tentar adicionar subvisualizações à visualização do meu controlador de navegação, em viewDidLoad. Adicionar novamente a visualização do navigationController à keyWindow pareceu funcionar, muito obrigado, Ash!
taber
1
Ainda estou vendo isso no GM (e essa correção ainda funciona). Os outros estão vendo o mesmo? Isso é apenas uma mudança na API?
rjkaplan
21
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.
Chris
1
Obrigado @AshFurrow. Boa solução alternativa até que seja corrigido!
kandelvijaya de
78

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 shouldRemovePresentersViewmé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:

  1. 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.

  2. Se você deseja animar a visualização dos controladores de visualização de apresentação, você deve considerar o uso de UIModalPresentationFullScreenestilo ou continuar usando UIModalPresentationCustome implementar sua própria subclasse de UIPresentationController com shouldRemovePresentersViewretorno YES. Na verdade, a implementação deste método é a principal diferença entre os controladores de apresentação internos definidos por estilos UIModalPresentationFullScreene, UIModalPresentationCustomalém do fato de que o último permite que você use controladores de apresentação personalizados.

  3. 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.

Egdmitry
fonte
2
Isso é super-estranho, porque este código depende de viewControllerForKey:'s views apenas quando viewForKey: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?
Ash Furrow
Bem, se 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.
egdmitry
Obrigado por explicar o raciocínio por trás deste problema. Você está absolutamente correto. Mover a posição da visualização na hierarquia de visualização sem substituí-la obviamente faria com que ela desaparecesse (postar o iOS 8 e estou trabalhando com o iOS 10 agora!) Obrigado por esclarecer.
Clay Ellis de
1
Obrigado egdmitry pelo seu esclarecimento. Que levantar uma outra questão que é a seguinte: como é que você acha que eu deveria implementar um revelam como apresentação? Um daqueles muito comuns hoje em dia em que a visualização de apresentação desliza parcialmente para fora para mostrar a visualização apresentada por baixo? Neste cenário, as visualizações de apresentação e apresentação precisam estar na tela e a visualização de apresentação é animada.
Andrea
70

No iOS 8, você deve manipular as visualizações retornadas por, em viewForKey:vez da .viewpropriedade dos controladores de visualização retornados por viewControllerForKey:. Isso não está muito claro na documentação beta, mas se você olhar a fonte de UIViewControllerTransitioning.h, verá este comentário acima viewControllerForKey::

// Currently only two keys are defined by the
// system - UITransitionContextToViewControllerKey, and
// UITransitionContextFromViewControllerKey.
// Animators should not directly manipulate a view controller's views and should
// use viewForKey: to get views instead.
- (UIViewController *)viewControllerForKey:(NSString *)key;

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:

- (UIView *)viewForTransitionContext:(id<UIViewControllerContextTransitioning>)transitionContext
{
#if __IPHONE_OS_VERSION_MAX_ALLOWED >= 80000
    if ([transitionContext respondsToSelector:@selector(viewForKey:)]) {
        NSString *key = [transitionContext viewControllerForKey:UITransitionContextFromViewControllerKey] == self ? UITransitionContextFromViewKey : UITransitionContextToViewKey;
        return [transitionContext viewForKey:key];
    } else {
        return self.view;
    }
#else
    return self.view;
#endif
}

Em seguida, pegue seu toViewControllere fromViewControllercomo 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/TransitionBug

Edit 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 viewForKeye UIModalPresentationFullScreen.

bcherry
fonte
2
O bug viewForKey estava me deixando louco! Obrigado por preencher. FWIW minha transição está funcionando bem obtendo a visão de UITransitionContextToViewControllerKey, mas minha transição está apenas aplicando uma transformação à visão inteira. Não tenho certeza se isso deve ser interpretado como manipulatingas visualizações dos VCs ou não ...
MathewS
1
Uau - isso é loucura. Eu não vi isso nas diferenças - provavelmente porque é apenas um pequeno comentário. Muito frustrante quando a Apple faz uma manobra como essa. Dedos cruzados sobre o seu radar.
Ash Furrow de
Estou vendo o viewForKeybug no GM também. Outros também? Você encontrou uma solução alternativa razoável para isso?
rjkaplan
2
Pensei de acordo com o comentário de - viewForKey// viewForKey: pode retornar nil, o que indica que o animador não deve manipular a visualização do controlador de visualização associado. Retornar nilnão é um bug.
Ken Kuan
4
@kenKuan você pode estar certo. ao usar UIModalPresentationFullScreen, viewForKeyretorna 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.
bcherry
24

Não definir modalPresentationStylecomo 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.

Graveley
fonte
1
Uau. Isso foi o suficiente! Testei sem modalPresentationStyle no iOS7 e 8 e funciona encontrar em ambos. Obrigado!!
Ah Ryun Moon,
1
Obrigado! Isso combinado com o uso em viewForKey:vez de .viewno viewControllerForKey:corrige todos os problemas para mim.
bcherry
1
Isso resolveu o problema para mim sem usar viewForKey, mas suponho que também deva ser usado.
Kevin Sliech
5
Embora isso pareça resolver o problema, é importante observar que a tela atrás do controlador de exibição ficará preta quando for exibida. Isso é importante se o seu controlador de visualização não estiver em tela inteira.
O cara de
16

Achei esta resposta extremamente útil em um tópico relacionado de Lefteris: https://stackoverflow.com/a/27165723/3709173

Resumindo:

  1. defina modalPresentationStyle como .Custom
  2. subclasse UIPresentationController, substitua shouldRemovePresentersView (com NO)
  3. substituir a apresentaçãoControllerForPresentedViewController em sua classe TransitionDelegate e retornar seu UIPresentationController personalizado

+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! :)

Mark Aron Szulyovszky
fonte
1
Esta é a resposta certa. Sem truques de mágica como no aceito. Obrigado, Mark!
Andrei Malygin
Infelizmente, isso não funciona no iOS 12.4, Xcode 10.3. A tela fica preta após a conclusão da transição (todas as visualizações foram removidas da hierarquia. No entanto, definir a propriedade 'modalPresentationStyle' como '.fullscreen' FUNCIONA. Saúde.
Womble
Eu tentei a versão Obj-C da implementação do Swift de Mark e gwinyai em meu projeto. Infelizmente, nenhum deles está funcionando como esperado. Estou usando o Xcode 11.1 e o destino de compilação é iOS 13.0, tentei no dispositivo e no simulador. No meu caso, minha configuração básica é uma visualização de coleção e quando você toca em uma célula, ela segue para uma visualização de detalhes com animação. No entanto, funciona perfeitamente bem se eu estiver usando a animação de transição padrão. O VC de apresentação não terá desaparecido quando eu retomar a visão dos detalhes.
infinity_coding7
8

No iOS 8, você precisa criar um UIPresentationController e implementar o método abaixo, no UIViewControllerTransitioningDelegate.

- (UIPresentationController *)presentationControllerForPresentedViewController:(UIViewController *)presented presentingViewController:(UIViewController *)presenting sourceViewController:(UIViewController *)source;

Solicita ao seu delegado o controlador de apresentação customizado para usar para gerenciar a hierarquia de visualização ao apresentar um controlador de visualização.

Valor de retorno:

O controlador de apresentação personalizado para gerenciar a apresentação modal.

Discussão:

Quando você apresenta um controlador de visualização usando o estilo de apresentação UIModalPresentationCustom, o sistema chama esse método e solicita o controlador de apresentação que gerencia seu estilo personalizado. Se você implementar este método, use-o para criar e retornar o objeto controlador de apresentação personalizado que deseja usar para gerenciar o processo de apresentação.

Se você não implementar este método, ou se sua implementação deste método retornar nil, o sistema usará um objeto controlador de apresentação padrão. O controlador de apresentação padrão não adiciona nenhuma visualização ou conteúdo à hierarquia de visualização.

Disponibilidade Disponível no iOS 8.0 e posterior.

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:

initWithPresentedViewController:presented presentingViewController:presenting

Antes fazia apresentações e depois era apresentado. Basta trocá-los e deve funcionar.

Paulo Faria
fonte
Desculpe por não assistir ao vídeo vinculado, mas não acho que você precisa de um UIPresentationController personalizado, a menos que você queira uma apresentação fora do padrão após a conclusão da animação, como uma visualização apresentada circular. Se você quer apenas uma animação diferente, implementar UIViewControllerAnimatedTransitioning deve ser suficiente, com base no meu conhecimento limitado.
Vaddadi Kartick de
7

em vez de [inView insertSubview: toViewController.view aboveSubview: fromViewController.view]; basta adicionar: [inView addSubview: toViewController.view];

if (self.presenting) {

    [transitionContext.containerView addSubview:toViewController.view];
    // your code

} else {
    // your code
}

Você pode ver um exemplo aqui: link e funciona no iOS 7 e iOS 8

CarlosGz
fonte
Essa deve ser a resposta aceita para fazer um tipo de animação UIModalPresentationStyleCustom, já que não há necessidade de adicionar fromViewController ao containerView. Você só precisa adicionar toViewController durante a apresentação da animação.
Scott Kaiser
Isso é muito útil, na verdade
Dmitry Bondarev
7

Aqui está uma versão Objective C da correção de Ash.

// my attempt at obj-c version of Ash's fix
UIView *theToView = [transitionContext viewControllerForKey:UITransitionContextToViewControllerKey].view;
[[[UIApplication sharedApplication] keyWindow] addSubview:theToView];
[transitionContext completeTransition:YES]

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!

vichudson1
fonte
5

Achei que funcionou bem para Obj-C:

    [transitionContext completeTransition:YES];
    if(![[UIApplication sharedApplication].keyWindow.subviews containsObject:toViewController.view]) {
        [[UIApplication sharedApplication].keyWindow addSubview:toViewController.view];
    }

Parece funcionar bem em iOS7 e iOS8.

Reedy
fonte
5

Descobri que viewForKey:UITransitionContextToViewKeyretorna 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, se viewForKey:UITransitionContextToViewKeyretorna nil, eu caio para toVC.viewe 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.

- (void)animateTransition:(id <UIViewControllerContextTransitioning>)transitionContext {
    // Get the 'from' and 'to' views/controllers.
    UIViewController *fromVC = [transitionContext viewControllerForKey:UITransitionContextFromViewControllerKey];
    UIViewController *toVC = [transitionContext viewControllerForKey:UITransitionContextToViewControllerKey];
    BOOL hasViewForKey = [transitionContext respondsToSelector:@selector(viewForKey:)]; // viewForKey is iOS8+.
    UIView *fromView = hasViewForKey ?
        [transitionContext viewForKey:UITransitionContextFromViewKey] :
        fromVC.view;
    UIView *toView = hasViewForKey ?
        [transitionContext viewForKey:UITransitionContextToViewKey] :
        toVC.view;

    // iOS8 has a bug where viewForKey:to is nil: http://stackoverflow.com/a/24589312/59198
    // The workaround is: A) get the 'toView' from 'toVC'; B) manually add the 'toView' to the container's
    // superview (eg the root window) after the completeTransition call.
    BOOL toViewNilBug = !toView;
    if (!toView) { // Workaround by getting it from the view.
        toView = toVC.view;
    }
    UIView *container = [transitionContext containerView];
    UIView *containerSuper = container.superview; // Used for the iOS8 bug workaround.

    // Perform the transition.
    toView.frame = container.bounds;
    [container insertSubview:toView belowSubview:fromView];
    [UIView animateWithDuration:kDuration delay:0 options:UIViewAnimationOptionCurveEaseIn animations:^{
        fromView.frame = CGRectOffset(container.bounds, 0, CGRectGetHeight(container.bounds));
    } completion:^(BOOL finished) {
        [transitionContext completeTransition:YES];

        if (toViewNilBug) {
            [containerSuper addSubview:toView];
        }
    }];
}
Chris
fonte
3

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.

Chris
fonte
2

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:

  1. Crie uma subclasse de UIPresentationController. Substitua shouldRemovePresentersView por false da seguinte forma:

    class ModalPresentationController: UIPresentationController {
    
    override var shouldRemovePresentersView: Bool {
    return false
    }
    
    override func containerViewWillLayoutSubviews() {
    presentedView?.frame = frameOfPresentedViewInContainerView
    }
    }
  2. 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:

    let newVC = mainStoryboard.instantiateViewController(withIdentifier: "newVC") as! NewViewController 
    
    newVC.transitioningDelegate = self
    
    newVC.modalPresentationStyle = UIModalPresentationStyle.custom
    
    newVC.modalPresentationCapturesStatusBarAppearance = true //optional
    
    present(newVC, animated: true, completion: nil)
  3. 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:

    extension CurrentViewController: UIViewControllerTransitioningDelegate {
    
    //this is where you implement animationController(forPresented) and animationController(forDismissed) methods
    
    func presentationController(forPresented presented: UIViewController, presenting: UIViewController?, source: UIViewController) -> UIPresentationController? {
    
    return ModalPresentationController(presentedViewController: presented, presenting: source)
    
    }
    }

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.

gwinyai
fonte
Este iis é um ótimo exemplo para fazer uma apresentação modal personalizada no Swift 3! Obrigado @gwinyai! Fiquei muito preso a isso até encontrar um exemplo que mostrava a nova API do swift 3 presentationController(forPresented presented UIViewController,... porque a API anterior do swift não incomodava o compilador, mas não era chamada.
Natalia
2

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 modalPresentationStylepara .overFullScreen. Isso está correto, .overCurrentContextfuncionaria 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.

Jordan Smith
fonte
1
Eu defino o estilo de apresentação para .overCurrentContext antes de carregar a visualização (no do initcontrolador de visualização) e o problema ainda acontece
ricardopereira
1

Usar 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.

Malhal
fonte
Por alguma razão, isso não parece permitir a interação com a exibição abaixo, onde UIModalPresentationCurrentContext fazia no iOS 7 .. Alguma ideia?
Christopher Wirt
Hmm para mim no iOS 10, .overCurrentContext resulta neste bug, mas .fullscreen não. Eu vim aqui esperando uma correção para usar .overCurrentContext, mas até agora nada parece que funcionará no iOS 10, exceto talvez a subclasse de UIPresentationController ...
Natalia
0

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

transitionContext.completeTransition(true)

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:

transitionContext.viewController(forKey: .to)?.view
transitionContext.viewController(forKey: .from)?.view

Diretamente:

transitionContext.view(forKey: .to)
transitionContext.view(forKey: .from)

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.

infinity_coding7
fonte
0

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

  1. altere o .modalPresentationStyledo childVC apresentado por parentVC do padrão .automaticpara .fullscreen.
  2. Em seguida, alterou o .modalPresentationStylede contentVC para .fullscreentambé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 .overCurrentContextou 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.

arvinq
fonte
-3

adiciona um controlador de visualização como filho de outro controlador de visualização.

[self addChildViewController:childViewController];                 

verifique e me avise.

Rushabh
fonte
não estou entendendo, você pode descrever usando codificação?
NiravPatel de
verifique esta documentação da apple developer.apple.com/library/ios/featuredarticles/…
Rushabh
isso de forma alguma responde à pergunta. ChildViewControllers não estão envolvidos em nenhuma parte das transições personalizadas, eles são um assunto completamente diferente.
Andras M.