i have iPad application with splitViewController and tableViewController in splitViewDetailController.
i would like to show detailViewController (with UIModalPresentationFormSheet), after click on tableCell, with custom animation. The animation shoud be vertical rotation of tableViewCell and rotating cell should transform into detailViewController view. The whole animation should look like animation in iTunes podcast.
Here's the code of my animation:
CGRect rectInCell = [[self.cellView superview] convertRect:self.cellView.frame toView:cell];
CGRect rectInTableView = [self.tableView rectForRowAtIndexPath:[self.tableView indexPathForCell:cell]];
CGRect rectInSuperview = [self.tableView convertRect:rectInTableView toView:[[[APP_DELEGATE window] subviews] lastObject]];
CGRect imgRect = CGRectMake(rectInSuperview.origin.x+rectInCell.origin.x, rectInSuperview.origin.y+rectInCell.origin.y, rectInCell.size.width, rectInCell.size.height);
self.originalRelativeFrame = imgRect;
self.originalFrame = self.cellView.frame;
self.originalSuperview = self.cellView.superview;
self.originalTransform = self.cellView.transform;
[self.cellView setFrame:imgRect];
if (self.whiteView == nil) {
self.whiteView = [[UIView alloc] init];
[self.whiteView setBackgroundColor:[UIColor whiteColor]];
}
[self.whiteView setFrame:imgRect];
[self.whiteView setAlpha:0];
self.cellView.layer.zPosition = self.cellView.frame.size.width;
self.whiteView.layer.zPosition = self.cellView.frame.size.width;
[[[[APP_DELEGATE window] subviews] lastObject] addSubview:self.whiteView];
[[[[APP_DELEGATE window] subviews] lastObject] addSubview:self.cellView];
CATransform3D rotation = CATransform3DMakeRotation(M_PI/2, 0, 1, 0);
CATransform3D scale = CATransform3DMakeScale(1.5,1.5,1);//(540.0/self.cellView.bounds.size.width, 620.0/self.cellView.bounds.size.height, 1);
CGPoint finCent = CGPointMake([[[[APP_DELEGATE window] subviews] lastObject] bounds].size.width/2.0, [[[[APP_DELEGATE window] subviews] lastObject] bounds].size.height/2.0);
//(finCent.x > self.cellView.center.x) ? (finCent.x - self.cellView.center.x) : (self.cellView.center.x - finCent.x);
CGPoint center = CGPointMake((self.cellView.center.x - finCent.x) / 2.0 ,(self.cellView.center.y - finCent.y )/2.0);
[UIView animateWithDuration:ANIMATION_DURATION_HALF delay:0 options:UIViewAnimationOptionCurveEaseOut
animations:^{
[self.cellView.layer setTransform:CATransform3DConcat(scale, rotation)];
[self.cellView setCenter:CGPointMake(self.cellView.center.x - center.x, self.cellView.center.y - center.y)];
//[self.cellView setAlpha:0];
[self.whiteView.layer setTransform:CATransform3DConcat(scale, rotation)];
[self.whiteView setCenter:CGPointMake(self.whiteView.center.x - center.x, self.whiteView.center.y - center.y)];
//[self.whiteView setAlpha:1];
[self.blackView setAlpha:0.3];
}
completion:^(BOOL finished) {
[self.whiteView setAlpha:1];
[self.cellView setAlpha:0];
[UIView animateWithDuration:ANIMATION_DURATION_HALF delay:0 options:UIViewAnimationOptionCurveLinear
animations:^{
CATransform3D rotation = CATransform3DMakeRotation(M_PI, 0, 1, 0);
CATransform3D scale = CATransform3DMakeScale(540.0/self.cellView.bounds.size.width, 620.0/self.cellView.bounds.size.height, 1);
CGPoint finCent = CGPointMake([[[[APP_DELEGATE window] subviews] lastObject] bounds].size.width/2.0, [[[[APP_DELEGATE window] subviews] lastObject] bounds].size.height/2.0);
[self.cellView.layer setTransform:CATransform3DConcat(scale, rotation)];
[self.cellView setCenter:finCent];
[self.whiteView.layer setTransform:CATransform3DConcat(scale, rotation)];
[self.whiteView setCenter:finCent];
}
completion:^(BOOL finished) {
[self presentModalViewController:self.modalCtrl animated:YES];
}];
}];
But the problem is rotation of application. After rotating application whiteView behind my detailViewController dosn't stay centered in the middle of window.
Any idea how can i fix this issue?
You should rearrange the layout of your views when the user rotates the device.
The UIViewController class offers a couple of methods to deal with this:
– willRotateToInterfaceOrientation:duration:
– willAnimateRotationToInterfaceOrientation:duration:
– didRotateFromInterfaceOrientation:
Have a look at UIViewController reference.
- (void)willRotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation
duration:(NSTimeInterval)duration {
CGRect imgRect = <CALC YOUR NEW FRAME HERE TO ACCOUNT FOR THE DEVICE ORIENTATION>;
[self.whiteView setFrame:imgRect];
}
When calculating the new frame, you can use the toInterfaceOrientation argument to know for which orientation. Another option you have that might make things simpler is defining the view center.
Related
I am new to animation, and trying to write a custom segue to achieve slide out a side menu from left to right, overlay the home view, and occupy half of the screen.
There is a custom segue code:
#import "CustomSegue.h"
#implementation CustomSegue
- (void)perform {
UIViewController *contentVC = self.sourceViewController;
UIViewController *sideBarVC = self.destinationViewController;
CGRect sideFrame = sideBarVC.view.frame;
[sideBarVC.view setFrame: CGRectMake(0, 0, 0, contentVC.view.frame.size.height)];
CGRect animationFrame = contentVC.view.frame;
sideFrame = sideBarVC.view.frame;
animationFrame.size.width = contentVC.view.frame.size.width / 2;
[UIView animateWithDuration:0.3
delay:0.0
options:UIViewAnimationOptionCurveEaseOut
animations:
^{
sideBarVC.view.frame = animationFrame;
}
completion:
^(BOOL finished) {
sideBarVC.view.frame = animationFrame;
contentVC.view.alpha = 0.5f;
[[contentVC.view superview] addSubview:sideBarVC.view];
}];
}
#end
I add some variable to see if the frame is correct, and it is correct when I change the frame.
But I don't see my "expected" animation: sideBarVC.view.frame = animationFrame;
Could some one help on this? Thanks.
If you want to have a slide from left to right animation, you will firstly have to set the original X of animating view's frame to be a negative value, then in the animation block, set original x to be 0. Something like that.
sideFrame = sideBarVC.view.frame;
sideBarVC.view.frame = CGRectOffset(sideFrame, - contentVC.view.frame.size.width, 0);
[[contentVC.view superview] addSubview:sideBarVC.view];
[UIView animateWithDuration:0.3 animations:^{
sideBarVC.view.frame = sideFrame;
contentVC.view.alpha = 0.5f;
} completion:nil];
Using your code I don't see animation happens, because sideBarVC.view is added in the completion block of the animation. By then the animation has already finished, and sideBarVC.view is added as subview and its frame is set.
Tunred out I misunderstand the position. Using below code could achieve the animation,
but it still has one problem, the side bar menu is under navigation tool bar on top of the screen. Do anyone know how to solve it?
- (void)perform {
UIViewController *contentVC = self.sourceViewController;
UIViewController *sideBarVC = self.destinationViewController;
CGRect sideFrame = sideBarVC.view.frame;
[sideBarVC.view setFrame: CGRectMake(-(contentVC.view.frame.size.width), 0, contentVC.view.frame.size.width/2, contentVC.view.frame.size.height)];
CGRect animationFrame = contentVC.view.frame;
sideFrame = sideBarVC.view.frame;
animationFrame.size.width = contentVC.view.frame.size.width / 2;
sideBarVC.view.alpha = 0;
[[[contentVC.view superview] window] addSubview:sideBarVC.view]; < -- this is important, not [superview addSubView]
[UIView animateWithDuration:1
delay:0.0
options:UIViewAnimationOptionCurveEaseOut
animations:^{
sideBarVC.view.frame = animationFrame;
sideBarVC.view.alpha = 1;
}
completion:^(BOOL finished) {
sideBarVC.view.alpha = 1;
sideBarVC.view.frame = animationFrame;
}];
For Swift 3
override func perform() {
let contentVC = self.sourceViewController;
let sideBarVC = self.destinationViewController;
var sideFrame = sideBarVC.view.frame
sideBarVC.view.frame = CGRect(x: -(contentVC.view.frame.size.width), y: 0, width: contentVC.view.frame.size.width/2, height: contentVC.view.frame.size.height)
sideFrame = sideFrame.offsetBy(dx: -1 * contentVC.view.frame.size.width, dy: 0)
contentVC.view.superview?.addSubview(sideBarVC.view)
UIView.animate(withDuration: 0.3) {
sideBarVC.view.frame = sideFrame
contentVC.view.alpha = 0.5
}
}
_cardView =[card initCard];
[self.view addSubview:_cardView];
_cardView.transform=CGAffineTransformScale(CGAffineTransformIdentity, 0.1, 0.1);
[UIView animateWithDuration:0.3
animations:^{
_cardView.transform=CGAffineTransformIdentity;
}];
I have a view which I animate to make it seem as if it is expanding from a point (similar to the animation of an app being opened). This view is returned from [card initCard], with card being a custom class, and assigned to _cardView. Using CGAffineTransformScale I first decrease the scale and then animate the increase of the scale. This works perfectly for the first card that is shown. However, when _cardView is set to nil and a new card is assigned to it, the same transformation and animation code produce the wrong animation which makes the view increase in scale before decreasing. I assume that the problem is in making the scale 0.1,0.1 but I have not been able to solve this.
Setting to nil:
else if (sender.state == UIGestureRecognizerStateEnded || sender.state == UIGestureRecognizerStateCancelled || sender.state == UIGestureRecognizerStateFailed)
{
if(sender.view.center.x>0){
[UIView animateWithDuration:0.2 animations:^{
CGRect rect=[sender.view frame];
rect.origin.x=([self.view frame].size.width/2)-129.5;
[sender.view setFrame:rect];
sender.view.alpha = 0.8;
}];
}else{
[UIView animateWithDuration:0.5 animations:^{
_protoypeView.alpha=0.0;
_protoypeView=nil;
_cardView=nil;
[self nextCard];
}];
}
}
and function nextCard:
-(void)nextCard{
if(cardNumber>[questionArray count]-1){
NSLog(#"Out of cards");
}else{
QuestionCard *card=[[QuestionCard alloc]init];
NSArray* array =[[NSArray alloc]initWithArray:questionArray[cardNumber]];
card.questionString=array[3];
card.whenPosted=array[0];
card.isAnon=array[2];
card.user=array[1];
card.replies=array[4];
card.profileImg=array[5];
_cardView =[card initCard];
[self.view addSubview:_cardView];
_cardView.alpha=0.0;
_cardView.transform=CGAffineTransformScale(CGAffineTransformIdentity, -1, -1);
_cardView.transform=CGAffineTransformIdentity;
[UIView animateWithDuration:1 animations:^{
_cardView.alpha=0.7;
}];
UIPanGestureRecognizer * pan1 = [[UIPanGestureRecognizer alloc]initWithTarget:self action:#selector(handlePanImage:)];
pan1.minimumNumberOfTouches = 1;
[_cardView addGestureRecognizer:pan1];
yOfView=[_cardView frame].origin.y+([_cardView frame].size.height/2);
cardNumber++;
}
}
First case of CGAffineTransform (after successful query to Parse database):
[UIView animateWithDuration:0.5 animations:^{
_protoypeView.alpha=0.0;
}completion:^(BOOL finished){
QuestionCard *card=[[QuestionCard alloc]init];
NSArray* array =[[NSArray alloc]initWithArray:questionArray[cardNumber]];
card.questionString=array[3];
card.whenPosted=array[0];
card.isAnon=array[2];
card.user=array[1];
card.replies=array[4];
card.profileImg=array[5];
_cardView =[card initCard];
[self.view addSubview:_cardView];
_cardView.transform=CGAffineTransformScale(CGAffineTransformIdentity, 0.0, 0.0);
[UIView animateWithDuration:0.3
animations:^{
_cardView.transform=CGAffineTransformIdentity;
}];
UIPanGestureRecognizer * pan1 = [[UIPanGestureRecognizer alloc]initWithTarget:self action:#selector(handlePanImage:)];
pan1.minimumNumberOfTouches = 1;
[_cardView addGestureRecognizer:pan1];
yOfView=[_cardView frame].origin.y+([_cardView frame].size.height/2);
cardNumber++;
}];
Found the problem - [self nextCard] was called in animations, but should be called in completion.
I wants to do animation something similar to app launch on the ios home screen. Like the whole collection view goes to scale up and the launched app covered the whole screen.
I am using the iOS 7 new api for viewcontroller transitions.
And I am using the parent collection viewcontroller snapshot to appropriate animation.
But still I am not getting enough like what animation is actually is happening at that time?
To get the performance and look you want, you may have to perform transforms on the view layers.
I put up a little demo on GitHub, but the relevant code is below.
- (void)collectionView:(UICollectionView *)collectionView didSelectItemAtIndexPath:(NSIndexPath *)indexPath
{
MyCellView *cell = (MyCellView *)[self collectionView:collectionView cellForItemAtIndexPath:indexPath];
self.detailViewController = [[DetailViewController alloc] initWithNibName:nil bundle:nil];
self.detailViewController.labelString = [NSString stringWithFormat:#"%i", indexPath.row];
[self.view.superview addSubview:self.detailViewController.view];
// tap position relative to collection view
float screenX = self.collectionView.frame.origin.x + cell.center.x;
float screenY = self.collectionView.frame.origin.y + cell.center.y - self.collectionView.contentOffset.y;
// tap position relative to view frame
float translateX = (self.view.frame.size.width / -2.0) + screenX;
float translateY = (self.view.frame.size.height / -2.0) + screenY;
CATransform3D transform_detail = CATransform3DScale(CATransform3DMakeTranslation(translateX, translateY, 0.0), 0.0, 0.0, 0.0);
CATransform3D transform_main = CATransform3DScale(CATransform3DMakeTranslation(-translateX * 5.0, -translateY * 5.0, 0.0), 5.0, 5.0, 5.0);
self.detailViewController.view.layer.transform = transform_detail;
[UIView animateWithDuration:0.5 animations:^{
self.detailViewController.view.layer.transform = CATransform3DIdentity;
self.view.layer.transform = transform_main;
} completion:^(BOOL finished) {
self.view.layer.transform = CATransform3DIdentity;
}];
}
You need to use custom segues.
This tutorial should help you and below is the code excerpt.
- (void)perform {
UIViewController *sourceViewController = self.sourceViewController;
UIViewController *destinationViewController = self.destinationViewController;
// Add the destination view as a subview, temporarily
[sourceViewController.view addSubview:destinationViewController.view];
// Transformation start scale
destinationViewController.view.transform = CGAffineTransformMakeScale(0.05, 0.05);
// Store original centre point of the destination view
CGPoint originalCenter = destinationViewController.view.center;
// Set center to start point of the button
destinationViewController.view.center = self.originatingPoint;
[UIView animateWithDuration:0.5
delay:0.0
options:UIViewAnimationOptionCurveEaseInOut
animations:^{
// Grow!
destinationViewController.view.transform = CGAffineTransformMakeScale(1.0, 1.0);
destinationViewController.view.center = originalCenter;
}
completion:^(BOOL finished){
[destinationViewController.view removeFromSuperview]; // remove from temp super view
[sourceViewController presentViewController:destinationViewController animated:NO completion:NULL]; // present VC
}];
}
I am animating UIView to have a feeling of book's page effect
#property (strong, nonatomic) UIView *insideView;
#property (strong, nonatomic) UIView *pageView;
#property (strong, nonatomic) UIView *backPageView;
#property (assign, nonatomic) CGRect cardFrame;
- (void)viewDidLoad
{
[super viewDidLoad];
[[self view] setBackgroundColor:[UIColor grayColor]];
//create frame for 2 test views
CGFloat size = 200.0;
_cardFrame = CGRectMake([[self view] center].x - size / 2, [[self view] center].y - size / 2 , size, size);
//lower view
_insideView = [[UIView alloc] initWithFrame: _cardFrame];
[_insideView setBackgroundColor:[UIColor redColor]];
//upper view
_pageView = [[UIView alloc] initWithFrame:_cardFrame];
[_pageView setBackgroundColor:[UIColor greenColor]];
//upper view back side
_backPageView = [[UIView alloc] initWithFrame:_cardFrame];
[_backPageView setBackgroundColor:[UIColor blueColor]];
[[self view] addSubview:_insideView];
[[self view] addSubview:_pageView];
[[self view] insertSubview:_backPageView belowSubview:_pageView];
//get layer of upper view and set needed property
CALayer *viewLayer = [_pageView layer];
CALayer *viewBackLayer = [_backPageView layer];
[viewLayer setAnchorPoint:(CGPoint){0.0 , 0.5}];
[viewLayer setFrame:_cardFrame];
[viewLayer setDoubleSided:NO];
[viewBackLayer setAnchorPoint:(CGPoint){0.0 , 0.5}];
[viewBackLayer setFrame:_cardFrame];
//create perspective
CATransform3D mt = CATransform3DIdentity;
mt.m34 = 1.0/-500.;
//create rotation
CATransform3D open = CATransform3DMakeRotation(3 * M_PI_4,0,-1, 0);
//create result transform
CATransform3D openTransform = CATransform3DConcat(open, mt);
[UIView animateWithDuration:1.0 animations:^
{
//close animation
[viewLayer setTransform:openTransform];
[viewBackLayer setTransform:openTransform];
} completion:^(BOOL finished)
{
[UIView animateWithDuration:1.0 animations:^
{
//close animation
[viewLayer setTransform:CATransform3DIdentity];
[viewBackLayer setTransform:CATransform3DIdentity];
}];
}];
}
But i want the UIView to animate from bottom to top,this code do animate but from left to right like book's page.
Please help!!
Thanks in advance.
try this.
//create frame for 2 test views
CGFloat size = 200.0;
_cardFrame = CGRectMake([[self view] center].x - size / 2, [[self view] center].y - size / 2 , size, size);
//lower view
_insideView = [[UIView alloc] initWithFrame: _cardFrame];
[_insideView setBackgroundColor:[UIColor redColor]];
//upper view
_pageView = [[UIView alloc] initWithFrame:_cardFrame];
[_pageView setBackgroundColor:[UIColor greenColor]];
//upper view back side
_backPageView = [[UIView alloc] initWithFrame:_cardFrame];
[_backPageView setBackgroundColor:[UIColor blueColor]];
[[self view] addSubview:_insideView];
[[self view] addSubview:_pageView];
[[self view] insertSubview:_backPageView belowSubview:_pageView];
//get layer of upper view and set needed property
CALayer *viewLayer = [_pageView layer];
CALayer *viewBackLayer = [_backPageView layer];
[viewLayer setAnchorPoint:(CGPoint){0.5 , 0.0}];
[viewLayer setFrame:_cardFrame];
[viewLayer setDoubleSided:NO];
[viewBackLayer setAnchorPoint:(CGPoint){0.5 , 0.0}];
[viewBackLayer setFrame:_cardFrame];
//create perspective
CATransform3D mt = CATransform3DIdentity;
mt.m34 = 1.0/-500.;
//create rotation
CATransform3D open = CATransform3DMakeRotation(3 * M_PI_4,1,0,0);
//create result transform
CATransform3D openTransform = CATransform3DConcat(open, mt);
[UIView animateWithDuration:1.0 animations:^
{
//close animation
[viewLayer setTransform:openTransform];
[viewBackLayer setTransform:openTransform];
} completion:^(BOOL finished)
{
[UIView animateWithDuration:1.0 animations:^
{
//close animation
[viewLayer setTransform:CATransform3DIdentity];
[viewBackLayer setTransform:CATransform3DIdentity];
}];
}];
Here is the code
- (void)viewDidLoad
{
[super viewDidLoad];
[[self view] setBackgroundColor:[UIColor grayColor]];
//create frame for 2 test views
CGFloat size = 200.0;
_cardFrame = CGRectMake([[self view] center].x - size / 2, [[self view] center].y - size / 2 , size, size);
//lower view
_insideView = [[UIView alloc] initWithFrame: _cardFrame];
[_insideView setBackgroundColor:[UIColor redColor]];
//upper view
_pageView = [[UIView alloc] initWithFrame:_cardFrame];
[_pageView setBackgroundColor:[UIColor greenColor]];
//upper view back side
_backPageView = [[UIView alloc] initWithFrame:_cardFrame];
[_backPageView setBackgroundColor:[UIColor blueColor]];
[[self view] addSubview:_insideView];
[[self view] addSubview:_pageView];
[[self view] insertSubview:_backPageView belowSubview:_pageView];
//get layer of upper view and set needed property
CALayer *viewLayer = [_pageView layer];
CALayer *viewBackLayer = [_backPageView layer];
// need to change the anchor point to center of top edge.
// that is the point in which you need to rotate.
[viewLayer setAnchorPoint:(CGPoint){0.5 , 0.0}];
[viewLayer setFrame:_cardFrame];
[viewLayer setDoubleSided:NO];
[viewBackLayer setAnchorPoint:(CGPoint){0.5 , 0.0}];
[viewBackLayer setFrame:_cardFrame];
//create perspective
CATransform3D mt = CATransform3DIdentity;
mt.m34 = 1.0/-500.;
//need to rotate in X axis. so changed arguments.
CATransform3D open = CATransform3DMakeRotation(3 * M_PI_4,1,0, 0);
//create result transform
CATransform3D openTransform = CATransform3DConcat(open, mt);
[UIView animateWithDuration:1.0 animations:^
{
//close animation
[viewLayer setTransform:openTransform];
[viewBackLayer setTransform:openTransform];
} completion:^(BOOL finished)
{
[UIView animateWithDuration:1.0 animations:^
{
//close animation
[viewLayer setTransform:CATransform3DIdentity];
[viewBackLayer setTransform:CATransform3DIdentity];
}];
}];
}
The two key parts in that page flip is the rotation transform and the anchor point. If you are unfamiliar with this then I suggest that you look at the documentation to see how they work, I will only give a brief explanation.
Rotation transform
You can see that CATransform3DMakeRotation takes 4 arguments, the first is the angle of the rotation and the next three are the axis of the rotation. You are rotating around (0,-1, 0) which is the y axis (vertical on the screen). To instead cause a rotation around the horizontal axis (x) you should change the last 3 arguments to 1, 0, 0 (or maybe -1, I can't seem to remember that on the top of my head).
CATransform3D open = CATransform3DMakeRotation(3.0*M_PI_4, // angle
1, 0, 0); // axis
Anchor point
The anchor point specifies how the layer is drawn relative to its position. Both x and y in the anchor point range from 0 to 1 so (0.5, 0.5) is in the center of the layer, no matter the size. In your case the anchor point is (0.0, 0.5) meaning center left edge. You should probably change that to (0.5, 0.0) center top edge or (0.5, 1.0) center bottom edge depending on where you want the anchor point to be for your page flip.
viewLayer.anchorPoint = CGPointMake(0.5, 0.0); // center top edge
set Uiview Frame in view did Load then set on your event button clicked. view animaate Bottom to top
CGRect optionsFrame = AddNOTEview.frame;
optionsFrame.origin.y=300;
[UIView beginAnimations:nil context:nil];
[UIView setAnimationDuration:0.50];
AddNOTEview.frame = optionsFrame;
[self.view addSubview:AddNOTEview];
My goal is to provide zooming modal transition from for the user from a view similar as springboard icons zoom in when launching apps.
The presented view controller zooms in correctly, but the navigation bar has wrong position under the status bar. This position gets corrected after calling [transitionContext completeTransition:finished];. How can I make it correct from the beginning of the transition?
This is a screen recording of the bug: http://youtu.be/7LKU4lzb-uw (the glitch is in the 6th second of the recording)
The UIViewControllerAnimatedTransitioning code:
- (void)animateTransition:(id<UIViewControllerContextTransitioning>)transitionContext
{
UIViewController *fromViewController = [transitionContext viewControllerForKey:UITransitionContextFromViewControllerKey];
UIViewController *toViewController = [transitionContext viewControllerForKey:UITransitionContextToViewControllerKey];
UIView *container = [transitionContext containerView];
CGPoint viewCenter = self.view.center;
CGSize viewSize = self.view.frame.size;
CGSize controllerSize = toViewController.view.frame.size;
CGFloat controllerFromX = viewCenter.x - (controllerSize.width / 2);
CGFloat controllerFromY = viewCenter.y - (controllerSize.height / 2);
CGAffineTransform transform = CGAffineTransformMakeTranslation(controllerFromX, controllerFromY);
transform = CGAffineTransformScale(transform, viewSize.width / controllerSize.width, viewSize.height / controllerSize.height);
if (self.reverse) {
[container insertSubview:toViewController.view belowSubview:fromViewController.view];
} else {
toViewController.view.transform = transform;
[container addSubview:toViewController.view];
}
[UIView animateKeyframesWithDuration:ZoomTransitioningDuration
delay:0
options:0
animations:^{
if (self.reverse) {
fromViewController.view.alpha = 0.0f;
fromViewController.view.transform = transform;
} else {
toViewController.view.transform = CGAffineTransformIdentity;
}
}
completion:^(BOOL finished) {
[transitionContext completeTransition:finished];
}];
}
The problem is that you are setting the transform before inserting the destination view controller's view into the container.
Switching the order should fix it:
if (self.reverse) {
[container insertSubview:toViewController.view belowSubview:fromViewController.view];
} else {
[container addSubview:toViewController.view];
toViewController.view.transform = transform;
}
See point 4 here. Since you've applied a transform prior to inserting the navigation controller's view as a subview, the layout engine doesn't think the navigation bar is at the top edge of the window, and therefore doesn't need to be adjusted to avoid the status bar.
I've found a solution, although pretty hacky. I have to manually adjust the navigation bar frame before the animation starts:
if (self.reverse) {
[container insertSubview:toViewController.view belowSubview:fromViewController.view];
} else {
toViewController.view.transform = transform;
[container addSubview:toViewController.view];
// fix navigation bar position to prevent jump when completeTransition: is called
if ([toViewController isKindOfClass:[UINavigationController class]]) {
UINavigationController* navigationController = (UINavigationController*) toViewController;
UINavigationBar* bar = navigationController.navigationBar;
CGRect frame = bar.frame;
bar.frame = CGRectMake(frame.origin.x, frame.origin.y + 20.0f, frame.size.width, frame.size.height);
}
}
Add the toViewControllerView first to the ContainerView, then set the toViewControllerView transform as given below.
[container addSubview:toViewController.view];
toViewController.view.transform = transform;
This will solve the problem.
This is still a hack, based on Ondřej Mirtes' one but it works better if you have an in-call status bar and you're on iOS8
if([toViewController isKindOfClass:[UINavigationController class]]) {
UINavigationController *navCtrl = (UINavigationController *)toViewController;
UINavigationBar *navBar = navCtrl.navigationBar;
if(navBar.frame.origin.y == 0 && navBar.frame.size.height == 44) {
navBar.frame = CGRectMake(0, 0, navBar.frame.size.width, fmin(44 + [UIApplication sharedApplication].statusBarFrame.size.height, 64));
}
}
Remains ugly though :/