108 votes

« De vue contrôleur » disparaît à l’aide de UIViewControllerContextTransitioning

J'ai eu un problème et j'ai décrit ci-dessous.

Je suis à l'aide de UIViewControllerContextTransitioning pour les transitions personnalisées.

J'ai 2 contrôleurs de vue , à première vue, contrôleur et la seconde vue contrôleur.

Maintenant, je veux ajouter secondview contrôleur à première vue-contrôleur avec animation. J'ai réalisé cela, j'ai maintenant secondview contrôleur transparent , de sorte que nous pouvons voir à première vue-contrôleur ci-dessous secondview contrôleur.

Mais je ne suis pas en mesure de voir à première vue-contrôleur , et je peux voir que du noir de l'écran ci-dessous secondview contrôleur.

Voici le code.

-(void)animateTransition:(id)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];
  }];
}

Lors de l' [self.transitionContext completeTransition:YES]; appelé, tout à coup le premier-vue-contrôleur disparaît et l'écran noir s'affiche au-dessous de seconde vue-contrôleur.

Est-ce une quelconque idée ? Merci.

99voto

Ash Furrow Points 6157

J'ai eu le même problème ici – ressemble à un bug dans iOS 8. J'ai déposé un radar.

J'ai utilisé Révéler à inspecter le point de vue de la hiérarchie après l'écran devient noir. La clé UIWindow est entièrement vide, pas de vue de la hiérarchie à tous!

Reveal'd

J'ai joué un peu et il semble qu'il y est une simple solution de contournement, pour les cas simples. Vous pouvez simplement ajouter de nouveau l' toViewControllers'vue comme une sous-vue de la touche de la fenêtre:

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

J'ai vérifié et la clé de la fenêtre de l' rootViewController est toujours bien réglé, c'est très bien. Je ne suis pas sûr de ce qui se passerait si vous avez présenté votre contrôleur de dans une déjà présenté modal contrôleur, donc, pour les cas plus complexes, vous aurez à expérimenter autour de.

78voto

egdmitry Points 483

Je me sens comme le raisonnement derrière cela devrait être mieux expliquée.

L'affichage disparaît parce que vous sortez de la présentation de la vue du contrôleur de la vue de son emplacement d'origine (afficher la hiérarchie), le mettre à l'intérieur de la containerView que votre animateur fournit, mais ne revient jamais en arrière une fois l'animation terminée. De sorte que la vue du contrôleur de point de vue est enlevée avec sa superview (containerView) à partir de la fenêtre complètement.

Dans iOS 7, le système retourne toujours afficher les contrôleurs de points de vue qui sont impliqués dans la présentation (présentation et présentée) à leur emplacement d'origine après la transition a fini d'animer automatiquement. Qui ne se fait plus pour certains styles de présentation dans iOS 8.

