"From View Controller" disappears using UIViewControllerContextTransitioning
Asked Answered
M

17

108

I got one problem and i have described it below.

I am using UIViewControllerContextTransitioning for custom transitions.

I have 2 view controllers, first view controller and second view controller.

Now I want to add second view controller on first view controller with an animation. I have achieved it, now the second view controller is transparent, so we can see first view controller below second view controller.

But I am not able to see first view controller, and I can see only black screen below second view controller.

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

When [self.transitionContext completeTransition:YES]; called, suddenly the first view controller disappears and black screen displays below second view controller.

Does any one have idea ? Thanks.

Melessa answered 21/6, 2014 at 5:48 Comment(0)
M
99

I was having the same problem here – looks like a bug in iOS 8. I've filed a radar.

I used Reveal to inspect the view hierarchy after the screen goes black. The key UIWindow is completely empty – no view hierarchy at all!

Reveal'd

I played around a bit and it looks like there is an easy workaround, for simple cases. You can just re-add the toViewController's view as a subview of the key window's:

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

I've checked and the key window's rootViewController is still correctly set, so that's fine. I'm not sure what would happen if you presented your controller from within an already presented modal controller, so for more complex cases, you'll have to experiment around.

Maidinwaiting answered 5/7, 2014 at 18:22 Comment(14)
I have also seen this issue. iOS 8 introduces a new method and keys for accessing the fromView and toView (Note: not view controller) It appears as though these references are not lost during the transition. You can add them to the container view as you normally would if you had just retrieved them from the view controllers.Slavey
I was seeing similar iOS 8 weirdness when trying to add subviews to my navigation controller's view, in viewDidLoad. Re-adding the navigationController's view to the keyWindow seemed to do the trick, thanks a lot, Ash!Unreserved
Thank you! This was driving me crazy because I thought it was a problem with my UIPercentDrivenInteractiveTransition subclass.Exhilarant
I'm still seeing this in GM (and this fix still works). Are others seeing the same? Is this just a change in the API?Dicephalous
@ash-furrow You are a genius. Thanks for your answer and for your many awesome tutorials.Atlanta
i'm also still seeing this issue in the GMDiez
Okay so I don't know if it's right or if it's wrong but I fixed it for my issues. I'll post in a new answer for good code reading.Turoff
absolutely genius! one question, do i need to add this line just for iOS 8, or does this change continue to work with iOS 7?Fanaticism
I don't know – try it out and find let us know!Maidinwaiting
I found that this bug (and many more!) vanishes if you set modalPresentationStyle = UIModalPresentationFullScreen. You of course still get your custom transition animation.Stereography
@Stereography Doesn't work with UIModalPresentationOverFullScreenCacography
Thanks @AshFurrow. Nice workaround until it is fixed!Cunnilingus
As Chris says, setting 'modalPresentationStyle' to 'fullscreen' instead of custom DOES work as of iOS 12.4, Xcode 10.3. Whereas using a custom UIPresentationController does not.Melvin
Problem is back ! With iOS 13 if you set your modalPresentationStyle to .overFullScreen you need to add UIApplication.shared.keyWindow!.addSubview(toVC.view) after the completeTransition to avoid the black window...Savoy
L
79

I feel like the reasoning behind this should be explained better.

The view disappears because you take out the presenting view controller's view out of its original location (view hierarchy), put it inside the containerView that your animator provides but never returns it back after the animation has finished. So that view controller's view is removed with its superview (containerView) from the window completely.

In iOS 7 the system always returned view controllers' views that are involved in the presentation (presenting and presented) to their original places after the transition has finished animating automatically. That no longer happens for some presentation styles in iOS 8.

The rule is very simple: the animator should only manipulate the presenting view controller's view if that view controller's view is going to be hidden (removed from the view hierarchy) completely by the end of transition. In other words it means that after the initial presentation animation finishes only the presented view controller's view will be visible and not the presenting view controller's view. For example if you set presented view controller's view's opacity to 50% and use UIModalPresentationFullScreen you will not be able to see presenting view controller's view underneath the presented but if you use UIModalPresentationOverFullscreen - you will (UIPresentationController's shouldRemovePresentersView method is responsible for specifying that).

Why not allow the animator manipulate the presenting view controller's view at all times? First of all, if the presenting view controller's view is going to stay visible after the animation finishes during the whole presentation life cycle there is no need to animate it at all — it just stays where it is. Second, if the ownership for that view controller is transferred to the presentation controller, the presentation controller will most likely not know how to layout that view controller's view when needed for example when the orientation changes, but the original owner of the presenting view controller does.

