I'm writing an app with a series of cards in a table view, similar to the layout of the Google app for iOS when Google Now cards are enabled. When the user taps on a card, there should be a custom transition to a new view controller which is basically the card looking bigger, almost filling the screen, and it has more details on it. The custom transition itself should look like the card is animated upward and growing in size until it reaches its final size and position, which is now the new view controller holding the card.
I have been trying to approach this using a custom view controller transition. When the card is tapped, I initiate a custom view controller transition with UIModalPresentationCustom
, and I set a transition delegate, which itself vends a custom animator and a custom UIPresentationController. In animateTransition:
, I add the new view controller's view into the container view, setting the frame to the card's frame initially (so it looks like the card is still there and unchanged). Then I attempt to perform an animation where the presented view's frame grows in size and changes in position so that it moves into its final position.
Here's some of my code which does what I've described above - I'm trying to keep it short and sweet, but I can provide more info if needed:
Transition Delegate
-(void)animateTransition:(id<UIViewControllerContextTransitioning>)transitionContext {
// NOWAnimationDelegate is my own custom protocol which defines the method for asking the presenting VC for the tapped card's frame.
UIViewController<NOWAnimationDelegate> *fromVC = (UIViewController<NOWAnimationDelegate> *)[transitionContext viewControllerForKey:UITransitionContextFromViewControllerKey];
UIViewController *finalVC = [transitionContext viewControllerForKey:UITransitionContextToViewControllerKey];
UIView *toView = [transitionContext viewForKey:UITransitionContextToViewKey];
// Ask the presenting view controller for the frame of the tapped card - this method works.
toView.frame = [fromVC rectForSelectedCard];
[transitionContext.containerView addSubview:toView];
CGRect finalRect = [transitionContext finalFrameForViewController:finalVC];
[UIView animateWithDuration:[self transitionDuration:transitionContext] animations:^{
toView.frame = finalRect;
}completion:^(BOOL finished) {
[transitionContext completeTransition:YES];
}];
}
Custom UIPresentationController
-(CGSize)sizeForChildContentContainer:(id<UIContentContainer>)container withParentContainerSize:(CGSize)parentSize {
return CGSizeMake(0.875*parentSize.width, 0.875*parentSize.height);
}
-(CGRect)frameOfPresentedViewInContainerView {
CGRect presentedViewFrame = CGRectZero;
CGRect containerBounds = self.containerView.bounds;
presentedViewFrame.size = [self sizeForChildContentContainer:(UIView<UIContentContainer> *)self.presentedView withParentContainerSize:containerBounds.size];
presentedViewFrame.origin.x = (containerBounds.size.width - presentedViewFrame.size.width)/2;
presentedViewFrame.origin.y = (containerBounds.size.height - presentedViewFrame.size.height)/2 + 10;
return presentedViewFrame;
}
What I'm finding is happening is that the new view is being automatically set to its final size immediately at the start of the animation, and then the animation is just the new view animating upwards. Using breakpoints, I'm noticing that frameOfPresentedViewInContainerView
is called during the [transitionContext.containerView addSubview:toView]
call, which would probably explain why this is happening - frameOfPresentedViewInContainerView
returns "The frame rectangle to assign to the presented view at the end of the animations" according to the UIPresentationController documentation.
However, I'm not sure how to proceed, or if it's even really possible. All the examples of custom view controller transitions I've seen have all had the final size of the presented view controller static and unchanging during the animation. Is there any way to perform a custom view controller transition with a changing size of the presented view during the animation, or do I have to approach this in a different way?