Juan González
Juan González

Reputation: 1526

Wait until animation block finishes before segue

I'm implementing some simple animations to my cards app.

Everything is working great so far but I have just one more detail to fix before I can say it is done.

The scenario is pretty simple:

Three cards must exit the screen with an animation before segue modally brings up the new screen.

Up until now he animation gets executed and the new view is loaded, but the detail I haven't been able to work out is the "wait until the animation finishes before bringing the new view".

This is how I'm doing it:

1) Set exit animation with this method

- (void)performExitAnimationWithCompletionBlock:(void (^)(BOOL))block
{    
    [UIView animateWithDuration:0.1f
                          delay:0.0f
                        options:UIViewAnimationOptionCurveEaseOut
                     animations:^
     {
         self.optionOneFront.center = self.optionOneBack.center = self.optionTwoFront.center;
         self.optionOneFront.transform = self.optionOneBack.transform = self.optionTwoFront.transform;

         self.optionThreeFront.center = self.optionThreeBack.center = self.optionTwoFront.center;
         self.optionThreeFront.transform = self.optionThreeBack.transform = self.optionTwoFront.transform;
     }
                     completion:^(BOOL finished)
     {
         CGPoint point = CGPointMake(self.optionTwoFront.center.x, self.view.frame.size.height * -2.0f);

         [UIView animateWithDuration:1.0f
                               delay:0.0f
                             options:UIViewAnimationOptionCurveEaseOut
                          animations:^
          {
              self.optionOneFront.center   = point;
              self.optionOneBack.center    = point;
              self.optionTwoFront.center   = point;
              self.optionTwoBack.center    = point;
              self.optionThreeFront.center = point;
              self.optionThreeBack.center  = point;
          }
                          completion:block];
     }];
}

2) Try to wrap the segue code within the animation before presenting the "AddOptions" VC

- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
    [self performExitAnimationWithCompletionBlock:^(BOOL finished)
     {
         // Executes the following "if" statement if the user wants to add new options
         if ([segue.identifier isEqualToString:@"AddOptions"])
         {
             UINavigationController *navigationController = segue.destinationViewController;
             OptionsViewController *controller = (OptionsViewController *)navigationController.topViewController;
             controller.delegate = self;
         }         
     }];    
}

As I said before, everything works but the modal windows comes up before the animation finishes.

Any idea of what I'm missing?

Upvotes: 3

Views: 7545

Answers (1)

pdriegen
pdriegen

Reputation: 2039

Instead of triggering the animation in the prepareForSeque method, you should try calling [self performExitAnimationWithCompletionBlock] when you want to start the animation process, and then trigger the seque manually using the [self performSegueWithIdentifier] method in the completion block of the final animation.

I'll assume that your seque it currently connected to a button touch in your storyboard. If that's the case you'll have to disconnect it in the storyboard. Perhaps you can keep the seque alive by connecting to an invisible button on your storyboard so that it can never be automatically fired.

Instead, write the button code like so:

-(void)btnStartSeque:(id)sender{

      //trigger animations

      [self performExitAnimationWithCompletionBlock:^(BOOL finished){
         [self performSegueWithIdentifer:@"AddOptions" sender:self];
     }];    
}

- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender{

   // Executes the following "if" statement if the user wants to add new options
    if ([segue.identifier isEqualToString:@"AddOptions"])
    {
      UINavigationController *navigationController = segue.destinationViewController;
      OptionsViewController *controller = (OptionsViewController *)navigationController.topViewController;
      controller.delegate = self;
    }               
}

An alternative (and perhaps better?) solution to get the functionality you want is not to use a seque at all, but instead manually transition the screen. In this case, delete the seque entirely from the storyboard. Also ensure you provide an identifier for OptionsViewController in the storyboard. Execute the following code on the action that causes the animation/transition:

-(void)btnStartModalTransition:(id)sender{

      //trigger animations

      [self performExitAnimationWithCompletionBlock:^(BOOL finished){

          //load the storyboard (sub in the name of your storyboard)
          UIStoryBoard* storyBoard = [UIStoryBoard storyBoardWithName:@"MyStoryBoard" bundle:nil]
          //load optionsviewcontroller from storyboard
          OptionsViewController *controller = (OptionsViewController *)[storyBoard instantiateViewControllerWithIdentifier:@"OptionsViewControllerIdentifier"];
          UINavigationController *navigationController = [[UINavigationController alloc] initWithRootViewController:controller];

         controller.delegate = self;
         [self presentModalViewController:navigationController animated:YES];
     }];    
}

Upvotes: 3

Related Questions