In iOS 8 viewForKey: method was introduced to get views that the animator manipulates. First, it helps to follow the rule described above by returning nil whenever the animator should not touch the view. Second, it may return a different view for the animator to animate. Imagine that you are implementing a presentation similar to form sheet. In this case you would want to add some shadow or decoration around the presented view controller's view. The animator will animate that decoration instead and the presented view controller's view will be a child of the decoration.

viewControllerForKey: doesn't go away, it can still be used if a direct access to view controllers is needed but the animator should not make any assumptions about the views it needs to animate.

There are several things you can do to correctly fix an issue with a disappearing presenting view controller's view when you explicitly place it inside the animator's container view:

  1. If do not need to animate the presenting view controller's view, use viewForKey: to get views to animate instead of reaching out to view controller's views directly. viewForKey: may return nil or even completely different views.

  2. If you want to animate the presenting view controllers's view you should consider using UIModalPresentationFullScreen style or continue using UIModalPresentationCustom and implement your own subclass of UIPresentationController with shouldRemovePresentersView returning YES. In fact, the implementation of this method is the main difference between internal presentation controllers defined by UIModalPresentationFullScreen and UIModalPresentationCustom styles apart from the fact that the latter allows you to use custom presentation controllers.

  3. In all other rare cases you will have to return the presenting view controller's view to its original location as other answers suggested.

