Latest Update: A better way to implement push segue animation without UINavigation bar
Apple provides three styles of Storyboard Segue, push segue, modal segue and custom segue. Push segue is a predefined segue with a horizontal sliding animation. To make it works, we have to integrate our view controller with UINavigationController. Sometimes, we don’t want to have a UINavigation Bar, but want to use push segue between viewcontroller transition. We may find that it won’t work. Alternatively, we can use modal segue instead. In modal style, there are four transitions including Cover Vertical, Flip Horizontal, Cross Dissolve and Partial Curl. However, there is no horizontal sliding animation effect. Hence, we have to use custom style segue. Here is a video to show you how we can create a horizontal sliding animation transition by custom segue.


Horizontal Sliding Custom Segue Example

In this example, we will put two viewcontroller on the storyboard, using custom segue HorizontalSlideSegue to connect each of them. Here is the HorizontalSlideSegue code example:

- (void) perform
{
    UIViewController *desViewController = (UIViewController *)self.destinationViewController;
    
    UIView *srcView = [(UIViewController *)self.sourceViewController view];
    UIView *desView = [desViewController view];
    
    desView.transform = srcView.transform;
    desView.bounds = srcView.bounds;
    
    if(isLandscapeOrientation)
    {
        if(isDismiss)
        {
            desView.center = CGPointMake(srcView.center.x, srcView.center.y  - srcView.frame.size.height);
        }
        else
        {
            desView.center = CGPointMake(srcView.center.x, srcView.center.y  + srcView.frame.size.height);
        }
    }
    else
    {
        if(isDismiss)
        {
            desView.center = CGPointMake(srcView.center.x - srcView.frame.size.width, srcView.center.y);
        }
        else
        {
            desView.center = CGPointMake(srcView.center.x + srcView.frame.size.width, srcView.center.y);
        }
    }
    
    
    UIWindow *mainWindow = [[UIApplication sharedApplication].windows objectAtIndex:0];
    [mainWindow addSubview:desView];
    
    // slide newView over oldView, then remove oldView
    [UIView animateWithDuration:0.3
                     animations:^{
                         desView.center = CGPointMake(srcView.center.x, srcView.center.y);
                         
                         if(isLandscapeOrientation)
                         {
                             if(isDismiss)
                             {
                                 srcView.center = CGPointMake(srcView.center.x, srcView.center.y + srcView.frame.size.height);
                             }
                             else
                             {
                                 srcView.center = CGPointMake(srcView.center.x, srcView.center.y - srcView.frame.size.height);
                             }
                         }
                         else
                         {
                             if(isDismiss)
                             {
                                 srcView.center = CGPointMake(srcView.center.x + srcView.frame.size.width, srcView.center.y);
                             }
                             else
                             {
                                 srcView.center = CGPointMake(srcView.center.x - srcView.frame.size.width, srcView.center.y);
                             }
                         }
                     }
                     completion:^(BOOL finished){
                         //[desView removeFromSuperview];
                         [self.sourceViewController presentModalViewController:desViewController animated:NO];
                     }];
}

In the ViewController, we override the method prepareForSegue to config the custom segue. Here is the source example,

- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
    HorizontalSlideSegue *s = (HorizontalSlideSegue *)segue;
    s.isDismiss = NO;
    
    if (UIDeviceOrientationIsLandscape([UIDevice currentDevice].orientation))
    {
        s.isLandscapeOrientation = YES;
    }
    else
    {
        s.isLandscapeOrientation = NO;
    }
}

To dismiss the Push Custom segue, we will change the prepareForSegue function a little bit in the second ViewController. It is very simple as well.

- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
    HorizontalSlideSegue *s = (HorizontalSlideSegue *)segue;
    s.isDismiss = YES;
    
    if (UIDeviceOrientationIsLandscape([UIDevice currentDevice].orientation))
    {
        s.isLandscapeOrientation = YES;
    }
    else
    {
        s.isLandscapeOrientation = NO;
    }
}

Push Segue Without UiNavigation Controller Custom Segue Example Source Code

Latest Update: Support for multiple ViewController in Source Code
Get this example under $2.99. With this source code, you can use HorizontalSlideSegue in your project, so that you can implement the Push Segue style without using UiNavigation controller or UiNavigation Bar.





In this example source code, it includes:

  • ViewController.m, first View viewcontroller class
  • DestViewController.m, second View viewcontroller class
  • ThirdViewController.m, third View viewcontroller class
  • HorizontalSlideSegue.m, custom segue class
Previous PostNext Post

