swampf0etus
swampf0etus

Reputation: 411

Custom transition between UIViewControllers

I've just changed my app from being TabView driven to CollectionView driven, as there are too many sections of my app to be feasible for a TabView. When you start the app you are presented with several items in a CollectionView and selecting any of these items will take you to the relevant section of the app.

In XCode, the collection view lives in its own storyboard and each section of the app has its own storyboard.

In the CollectionView's didSelectItemAtIndexPath, I launch the relevant starboard as follows;

UIStoryboard *storyboard = [UIStoryboard storyboardWithName:@"relevant_storyboard" bundle:nil];
UIViewController* vc = [storyboard instantiateInitialViewController];
[self presentViewController:vc animated:YES completion:nil];

Now, none of the built-in transition animations really suit launching from a CollectionView, so I'd really like a custom effect, such as zoom in. However, I'm struggling to find any decent examples that work for me to create any kind of custom transition. I've tried [UIView transitionFromView], but I don't think that suits transitioning between UIViewControllers. I've tried transitionFromViewController:toViewController: but don't think I have the view hierarchy set up correctly. I've also tried using CATransition without success.

I've thought about doing it with a custom segue but, as my CollectionView is in it's own storyboard and have separate storyboards for each section of my app, I can't see how I can do this. At least not without having all sections of the app inside one storyboard, which would make the storyboard huge and difficult to manage.

So, can anyone give me any code examples or pointers on how I can solve this?

Upvotes: 0

Views: 1494

Answers (2)

user2277872
user2277872

Reputation: 2973

Have you tried the UIView animation block?

 [UIView animationWithDuration:1.0 animation^ {
    // do custom animation with the view
 }completion:^(BOOL finished) {
     if(finished) {
        NSLog(@"Finished");
     }
 }];

It allows you to do custom animations when dealing with UIView(s), and even with UIViewControllers. I use it alot when dealing with custom animation actions.

EDIT:

for example, if you'd like to make the view of the current controller to move up the screen, and the second view controller to slide down in place of it, just do

 [UIView animationWithDuration:1.0 animation^ {
    // do custom animation with the view
    // make sure CoreGraphics.framework is imported
    // sliding current view to the top of the screen
    self.view.transform = CGAffineTransformMakeTranslation(0,0);

    // sliding 2nd view down..
    // uncomment the following line, and one of the options for translation
    //SecondView *sv = [[SecondView alloc] init];
    // just edit the x,y in CGAffineTransformMakeTranslation to set where it will go
    //sv.view.transform = CGAffineTransformMakeTranslation(320, 480) // iphone 4
    //sv.view.transform = CGAffineTransformMakeTranslation(768, 1024) // ipad 1

 }completion:^(BOOL finished) {
     if(finished) {
        NSLog(@"Finished");
     }
 }];

Hope this helps!

Upvotes: 1

architectpianist
architectpianist

Reputation: 2552

In my app I used a similar effect to zoom in from a thumbnail in a collection view cell to a child view controller that took up the entire screen. You could conceivably do the same thing for a navigation controller push as well.

In my code, I had a scoreView property on the cell subclass that I wanted to zoom up into the full screen. In your case, you may want to use a UIImageView with a screenshot of your new view. Alternatively, you could present the new view controller with a screenshot of the old view controller and then animate from there.

//Instantiate the view controller to be animated in...

//If the cell is not completely inside the collection view's frame, a dissolve animation might be more graceful.
BOOL dissolveAnimation = !CGRectContainsRect(CGRectMake(0, 0, self.collectionView.frame.size.width, self.collectionView.frame.size.height), cellRect);

//Get the frame of the cell in self.view coordinates, then the frame of the thumbnail view
CGRect cellRect = [self.collectionView layoutAttributesForItemAtIndexPath:indexPath].frame;
cellRect = CGRectOffset(cellRect, 0.0, -self.collectionView.contentOffset.y);
VSScoreCell *scoreCell = (VSScoreCell *)[self.collectionView cellForItemAtIndexPath:indexPath];
CGRect scoreRect = dissolveAnimation ? CGRectMake(0.0, 0.0, self.view.frame.size.width, self.view.frame.size.height) : CGRectMake(cellRect.origin.x + scoreCell.scoreView.frame.origin.x, cellRect.origin.y + scoreCell.scoreView.frame.origin.y, scoreCell.scoreView.frame.size.width, scoreCell.scoreView.frame.size.height);
VSScoreView *scoreView = [[VSScoreView alloc] initWithFrame:scoreRect];

//Initialize the view that will be animated up (in this case scoreView)...

if (dissolveAnimation)
    scoreView.alpha = 0.0;

[self.view addSubview:scoreView];

[UIView animateWithDuration:0.3 delay:0 options:UIViewAnimationOptionBeginFromCurrentState animations:^{
    if (dissolveAnimation)
        scoreView.alpha = 1.0;
    else
        scoreView.frame = CGRectMake(0.0, 0.0, self.view.frame.size.width, self.view.frame.size.height);
} completion:^(BOOL finished) {
    if (finished)
    {
        //Add scoreDisplayController as a child view controller or present it without animation
        [scoreView removeFromSuperview];            
    }
}];

Of course, the new iOS might make this easier (my lips are sealed), but I hope this is somewhat helpful for your situation!

Upvotes: 1

Related Questions