Lunalunacy answered 17/9, 2014 at 22:10 Comment(4)
That's super-weird because this code relies on viewControllerForKey:'s views only when viewForKey: returns nil, and I still had to re-add it to the window manually. Do you have an example of code working without this workaround?Maidinwaiting
Well, if viewForKey: returns nil then for sure you will have to re-add the presenting view controller's view to the window if you remove it from it in your animator. In case viewForKey returns the actual view controller's view it is safe to move that view because UIKit would move it back to it's original position after the presentation lifecycle is over.Lunalunacy
Thank you for explaining the reasoning behind this issue. You're absolutely right. Moving the view's position in the view hierarchy without replacing it would obviously make it disappear (post iOS 8, and I'm working with iOS 10 right now!) Thanks for clarifying.Va
Thanks egdmitry for your clarification. Which raise another question which is: how do you think I should implement a reveal like presentation? One of those very common nowadays where the presenting view slides partially out to show the presented view underneath? In this scenario both the presenting and presented views need to be onscreen and the presenting view is the one animated.Campground
R
70

In iOS 8, you must manipulate the views returned by viewForKey: instead of the .view property of the view controllers returned by viewControllerForKey:. This isn't particularly clear from the beta documentation, but if you look into the source for UIViewControllerTransitioning.h you'll see this comment above 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;

So instead of adjusting frames etc of toViewController.view, use the return value of [transitionContext viewForKey:UITransitionContextToViewKey].

If your app needs to support iOS7 and/or Xcode 5, then you can use a simple category method on UIViewController like the following:

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

Then, get your toViewController and fromViewController as usual, but get the views using [toViewController viewForTransitionContext:transitionContext].

Edit: There appears to be a bug, where the presenting view controller's view is nil when returned from viewForKey, which prevents you from making modal transitions that animate the presenting view at all (such as sliding off, or flip-horizontal). I filed a bug for iOS8 at rdar://17961976 (http://openradar.appspot.com/radar?id=5210815787433984). Also see the sample project at http://github.com/bcherry/TransitionBug

Edit 2: Thanks to graveley for the suggestion, using UIModalPresentationFullScreen fixes the issue. Perhaps this is not a bug. Apple may intend that UIModalPresentationCustom only modifies the view of the incoming modal. If you want to modify the outgoing view, you need to guarantee full screen presentation of the new view? In any case, you should use viewForKey and UIModalPresentationFullScreen.

Revolution answered 7/8, 2014 at 23:6 Comment(8)
The viewForKey bug was driving me crazy!— thanks for filing. FWIW my transition is working fine by getting the view from UITransitionContextToViewControllerKey, but my transition is only applying a transform to the entire view. I'm not sure if that should be interpreted as manipulating the VCs views or not...Exhilarant
Wow – that's nuts. I didn't see that in the diffs – probably because it's just some little comment. Really frustrating when Apple pulls a stunt like this. Fingers crossed about your radar.Maidinwaiting
I'm seeing the viewForKey bug in the GM as well. Are others as well? Have you found a reasonable workaround for it?Dicephalous
I don't have any other workaround besides what @AshFurrow posted in the other answer. My bug report is still open and untouched.Revolution
I thought according to comment of - viewForKey // viewForKey: may return nil which would indicate that the animator should not manipulate the associated view controller's view. Returning nil is not a bug.Affairs
@KenKuan yeah but if it always returns nil then it's impossible to use the framework to implement animations where the source view moves or transforms (page curl, horizontal flip, slide-out, or anything else you can think of)Revolution
@kenKuan you might be right. when using UIModalPresentationFullScreen, viewForKey does return the from view and the to view. So maybe it's intentional that it returns nil for UIModalPresentationCustom. I'm updating my bug report and will post back here if I hear back from Apple about it.Revolution
If only I could thumb this up a hundred more times.Jarboe
D
25

Not setting modalPresentationStyle to UIModalPresentationCustom fixed the issue for me.

In other words, leaving at the default of UIModalPresentationFullScreen instead of specifying UIModalPresentationCustom fixed the disappearing view issue. Note the UIViewControllerTransitioningDelegate protocol still seems to be followed even when leaving this at the default. If i recall correctly, once upon a time UIModalPresentationCustom was a requirement.

Works so far, have only tried this for non-interactive animations.

Disherison answered 4/9, 2014 at 0:27 Comment(4)
wow. That did it! I tested without modalPresentationStyle in iOS7 & 8 and it works find in both. Thanks!!Entozoon
Thank you! This combined with using viewForKey: instead of .view on the viewControllerForKey: fixes all issues for me.Revolution
This fixed the problem for me without using viewForKey, but I suppose that should be used as well.Intosh
Although this seems to fix the problem, it is important to note that the screen behind your view controller will become black once it is displayed. This is important if your view controller is not full screen.Metameric
A
19

I've found this extremely useful answer in a related thread by Lefteris: https://mcmap.net/q/204912/-animating-the-presenting-view-in-a-uipresentationcontroller

To sum it up:

  1. set modalPresentationStyle to .Custom
  2. subclass UIPresentationController, override shouldRemovePresentersView (with NO)
  3. override presentationControllerForPresentedViewController in your TransitionDelegate class and return your custom UIPresentationController

+1 in your custom transition, don't add toView when the dismissal animation is happening.

Demonstrated here:

https://www.dropbox.com/s/7rpkyamv9k9j18v/CustomModalTransition.zip?dl=0 without any hacks! it's like magic! :)

Akela answered 19/7, 2015 at 14:59 Comment(3)
This is the actual right answer. Without magic tricks like in the accepted one. Thanks, Mark !Maricela
Unfortunately, this doesn't work in iOS 12.4, Xcode 10.3. The screen turns black after the transition completes (all views have been removed from the hierarchy. However, setting the 'modalPresentationStyle' property to '.fullscreen' DOES work. Cheers.Melvin
I tried the Obj-C version from Mark and gwinyai's Swift implementation in my project. Unfortunately none of them is working as expected. I am using Xcode 11.1 and build target is iOS 13.0, I tried on both device and simulator. In my case, my basic set up is a collection view and when you tap one cell it will segue to a detail view with animation. However, it works totally fine if I am using the default transition animation. The presenting VC will not be gone when I resume from the details the view.Seato
F
8

instead of [inView insertSubview:toViewController.view aboveSubview:fromViewController.view]; just add: [inView addSubview:toViewController.view];

if (self.presenting) {

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

} else {
    // your code
}

You can see an example here: link and it works on iOS 7 and iOS 8

Flew answered 10/7, 2014 at 18:38 Comment(2)
This should be the accepted answer for doing a UIModalPresentationStyleCustom type of animation since there is no need to add the fromViewController to the containerView. You only need to add the toViewController during the presenting animation.Clarify
This is very helpful, actuallyMaribelmaribelle
C
8

In iOS 8, you need create a UIPresentationController and implement the method below, in the UIViewControllerTransitioningDelegate.

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

Asks your delegate for the custom presentation controller to use for managing the view hierarchy when presenting a view controller.

Return Value:

The custom presentation controller for managing the modal presentation.

Discussion:

When you present a view controller using the UIModalPresentationCustom presentation style, the system calls this method and asks for the presentation controller that manages your custom style. If you implement this method, use it to create and return the custom presentation controller object that you want to use to manage the presentation process.

If you do not implement this method, or if your implementation of this method returns nil, the system uses a default presentation controller object. The default presentation controller does not add any views or content to the view hierarchy.

Availability Available in iOS 8.0 and later.

For more information watch the WWDC 2014 video:

https://developer.apple.com/videos/wwdc/2014/?include=228

There's also a sample code from the WWDC called "LookInside: Presentation Controllers Adaptivity and Custom Animator Objects", which you can download from the WWDC 2014 sample code page.

You may need to change the sample code a little bit. The UIPresentationController init method changed to:

initWithPresentedViewController:presented presentingViewController:presenting

Before it was presenting and then presented. Just swap them and it should work.

Cavalier answered 10/9, 2014 at 21:56 Comment(1)
Sorry for not watching the linked video, but I don't think you need a custom UIPresentationController unless you want a non-standard presentation after the animation completes, like a circular presented view. If you just want a different animation, implementing UIViewControllerAnimatedTransitioning should be enough, based on my limited knowledge.Nuthouse
T
7

Here is an Objective C version of Ash's fix.

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

I had to swap the order and call the [transitionContext completeTransition:] method after adding the view back in to get presenting a new view controller from the dismissal completion block of another view controller to work right.

I don't know that this'll fix it for everyone but it works in my app. Cheers!

Turoff answered 10/9, 2014 at 21:59 Comment(0)
H
5

I found this worked fine for Obj-C:

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

Seems to work fine on both ios7 and ios8.

Hassle answered 16/9, 2014 at 12:14 Comment(0)
S
5

I found that viewForKey:UITransitionContextToViewKey returns nil on ios8. So if it's nil, I grab the view from the 'to' view controller.

However, this seems to result in the 'to' view not being moved from the container to the window when completeTransition:YES is called. So if viewForKey:UITransitionContextToViewKey returns nil, I fall over to toVC.view, and keep track of the fact that it returned nil, and after the completion I move it to the container's initial superview (which happens to be the window).

So this code works on iOS7 as well as iOS8, and should work on iOS9 too even if they fix it or not.

- (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: https://mcmap.net/q/202475/-quot-from-view-controller-quot-disappears-using-uiviewcontrollercontexttransitioning
    // 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];
        }
    }];
}
Stereography answered 17/4, 2015 at 3:35 Comment(0)
S
3