La règle est très simple: l'animateur ne doit manipuler la présentation de la vue du contrôleur de la vue, si ce point de vue du contrôleur de la vue va être cachées (supprimé à partir de la vue de la hiérarchie) complètement par la fin de la transition. En d'autres termes cela signifie que, après la présentation initiale de l'animation ne finit que la vue du contrôleur de la vue sera visible et pas de présenter en vue du contrôleur de vue. Par exemple, si vous définissez présentés vue du contrôleur de vue de l'opacité à 50% et l'utilisation UIModalPresentationFullScreen vous ne serez pas en mesure de voir la présentation de la vue du contrôleur de la vue de dessous de l'présenté, mais si vous utilisez UIModalPresentationOverFullscreen - vous (UIPresentationController de l' shouldRemovePresentersView méthode est responsable de la spécification).

Pourquoi ne pas permettre à l'animateur de manipuler la présentation de la vue du contrôleur de la vue à tout moment? Tout d'abord, si la présentation de la vue du contrôleur de la vue va rester visible après l'animation des finitions au cours de l'ensemble de la présentation du cycle de vie il n'y a pas besoin de l'animer à tous qu'il reste où il est. Deuxièmement, si le droit de propriété pour afficher la barre de contrôle est transféré à la présentation de contrôleur, la présentation de la manette plus susceptibles de ne pas savoir comment la mise en page que la vue du contrôleur de la vue lorsque nécessaire, par exemple lorsque les changements d'orientation, mais le propriétaire original de la présentation-vue-contrôleur.

Dans iOS 8 viewForKey: méthode a été introduite pour obtenir des vues que l'animateur manipule. Tout d'abord, il permet de suivre la règle décrite ci-dessus par le retour de néant à chaque fois que l'animateur ne doit pas toucher la vue. Deuxièmement, elle peut retourner une différente vue de l'animateur pour animer. Imaginez que vous êtes à la mise en œuvre d'une présentation similaire à la forme de la feuille. Dans ce cas, vous voulez ajouter un peu de l'ombre ou de la décoration autour de la vue du contrôleur de vue. L'animateur s'animer que la décoration de la place, et la vue du contrôleur de vue d'un enfant de la décoration.

viewControllerForKey: ne disparaît pas, il peut toujours être utilisé si un accès direct à la vue des contrôleurs est nécessaire, mais l'animateur ne doit pas faire d'hypothèses sur le point de vue qu'il doit animer.

Il y a plusieurs choses que vous pouvez faire pour résoudre un problème avec la disparition de la présentation de la vue du contrôleur de la vue lorsque vous explicitement le placer à l'intérieur de l'animateur du conteneur de vue:

  1. Si n'avez pas besoin d'animer la présentation de la vue du contrôleur de la vue, utilisez viewControllerForKey: pour obtenir des vues d'animer au lieu de tendre la main à vue-contrôleur les vues directement. viewControllerForKey peut retourner nil ou même complètement différents points de vue.

  2. Si vous souhaitez animer la présentation de la vue des contrôleurs de vue, vous devriez envisager d'utiliser UIModalPresentationFullscreen style ou de continuer à utiliser UIModalPresentationCustom et de mettre en œuvre votre propre sous-classe de UIPresentationController avec shouldRemovePresentersView de revenir YES. En fait, la mise en œuvre de cette méthode est la principale différence entre la présentation interne des contrôleurs défini par UIModalPresentationFullscreen et UIModalPresentationCustom styles en dehors du fait que ce dernier vous permet d'utiliser vos propres présentation des contrôleurs.

  3. Dans tous les autres cas rares, vous devez revenir sur la présentation de la vue du contrôleur de la vue à son emplacement d'origine comme d'autres réponses suggérées.

70voto

bcherry Points 3541

Dans iOS 8, vous devez manipuler les vues retourné par viewForKey: , au lieu de l' .view de la propriété de la vue des contrôleurs retourné par viewControllerForKey:. Ce n'est pas particulièrement clair à partir de la documentation de la version bêta, mais si vous regardez dans le code source pour UIViewControllerTransitioning.h vous verrez ce commentaire ci-dessus 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;

Donc, au lieu de régler etc cadres de toViewController.view, utiliser la valeur de retour de l' [transitionContext viewForKey:UITransitionContextToViewKey].

Si votre application a besoin de soutien iOS7 et/ou Xcode 5, alors vous pouvez utiliser une simple catégorie de méthode sur UIViewController comme suit:

- (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
}

Puis, obtenez votre toViewController et fromViewController comme d'habitude, mais avoir le point de vue à l'aide de [toViewController viewForTransitionContext:transitionContext].

Edit: Il semble y avoir un bug, d'où la présentation de la vue du contrôleur de vue est nulle lorsque le retour de viewForKey, ce qui vous empêche de faire modale des transitions qui animent la présentation de la vue à tous (comme le glisser, ou flip-horizontal). J'ai déposé un bug pour iOS8 à rdar://17961976 (http://openradar.appspot.com/radar?id=5210815787433984). Voir aussi l'exemple de projet à http://github.com/bcherry/TransitionBug

Edit 2: Merci à graveley pour la suggestion, à l'aide de UIModalPresentationFullScreen résout le problème. Peut-être que ce n'est pas un bug. Apple a l'intention que UIModalPresentationCustom modifie seulement le point de vue de l'entrants modal. Si vous souhaitez modifier les sortants de vue, vous avez besoin de garantir le plein écran de présentation de la nouvelle vue? Dans tous les cas, vous devez utiliser viewForKey et UIModalPresentationFullScreen.

25voto

graveley Points 66

Ne pas fixer modalPresentationStyle de UIModalPresentationCustom résolu le problème pour moi.

En d'autres termes, en laissant à la valeur par défaut de UIModalPresentationFullScreen au lieu de spécifier UIModalPresentationCustom fixe la disparition de vue en question. Remarque le UIViewControllerTransitioningDelegate encore, le protocole semble être suivie, même en sortant à la valeur par défaut. Si je me souviens bien, une fois UIModalPresentationCustom est une exigence.

Fonctionne jusqu'à présent, ne l'ai essayé ce pour les non-des animations interactives.

8voto

CarlosGz Points 11

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 il fonctionne sur iOS 7 et 8 d’iOS

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X