I am NOT using navigation controller, and I am using storyboards.
I have to make a transition from 1 view controller to other, for which I am using segue.
Now I set the segue style to Custom, and in the corresponding class, I override the perform
method.
-(void)perform
{
UIViewController *sourceViewController = [self sourceViewController];
UIViewController *destinationViewController = [self destinationViewController];
CATransition *transition = [CATransition animation];
transition.duration = 0.25;
transition.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseIn];
transition.type = kCATransitionPush;
transition.subtype = kCATransitionFromLeft;
[sourceViewController.view.layer addAnimation:transition forKey:kCATransition];animated:NO];
[sourceViewController presentViewController:destinationViewController animated:YES completion:nil];
}
But there is also a property of the destination view controller modalTransitionStyle
.
So Right now, the source VC goes from left to right as if it is being pushed, but I want to show that it is being pushed by the destination view controller. Instead, the destination VC does a 'Cover Vertical' by default, and there are only four options available for the modalTransitionStyle
property, none of which is working for me.
I think to make it work, this animation should be added to some superview layer, a superview from which both view controllers have been presented. But there is no such superview..
Usually you would give a storyboardId to the destinationController and call it like this from the sourceViewController:
//push next view
UIStoryboard *storyboard = self.storyboard;
YourViewControllerClass *destVC = [storyboard instantiateViewControllerWithIdentifier:@"StoryboardID"];
[self.navigationController pushViewController:destVC animated:YES];
Optionally, you can do it manually like this:
// Get the views.
UIView * fromView = sourceViewController.view;
UIView * toView = destinationViewController.view;
// Get the size of the view area.
CGRect viewSize = fromView.frame;
// Add the toView to the fromView
[fromView.superview addSubview:toView];
// Position it off screen.
toView.frame = CGRectMake( 320 , viewSize.origin.y, 320, viewSize.size.height);
[UIView animateWithDuration:0.4 animations:
^{
// Animate the views on and off the screen. This will appear to slide.
fromView.frame =CGRectMake( -320 , viewSize.origin.y, 320, viewSize.size.height);
toView.frame =CGRectMake(0, viewSize.origin.y, 320, viewSize.size.height);
}
completion:^(BOOL finished)
{
if (finished)
{
// Remove the old view from its parent.
[fromView removeFromSuperview];
//I use it to have navigationnBar and TabBar at the same time
//self.tabBarController.selectedIndex = indexPath.row+1;
}
}];
** EDIT **
Inverse function (similar to the back button in the navigation controller):
// Get the views.
UIView * fromView = fromViewController.view;
UIView * toView = destViewController.view;
// Get the size of the view area.
CGRect viewSize = fromView.frame;
// Add the to view to the tab bar view.
[fromView.superview addSubview:toView];
// Position it off screen.
toView.frame = CGRectMake( -320 , viewSize.origin.y, 320, viewSize.size.height);
[UIView animateWithDuration:0.4 animations:
^{
// Animate the views on and off the screen. This will appear to slide.
fromView.frame =CGRectMake( 320 , viewSize.origin.y, 320, viewSize.size.height);
toView.frame =CGRectMake(0, viewSize.origin.y, 320, viewSize.size.height);
}
completion:^(BOOL finished)
{
if (finished)
{
// Remove the old view from the tabbar view.
[fromView removeFromSuperview];
}
}];
All of the ViewControllers in my app inherit from MyViewController
which, in addition to some other default behaviours, has this property:
@property(readwrite, nonatomic) BOOL slideFromSide;
And this code:
- (void) presentViewController: (UIViewController*) vc animated: (BOOL) flag completion: (void (^)(void)) completion
{
BOOL slideIn = NO;
if ([vc isKindOfClass: [MyViewController class]])
{
MyViewController *svc = (MyViewController*) vc;
slideIn = svc.slideFromSide;
}
if (slideIn)
{
[self addChildViewController: vc];
[self.view addSubview: vc.view];
CGRect frame = vc.view.frame;
frame.origin.x = frame.size.width;
vc.view.frame = frame;
frame.origin.x = 0;
[UIView animateWithDuration: 0.33
animations: ^{
vc.view.frame = frame;
}
];
}
else
{
[super presentViewController: vc animated: flag completion: completion];
}
}
- (IBAction) backAction: (id) sender
{
if (_slideFromSide)
{
CGRect frame = self.view.frame;
frame.origin.x = frame.size.width;
[UIView animateWithDuration: 0.33
animations: ^{
self.view.frame = frame;
}
completion:^(BOOL finished) {
[self removeFromParentViewController];
}
];
}
else
{
[self dismissViewControllerAnimated: YES completion: nil];
}
}
Then, in the ViewControllers where I want to slide-in, I have:
- (id) initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
self = [super initWithNibName: nibNameOrNil bundle: nibBundleOrNil];
if (self)
{
self.slideFromSide = YES;
// Whatever else you want to do
}
return self;
}
Calling a new ViewController is just like normal:
WhateverViewController *vc = [WhateverViewController alloc] initWithNibName: nil bundle: nil];
[self presentViewController: vc animated: YES completion: nil];