I found that this bug (and many more!) vanishes if you set modalPresentationStyle = UIModalPresentationFullScreen. You of course still get your custom transition animation.

Stereography answered 15/5, 2015 at 5:20 Comment(0)
S
2

I got stuck on this issue too. I was looking to create a custom transition with a semi-transparent background where I could still see the view controller I was coming from but I only got a black background. I found Mark Aron's answer in this thread helped me but it is written in Objective C so here is a Swift 3 version of that answer which I have tested for iOS 9 and iOS 10:

  1. Create a subclass of UIPresentationController. Override the shouldRemovePresentersView to false as follows:

    class ModalPresentationController: UIPresentationController {
    
    override var shouldRemovePresentersView: Bool {
    return false
    }
    
    override func containerViewWillLayoutSubviews() {
    presentedView?.frame = frameOfPresentedViewInContainerView
    }
    }
    
  2. In the place you are instantiating the new view controller and setting its transition delegate, indicate that you want it to show a custom modal presentation style as follows:

    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. Now override the presentationController method of your UIViewControllerTransitioningDelegate and return your custom UIPresentationController. I had mine as an extension to my current class:

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

One other thing to note is you should not try and reference your fromView in your presentAnimator class. This will be nil and you will get an error at runtime. Other than that if you implement things like things you will get your custom transition with its animation and a semi-transparent background if you make one.

