0

I have subclassed UIStoryboardSegue to create a Left to Right Segue. The segue works, however, there is a black vertical bar or background that is momentarily visible between the two View Controllers that mars the effect. (I want the segue to look like a normal right to left show segue but in the opposite direction). Does anyone know what could be causing this or how to get rid of it? Here is my code:

#import "customSegue.h"
#import "QuartzCore/QuartzCore.h"

@implementation customSegue

-(void)perform {

    UIViewController *sourceViewController = (UIViewController*)[self sourceViewController];
    UIViewController *destinationController = (UIViewController*)[self destinationViewController];

    CATransition* transition = [CATransition animation];
    transition.duration = .25;
    transition.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut];
    transition.type = kCATransitionPush; //kCATransitionMoveIn; //, kCATransitionPush, kCATransitionReveal, kCATransitionFade
    transition.subtype = kCATransitionFromLeft; //kCATransitionFromLeft, kCATransitionFromRight, kCATransitionFromTop, kCATransitionFromBottom



    [sourceViewController.navigationController.view.layer addAnimation:transition
                                                                forKey:kCATransition];

    [sourceViewController.navigationController pushViewController:destinationController animated:NO];

}
@end

Edit:

I thought I would collect some the suggested fixes I have found although none are working for me.

Set the background color of the presenting view controller to white

Set self.definesPresentationContext = YES; on the presenting view controller or check "Defines Context" for the VC in storyboard from accepted answer here.

Specify the context as follows:

UIViewController *rootViewController = [UIApplication sharedApplication].delegate.window.rootViewController;
    rootViewController.modalPresentationStyle = UIModalPresentationCurrentContext;
    UIViewController *destinationController = (UIViewController*)[self destinationViewController]
    [sourceViewController presentViewController:destinationController animated:NO completion:nil];

from accepted answer here.

user6631314
  • 1,751
  • 1
  • 13
  • 44

1 Answers1

1

What you're seeing is the view's changing opacity near the beginning and end of the animation, so the "black bar" you're seeing is actually the backing window. While it might not be perfect, a quick fix is to change the background color of your window to match the background color of your destination view controller (then set it back after the transition completes if needed).

Here's your code example with the modifications necessary:

-(void)perform {
    UIViewController *sourceViewController = (UIViewController*)[self sourceViewController];
    UIViewController *destinationController = (UIViewController*)[self destinationViewController];

    CATransition* transition = [CATransition animation];
    CGFloat animationDuration = 0.25f;
    transition.duration = animationDuration;
    transition.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut];
    transition.type = kCATransitionPush; //kCATransitionMoveIn; //, kCATransitionPush, kCATransitionReveal, kCATransitionFade
    transition.subtype = kCATransitionFromLeft; //kCATransitionFromLeft, kCATransitionFromRight, kCATransitionFromTop, kCATransitionFromBottom
    transition.fillMode = kCAFillModeForwards;



    [sourceViewController.navigationController.view.layer addAnimation:transition
                                                                forKey:kCATransition];
    // hold onto the previous window background color
    UIColor *previousWindowBackgroundColor = sourceViewController.view.window.backgroundColor;
    // switch the window background color to match the destinationController's background color temporarily
    sourceViewController.view.window.backgroundColor = destinationController.view.backgroundColor;
    // do the transition
    [sourceViewController.navigationController pushViewController:destinationController animated:NO];
    // switch the window color back after the transition duration from above
    dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(animationDuration * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
        // make sure we still have a handle on the destination controller
        if (destinationController) {
            destinationController.view.window.backgroundColor = previousWindowBackgroundColor;
        }
    });
}

Here's an example of the transition slowed down to 2seconds:

Slowed down transition

And the animation at 0.25 as you have it in your code:

Your speed transition

R4N
  • 2,455
  • 1
  • 7
  • 9
  • I agree that Apple should have a neater way to make this work but your approach does the job! BTW, what would you estimate the speed of the regular show segue to be? I have tried various values and .45 seems about right but it's hard to say. (also probably depends on transition style. In above code I use kCAMediaTimingFunctionEaseInEaseOut but Apple says ...Default is used by most system transitions – user6631314 Sep 08 '18 at 21:51
  • I got ~0.52s when doing the time calculation from right before the push happened, to once viewDidAppear: was called in the second VC. You could do similar time calculations with your own custom transitions to try to get it to match up with that. – R4N Sep 10 '18 at 11:38