25 Comments

  1. Hi James,

    I’m adding a third view controller to check the HorizontalSlideSegue functionality working with several views, but unfortunately it’s not working.

    Can you please let me know why?

    1. Hi, Chris,

      I have check my source code. According to your requirement, I have improved my source code a little bit to support multiple view. You can watch the video to find out how to config the viewcontroller in storyboard.

      After that, you need to update the prepareForSegue function a little bit. You need to check the segue identifier to set isDismiss. For forward segue, please set isDismiss to NO. Otherwise, please set isDismiss to YES.

      Thanks

  2. Hi,

    All source code is updated. Now it can support multiple views for forward and backward segue modal.

    Thanks

  3. i purchased the code and am having a hard time changing it over from an iPhone to an iPad. What i really need to do is implement this into an existing app i built.

    1. Hi Brent,

      I think it should be very easy to use in your project. If you are using model segue, just change it to custom, and use my class name. I put how-to in my videos. What problems are you facing?

      Best Regards
      James

  4. I brought in the class and now the app crashes when i run it. I get the following…

    return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class]));

    I am new to all this and maybe i am doing something wrong.

    Can you point me to to a detailed tutorial to follow?

    1. Hi Brent,

      Your error message is too generic. I guess there are some null variable you are accessing when you are switching views. You can check if you are doing something in “viewDidLoad” and “viewDidappear”.

  5. I found more about the error…

    *** Terminating app due to uncaught exception ‘NSInvalidArgumentException’, reason: ‘-[UIStoryboardModalSegue setIsLandscapeOrientation:]: unrecognized selector sent to instance 0x8c515c0’

    Now i kinda have it working but i can still get the above error.
    – My first issue was that i have a landscape app and i had to set my views to inferred. That got the transition to work.

    – It still gives me the above error if i use a standard model transition.

    – If i disable the portrait views than the transition always happens landscape based on the orientation of the device.

    1. – It still gives me the above error if i use a standard model transition.

      If you want to use “standard model transition”, you have to comment the code “s.isLandscapeOrientation” in prepareForSegue in your viewcontroller.

  6. Hi, the example works. Thanks for the post.
    But if I have a text field in the dest view, and set the text field as the first responder, i.e., shows the cursor in the text field and brings up the keyboard, the first responder crashes when using the custom HorizontalSlideSegue.

    Do you have any suggestions on this problem? How can I set up a first responder field at the dest view when using the custom segue?

    Thanks.

    1. How do you set the first responder? In viewDidAppear or viewDidLoad? I suggest you to all your jobs which are related to UI in viewDidLoad

      1. I have tried setting the first responder in viewDidLoad(), viewWillAppear() and viewDidAppear(), separately, but none of them worked.

        After clicked the button and triggered the segue, the dest view was showed, in the nice horizontal slide transition mode, the cursor appeared in the first responder text field, the keyboard showed up a little while, and then slide down and disappeared, and I could n’t type since there was no keyboard. When I tried to click in the first responder field, it shows the following error:

        “: CGContextSetFillColorWithColor: invalid context 0x0. This is a serious error. This application, or a library it uses, is using an invalid context and is thereby contributing to an overall degradation of system stability and reliability. This notice is a courtesy: please fix this problem. It will become a fatal error in an upcoming update.”

        Thanks.

        1. It seems that the dest view viewDidLoad happens before the segue transition animation completes. Taking care of the timing of these actions solved the problem.

          Thanks.

        2. I will write some testing on your scenario. To be sure to solve your problem, can you please pass me that piece of code which cause you the problem. If you can send the the whole file, it will be wonderful.

          1. Thank you for the reply, James. The problem is solved by setting the first responder after the transition animation is completed.

            Thanks.

  7. Hey, i just bought this code and get this error message.

    Terminating app due to uncaught exception ‘NSInvalidArgumentException’, reason: ‘Could not find a segue class named ‘HorizontalSlideSegue”.

    All the files are in in my project and everything is #imported. Any solution?

    1. Hi,

      It seems that your project can not find HorizontalSlideSegue class. You’d better to double check your project. One solution is you can delete the class file and create a new HorizontalSlideSegue class and copy the source code back.

      Thanks

  8. Is it possible to use both Horizontal Slide Segues and Standard Modal Segues? I’m having similar problems to Brent I think. I’m trying to use the Horizontal Slide Segue to slide back from a page but also use a Standard Modal Segue to make a different page appear. It’s a landscape app but when I comment the code “s.isLandscapeOrientation” my transitions are now moving vertically rather than horizontally. And when I uncomment (which makes the transitions work) the modal segues break the app with the same warning as Brent received.

    Many thanks for any advice. (Complete programming newbie)

    1. Hello Matt,

      I think your problem is solvable. But you have to add more flag to control if my code should be running. The logic is not that complicated. My advice is reading the code and try to completely understand what they are doing. After that, your problem will be very easy to solve.

      Best Regards
      James

  9. Hello James,

    great code.
    I have however one issue i can’t seem to solve.
    the segue goes horizontally, but always to the right.
    so to view 2 it goes correct, but back to view 1 it doesn’t move left.

    do you have any tips on this?

    thanks a lot!

      1. Hi James,

        Many thanks for the quick reply!
        sorry, am a bit of a newbie in this field,
        but i get errors in using the *s in my viewcontroller.m file with that part of the code.

        Thanks!

Leave a Reply to Brent Cancel reply

Your email address will not be published. Required fields are marked *