Shinshina answered 24/12, 2016 at 15:7 Comment(1)
This iis is a great example for doing a custom modal presentation in Swift 3! Thanks @gwinyai! I got super stuck on this until I found an example that showed the new swift 3 API for presentationController(forPresented presented UIViewController,... because the previous swift API didn't upset the complier but didn't get called.Groat
L
2

After encountering this issue, I was very confused, because I'd written something almost identical not too long ago that worked fine. Came here looking for answers to find fixes that look pretty hacky, and don't seem to understand the root cause... it's actually very easy to fix.

Some answers mention changing modalPresentationStyle to .overFullScreen. This is correct, .overCurrentContext would work too. This is expected, and the behaviour Apple documents. But why isn't this working for everyone? Why all the hacky code, and combinations of this with something else, and crazy stuff that you shouldn't be doing?

Turns out, you need to set the presentation style BEFORE THE VIEW LOADS. Not after. Do it in init, or do it from the previous controller, or however you'd like - as long as it is before the view loads.

Lenka answered 29/1, 2017 at 0:15 Comment(1)
I set the presentation style to .overCurrentContext before the view load (in the init of the view controller) and the issue still happensCambell
S
1

Using the new UIModalPresentationOverCurrentContext fixed it for me. My original transition on iOS 7 was just to have a blurred background of the view underneath the modal.

Siqueiros answered 14/12, 2014 at 21:45 Comment(2)
For some reason, this doesn't seem to allow interaction with the view underneath, where UIModalPresentationCurrentContext did in iOS 7.. Any thoughts?Pede
Hmm for me on iOS 10, .overCurrentContext results in this bug but .fullscreen does not. I came here hoping for a fix for using .overCurrentContext but so far nothing seems like it'll work in iOS 10 except maybe subclassing UIPresentationController...Groat
S
0

Ok, guys, I think that I solve one case that 'a working animator' stops working properly when you build app in iOS 13 and above.

Env Xcode 11.1, iOS 13.1

Problem

What I want to do is very simple: I have a collection view, when a cell is tapped, it will segue to a detail view. Instead of using the boring default style of 'present modally', I want to make it more interesting, so I wrote an animator for view controller transition.

I set up the segue in IB by drag-and-drop from my collection VC to the detail VC. The style of segue is 'Present modally' and presentation is set to 'Full Screen'.

When it shows the detail view, everything works as expected. However, when I dismiss the detail view and return to the collection view, I can only see the animated detail view, the collection view is just gone. I poked here and there and I have a few discoveries

1.Right after the following line is called from function 'animateTransition()', the collection view resumes and shows up

transitionContext.completeTransition(true)

2.As long as the detail view is not fully cover the collection view, the collection view will not disappear when it segues back from detail view

Solution

To be honest, I know little about how the animated transition works. So I can only follow this post and the other one, try each of the answers. Unfortunately, none of them works for me. Finally, I came to a point where the only thing I can tweak is the presentation style of segue in IB (which I should have done at very very beginning). When I set the presentation to 'Over Full Screen', miracle happens and my problem is solved. The detail view could show in full screen with animation and when it dismissed, I can see both collection view as background and animated detail view.

Then one more discovery along the road

3.To refer to 'toView' and 'fromView', both of the following methods work

Indirectly way:

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

Directly way:

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

But when I switched the segue style to 'Over Full Screen', the directly way return 'nil' for both 'toView' and 'fromView' and only indirectly way works, this problem is also mentioned in another post, so I think it's worth to post my little discovery here.

Hope this will be helpful to someone in the future.

Seato answered 16/11, 2019 at 2:25 Comment(0)
E
0

I was having the same problem when dismissing a content view controller.

My app has this parent view controller showing a child view controller (presenting vc) modally. Then when a subview in the childVC is tapped, it shows another vc (which I am calling the content view controller (presented vc))

My problem is that, when Dismissing the contentVC (now the presenting vc), it should go to child VC (now the presented VC) but as soon as my custom transition finishes, childVC suddenly disappears, showing the parent VC.

What I did to solve this issue is to

  1. change the .modalPresentationStyle of the childVC presented by parentVC from the default .automatic to .fullscreen.
  2. Then changed the .modalPresentationStyle of contentVC to .fullscreen as well.

This solves the issue. but it won't show your child VC as a card-style sheet on top of parentVC (when using .overCurrentContext or automatic) which is new in iOS 13.

Would love to know if there are any solution that will retain the card-style sheet for the childVC when presented by parent.

Eikon answered 24/4, 2020 at 6:35 Comment(0)
H
-3

adds a view controller as a child of another view controller.

[self addChildViewController:childViewController];                 

check and let me know.

Heliogravure answered 21/6, 2014 at 6:21 Comment(3)
i am not getting , can you describe it using coding ?Melessa
check this apple documentation developer.apple.com/library/ios/featuredarticles/…Heliogravure
this in no way answers the question. ChildViewControllers are not involved in any part of custom transitions, they are a completely different subject.Chinfest

© 2022 - 2024 — McMap. All rights reserved.