J'ai un problème et je l'ai décrit ci-dessous.
J'utilise UIViewControllerContextTransitioning
pour des transitions personnalisées.
J'ai 2 contrôleurs de vue, un premier contrôleur de vue et un deuxième contrôleur de vue.
Maintenant, je veux ajouter un deuxième contrôleur de vue sur le premier contrôleur de vue avec une animation. Je l'ai atteint, maintenant le deuxième contrôleur de vue est transparent, nous pouvons donc voir le premier contrôleur de vue sous le deuxième contrôleur de vue.
Mais je ne peux pas voir le premier contrôleur de vue, et je ne peux voir que l'écran noir sous le deuxième contrôleur de vue.
-(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];
}];
}
Lorsqu'il est [self.transitionContext completeTransition:YES];
appelé, le premier contrôleur de vue disparaît soudainement et un écran noir s'affiche sous le second contrôleur de vue.
Quelqu'un a-t-il une idée? Merci.
la source
modalPresentationStyle = UIModalPresentationFullScreen
. Bien sûr, vous obtenez toujours votre animation de transition personnalisée.Je pense que le raisonnement derrière cela devrait être mieux expliqué.
La vue disparaît car vous retirez la vue du contrôleur de vue de présentation de son emplacement d'origine (hiérarchie de vues), placez-la dans le containerView que votre animateur fournit mais ne la retourne jamais une fois l'animation terminée. Ainsi, la vue du contrôleur de vue est complètement supprimée avec sa vue supervisée (containerView) de la fenêtre.
Dans iOS 7, le système renvoyait toujours les vues des contrôleurs de vue impliqués dans la présentation (présentation et présentation) à leur emplacement d'origine une fois l'animation terminée de la transition. Cela ne se produit plus pour certains styles de présentation dans iOS 8.
La règle est très simple: l'animateur ne doit manipuler la vue du contrôleur de vue de présentation que si la vue de ce contrôleur de vue va être complètement masquée (supprimée de la hiérarchie de vue) à la fin de la transition . En d'autres termes, cela signifie qu'après la fin de l'animation de présentation initiale, seule la vue du contrôleur de vue présentée sera visible et non la vue du contrôleur de vue de présentation. Par exemple, si vous définissez l'opacité de la vue du contrôleur de vue présenté à 50% et utilisez UIModalPresentationFullScreen, vous ne pourrez pas voir la vue du contrôleur de vue présentée sous le présenté, mais si vous utilisez UIModalPresentationOverFullscreen - vous (la
shouldRemovePresentersView
méthode d'UIPresentationController est responsable de le spécifier).Pourquoi ne pas permettre à l'animateur de manipuler la vue du contrôleur de vue de présentation à tout moment? Tout d'abord, si la vue du contrôleur de vue de présentation doit rester visible après la fin de l'animation pendant tout le cycle de vie de la présentation, il n'est pas nécessaire de l'animer du tout - elle reste simplement là où elle est. Deuxièmement, si la propriété de ce contrôleur de vue est transférée au contrôleur de présentation, le contrôleur de présentation ne saura probablement pas comment mettre en page la vue de ce contrôleur de vue lorsque cela est nécessaire, par exemple lorsque l'orientation change, mais le propriétaire d'origine du contrôleur de vue de présentation le fait. .
Dans iOS 8, la
viewForKey:
méthode a été introduite pour obtenir des vues que l'animateur manipule. Tout d'abord, il est utile de suivre la règle décrite ci-dessus en renvoyant nul chaque fois que l'animateur ne doit pas toucher la vue. Deuxièmement, il peut renvoyer une vue différente pour l'animateur à animer. Imaginez que vous implémentez une présentation similaire à une feuille de formulaire. Dans ce cas, vous voudrez ajouter une ombre ou une décoration autour de la vue du contrôleur de vue présenté. L'animateur animera cette décoration à la place et la vue du contrôleur de vue présentée sera un enfant de la décoration.viewControllerForKey:
ne disparaît pas, il peut toujours être utilisé si un accès direct aux contrôleurs de vue est nécessaire, mais l'animateur ne doit faire aucune hypothèse sur les vues dont il a besoin pour animer.Il y a plusieurs choses que vous pouvez faire pour résoudre correctement un problème avec la vue d'un contrôleur de vue de présentation qui disparaît lorsque vous le placez explicitement dans la vue conteneur de l'animateur:
Si vous n'avez pas besoin d'animer la vue du contrôleur de vue de présentation, utilisez
viewForKey:
pour obtenir des vues à animer au lieu d'atteindre directement les vues du contrôleur.viewForKey:
peut renvoyer des vues nulles ou même complètement différentes.Si vous souhaitez animer la vue des contrôleurs de vue de présentation, vous devez envisager d'utiliser le
UIModalPresentationFullScreen
style ou continuer à utiliserUIModalPresentationCustom
et à implémenter votre propre sous-classe de UIPresentationController avecshouldRemovePresentersView
retourYES
. En fait, la mise en œuvre de cette méthode est la principale différence entre les contrôleurs de présentation internes définis parUIModalPresentationFullScreen
et lesUIModalPresentationCustom
styles mis à part le fait que ce dernier vous permet d'utiliser des contrôleurs de présentation personnalisés.Dans tous les autres cas rares, vous devrez ramener la vue du contrôleur de vue de présentation à son emplacement d'origine, comme d'autres réponses le suggèrent.
la source
viewControllerForKey:
les sview
que lorsque leviewForKey:
retour est nul, et je devais encore le rajouter manuellement à la fenêtre. Avez-vous un exemple de code fonctionnant sans cette solution de contournement?viewForKey:
retourne nil, vous devrez certainement ajouter à nouveau la vue du contrôleur de vue de présentation à la fenêtre si vous la supprimez dans votre animateur. Dans le cas où viewForKey renvoie la vue réelle du contrôleur de vue, il est prudent de déplacer cette vue car UIKit la ramènerait à sa position d'origine une fois le cycle de vie de la présentation terminé.Dans iOS 8, vous devez manipuler les vues renvoyées par
viewForKey:
au lieu de la.view
propriété des contrôleurs de vue renvoyés parviewControllerForKey:
. Ce n'est pas particulièrement clair dans la documentation bêta, mais si vous regardez dans la source de UIViewControllerTransitioning.h, vous verrez ce commentaire ci-dessusviewControllerForKey:
- :Donc, au lieu d'ajuster les images, etc.
toViewController.view
, utilisez la valeur de retour de[transitionContext viewForKey:UITransitionContextToViewKey]
.Si votre application doit prendre en charge iOS7 et / ou Xcode 5, vous pouvez utiliser une méthode de catégorie simple sur UIViewController comme suit:
Ensuite, récupérez votre
toViewController
etfromViewController
comme d'habitude, mais obtenez les vues en utilisant[toViewController viewForTransitionContext:transitionContext]
.Modifier: il semble y avoir un bogue, où la vue du contrôleur de la vue de présentation est nulle lorsqu'elle est renvoyée
viewForKey
, ce qui vous empêche d'effectuer des transitions modales qui animent la vue de présentation (comme un glissement ou un basculement horizontal). J'ai déposé un bogue pour iOS8 sur rdar: // 17961976 ( http://openradar.appspot.com/radar?id=5210815787433984 ). Consultez également l'exemple de projet à l' adresse http://github.com/bcherry/TransitionBugEdit 2: Merci à Graveley pour la suggestion, l'utilisation de UIModalPresentationFullScreen résout le problème. Ce n'est peut-être pas un bug. Apple peut avoir l'intention que UIModalPresentationCustom modifie uniquement la vue du modal entrant. Si vous souhaitez modifier la vue sortante, vous devez garantir une présentation plein écran de la nouvelle vue? Dans tous les cas, vous devez utiliser
viewForKey
et UIModalPresentationFullScreen.la source
manipulating
les vues des VC ou non ...viewForKey
bogue dans le GM. Les autres aussi? Avez-vous trouvé une solution de contournement raisonnable pour cela?- viewForKey
// viewForKey: peut retourner nil, ce qui indiquerait que l'animateur ne devrait pas manipuler la vue du contrôleur de vue associé. Le retournil
n'est pas un bug.viewForKey
renvoie la vue de et la vue à. Alors peut-être que c'est intentionnel qu'il renvoie nul pour UIModalPresentationCustom. Je mets à jour mon rapport de bogue et je le publierai ici si j'en reviens d'Apple.Pas de réglage
modalPresentationStyle
UIModalPresentationCustom a résolu le problème pour moi.En d'autres termes, laisser la valeur par défaut de UIModalPresentationFullScreen au lieu de spécifier UIModalPresentationCustom a résolu le problème de la vue en voie de disparition. Notez que le protocole UIViewControllerTransitioningDelegate semble toujours être suivi même en le laissant à la valeur par défaut. Si je me souviens bien, il était une fois UIModalPresentationCustom était une exigence.
Fonctionne jusqu'à présent, je n'ai essayé cela que pour les animations non interactives.
la source
viewForKey:
au lieu de.view
sur lesviewControllerForKey:
corrige tous les problèmes pour moi.J'ai trouvé cette réponse extrêmement utile dans un fil de discussion connexe de Lefteris: https://stackoverflow.com/a/27165723/3709173
Résumer:
+1 dans votre transition personnalisée, n'ajoutez pas toView lorsque l'animation de renvoi se produit.
Démontré ici:
https://www.dropbox.com/s/7rpkyamv9k9j18v/CustomModalTransition.zip?dl=0 sans aucun hacks! c'est comme de la magie! :)
la source
Dans iOS 8, vous devez créer un UIPresentationController et implémenter la méthode ci-dessous, dans le UIViewControllerTransitioningDelegate.
Pour plus d'informations, regardez la vidéo WWDC 2014:
https://developer.apple.com/videos/wwdc/2014/?include=228
Il existe également un exemple de code de la WWDC appelé «LookInside: Adaptivité des contrôleurs de présentation et objets d'animation personnalisés», que vous pouvez télécharger à partir de la page de codes d'exemple de la WWDC 2014.
Vous devrez peut-être modifier un peu l'exemple de code. La méthode d'initialisation UIPresentationController a été modifiée en:
Avant, il était présenté puis présenté. Échangez-les et cela devrait fonctionner.
la source
au lieu de [inView insertSubview: toViewController.view aboveSubview: fromViewController.view]; il suffit d'ajouter: [inView addSubview: toViewController.view];
Vous pouvez voir un exemple ici: lien et cela fonctionne sur iOS 7 et iOS 8
la source
Voici une version Objective C du correctif d'Ash.
J'ai dû échanger la commande et appeler la méthode [transitionContext completeTransition:] après avoir rajouté la vue pour obtenir la présentation d'un nouveau contrôleur de vue du bloc d'achèvement de renvoi d'un autre contrôleur de vue pour fonctionner correctement.
Je ne sais pas si cela résoudra le problème pour tout le monde, mais cela fonctionne dans mon application. À votre santé!
la source
J'ai trouvé que cela fonctionnait bien pour Obj-C:
Semble fonctionner correctement sur ios7 et ios8.
la source
Je l'ai trouvé
viewForKey:UITransitionContextToViewKey
renvoie nul sur ios8. Donc, si c'est nul, je saisis la vue du contrôleur de vue 'to'.Cependant, cela semble avoir pour conséquence que la vue «à» ne soit pas déplacée du conteneur vers la fenêtre lorsqu'elle
completeTransition:YES
est appelée. Donc siviewForKey:UITransitionContextToViewKey
retourne nul, je tombetoVC.view
, et garde une trace du fait qu'il a renvoyé nil, et après l'achèvement, je le déplace vers la supervision initiale du conteneur (qui se trouve être la fenêtre).Donc, ce code fonctionne aussi bien sur iOS7 que sur iOS8, et devrait également fonctionner sur iOS9 même s'ils le corrigent ou non.
la source
J'ai trouvé que ce bogue (et bien d'autres!) Disparaît si vous définissez
modalPresentationStyle = UIModalPresentationFullScreen
. Bien sûr, vous obtenez toujours votre animation de transition personnalisée.la source
Je suis resté coincé sur ce problème aussi. Je cherchais à créer une transition personnalisée avec un arrière-plan semi-transparent où je pouvais toujours voir le contrôleur de vue d'où je venais, mais je n'avais qu'un arrière-plan noir. J'ai trouvé la réponse de Mark Aron dans ce fil de discussion qui m'a aidé mais elle est écrite en Objective C, voici donc une version Swift 3 de cette réponse que j'ai testée pour iOS 9 et iOS 10:
Créez une sous-classe de UIPresentationController. Remplacez shouldRemovePresentersView par false comme suit:
À l'endroit où vous instanciez le nouveau contrôleur de vue et définissez son délégué de transition, indiquez que vous souhaitez qu'il affiche un style de présentation modal personnalisé comme suit:
Remplacez maintenant la méthode presentationController de votre UIViewControllerTransitioningDelegate et renvoyez votre UIPresentationController personnalisé. J'avais le mien comme extension de ma classe actuelle:
Une autre chose à noter est que vous ne devez pas essayer de référencer votre fromView dans votre classe presentAnimator. Ce sera nul et vous obtiendrez une erreur lors de l'exécution. À part cela, si vous implémentez des choses comme des choses, vous obtiendrez votre transition personnalisée avec son animation et un arrière-plan semi-transparent si vous en faites un.
la source
presentationController(forPresented presented UIViewController,...
car la précédente API swift n'a pas dérangé le complicateur mais n'a pas été appelée.Après avoir rencontré ce problème, j'étais très confus, car j'avais écrit quelque chose de presque identique il n'y a pas si longtemps qui fonctionnait bien. Je suis venu ici à la recherche de réponses pour trouver des correctifs qui semblent assez piratés et qui ne semblent pas comprendre la cause profonde ... c'est en fait très facile à corriger.
Certaines réponses mentionnent le passage
modalPresentationStyle
à.overFullScreen
. C'est correct,.overCurrentContext
cela fonctionnerait aussi. Cela est attendu, et le comportement des documents Apple. Mais pourquoi cela ne fonctionne-t-il pas pour tout le monde? Pourquoi tout le code hacky, et les combinaisons de cela avec autre chose, et des trucs fous que vous ne devriez pas faire?Il s'avère que vous devez définir le style de présentation AVANT LES CHARGES DE VUE . Pas après. Faites-le dans init, ou faites-le à partir du contrôleur précédent, ou comme vous le souhaitez - tant que c'est avant le chargement de la vue.
la source
.overCurrentContext
avant le chargement de la vue (dans leinit
contrôleur de vue) et le problème se produit toujoursL'utilisation du nouveau UIModalPresentationOverCurrentContext l'a corrigé pour moi. Ma transition originale sur iOS 7 consistait simplement à avoir un arrière-plan flou de la vue sous le modal.
la source
Ok, les gars, je pense que j'ai résolu un cas où `` un animateur qui travaille '' cesse de fonctionner correctement lorsque vous créez une application sous iOS 13 et supérieur.
Env Xcode 11.1, iOS 13.1
Problème
Ce que je veux faire est très simple: j'ai une vue de collection, quand une cellule est tapée, elle passe à une vue de détail. Au lieu d'utiliser le style par défaut ennuyeux de «présenter modalement», je veux le rendre plus intéressant, j'ai donc écrit un animateur pour la transition du contrôleur de vue.
J'ai mis en place le segue dans IB par glisser-déposer de ma collection VC au détail VC. Le style de segue est «Présent modalement» et la présentation est définie sur «Plein écran».
Lorsqu'il affiche la vue détaillée, tout fonctionne comme prévu. Cependant, lorsque je ferme la vue détaillée et retourne à la vue de la collection, je ne peux voir que la vue de détail animée, la vue de la collection a simplement disparu. J'ai poussé ici et là et j'ai quelques découvertes
Juste après l'appel de la ligne suivante à partir de la fonction 'animateTransition ()', la vue de la collection reprend et apparaît
Tant que la vue détaillée ne couvre pas entièrement la vue de la collection, la vue de la collection ne disparaîtra pas lorsqu'elle reviendra de la vue de détail
Solution
Pour être honnête, je sais peu de choses sur le fonctionnement de la transition animée. Donc je ne peux que suivre ce post et l'autre , essayer chacune des réponses. Malheureusement, aucun d'entre eux ne fonctionne pour moi. Enfin, je suis arrivé à un point où la seule chose que je puisse modifier est le style de présentation de segue dans IB (ce que j'aurais dû faire au tout début). Lorsque je règle la présentation sur «Sur plein écran», un miracle se produit et mon problème est résolu. La vue détaillée peut s'afficher en plein écran avec une animation et lorsqu'elle est rejetée, je peux voir à la fois la vue de la collection en arrière-plan et la vue de détail animée.
Puis une autre découverte le long de la route
Pour faire référence à 'toView' et 'fromView', les deux méthodes suivantes fonctionnent
Indirectement façon:
Directement façon:
Mais lorsque j'ai basculé le style de segue sur `` Over Full Screen '', la manière directe retourne `` nil '' pour `` toView '' et `` fromView '' et fonctionne uniquement indirectement, ce problème est également mentionné dans un autre article , donc je pense que cela vaut la peine pour poster ma petite découverte ici.
J'espère que cela sera utile à quelqu'un à l'avenir.
la source
J'avais le même problème lors du rejet d'un contrôleur de vue de contenu.
Mon application a ce contrôleur de vue parent montrant un contrôleur de vue enfant (présentant vc) de manière modale. Ensuite, lorsqu'une sous-vue dans le childVC est tapée, elle montre un autre vc (que j'appelle le contrôleur de vue de contenu (présenté vc))
Mon problème est que, lors de la suppression du contentVC (maintenant le vc de présentation), il devrait aller au VC enfant (maintenant le VC présenté) mais dès que ma transition personnalisée se termine, childVC disparaît soudainement, montrant le VC parent.
Ce que j'ai fait pour résoudre ce problème est de
.modalPresentationStyle
valeur par défaut du childVC présenté par parentVC.automatic
en.fullscreen
..modalPresentationStyle
de contentVC en.fullscreen
aussi.Cela résout le problème. mais il ne montrera pas votre VC enfant comme une feuille de style carte au-dessus de parentVC (lors de l'utilisation
.overCurrentContext
ou automatique) qui est nouveau dans iOS 13.J'adorerais savoir s'il existe une solution qui conservera la feuille de style carte pour l'enfantVC lorsqu'elle est présentée par le parent.
la source
ajoute un contrôleur de vue en tant qu'enfant d'un autre contrôleur de vue.
vérifier et laissez-moi savoir.
la source