View transition doesn't animate during custom pop segue - ios

I'm using a custom segue to create an expand animation when I push new view controllers onto my navigation stack. If no sourceRect is specified when prepareForSegue:sender: is called, then the destination view controller is expanded from the center of the source view controller.
ExpandSegue.m:
- (id)initWithIdentifier:(NSString *)identifier source:(UIViewController *)source destination:(UIViewController *)destination {
self = [super initWithIdentifier:identifier source:source destination:destination];
self.sourceRect = CGRectMake(source.view.center.x, source.view.center.y, 0.0, 0.0);
return self;
}
- (void)perform {
UIViewController *sourceViewController = (UIViewController *)self.sourceViewController;
UIViewController *destinationViewController = (UIViewController *)self.destinationViewController;
CGRect destinationRect = sourceViewController.view.frame;
CGFloat tx = self.sourceRect.origin.x + self.sourceRect.size.width/2 - destinationRect.origin.x - destinationRect.size.width/2;
CGFloat ty = self.sourceRect.origin.y + self.sourceRect.size.height/2 - destinationRect.origin.y - destinationRect.size.height/2;
CGFloat sx = self.sourceRect.size.width/destinationRect.size.width;
CGFloat sy = self.sourceRect.size.height/destinationRect.size.height;
[sourceViewController.view addSubview:destinationViewController.view];
[destinationViewController.view setFrame:sourceViewController.view.frame];
[destinationViewController.view setTransform:CGAffineTransformConcat(CGAffineTransformMakeScale(sx, sy), CGAffineTransformMakeTranslation(tx, ty))];
[UIView animateWithDuration:0.5
delay:0.0
options:UIViewAnimationCurveEaseOut
animations:^{
[destinationViewController.view setTransform:CGAffineTransformIdentity];
} completion:^(BOOL finished) {
[destinationViewController.view removeFromSuperview];
[sourceViewController.navigationController pushViewController:destinationViewController animated:NO];
}];
}
The expand segue works as expected. I tried to create a collapse segue by reversing the logic from the expand segue, but this has given me problems. I want the source view controller to shrink down to the size of the destinationRect. If no destinationRect is supplied, then I want the view to shrink to the center of the destination view controller's view.
CollapseSegue.m:
- (id)initWithIdentifier:(NSString *)identifier source:(UIViewController *)source destination:(UIViewController *)destination {
self = [super initWithIdentifier:identifier source:source destination:destination];
self.destinationRect = CGRectMake(source.view.center.x, source.view.center.y, 0.0, 0.0);
return self;
}
- (void)perform {
UIViewController *sourceViewController = (UIViewController *)self.sourceViewController;
UIViewController *destinationViewController = (UIViewController *)self.destinationViewController;
CGRect sourceRect = sourceViewController.view.frame;
CGFloat tx = self.destinationRect.origin.x + self.destinationRect.size.width/2 - sourceRect.origin.x - sourceRect.size.width/2;
CGFloat ty = self.destinationRect.origin.y + self.destinationRect.size.height/2 - sourceRect.origin.y - sourceRect.size.height/2;
CGFloat sx = self.destinationRect.size.width/sourceRect.size.width;
CGFloat sy = self.destinationRect.size.height/sourceRect.size.height;
[sourceViewController.navigationController popViewControllerAnimated:NO];
[destinationViewController.view addSubview:sourceViewController.view];
[sourceViewController.view setFrame:destinationViewController.view.frame];
[UIView animateWithDuration:0.5
delay:0.0
options:UIViewAnimationCurveEaseOut
animations:^{
[sourceViewController.view setTransform:CGAffineTransformConcat(CGAffineTransformMakeScale(sx, sy), CGAffineTransformMakeTranslation(tx, ty))];
} completion:^(BOOL finished) {
[sourceViewController.view removeFromSuperview];
}];
}
Rather than animating nicely, the view for the sourceViewController simply disappears as if I had only called [sourceViewController.navigationController popViewControllerAnimated:NO]; This would seem to indicate that I'm not setting up my view hierarchy properly, but I can't seem to figure out where I'm going wrong! Any help would be greatly appreciated.

Related

Different presentation between push and model

I have a Custom Transition, I apply it in a ViewController which complies with UIViewControllerTransitioningDelegate protocol. My transition works ok. But when i change UIViewControllerTransitioningDelegate protocol to UINavigationControllerDelegate protocol, it works strangely.
The function i want to realize
Strange presentation with only one piece of toView
MyTransitioning:
#import "MyTransitioning.h"
#define PARTS_COUNT 4
#interface MyTransitioning()
#property (nonatomic) CGFloat partWidth;
#property (nonatomic) CGFloat partHeight;
#end
#implementation MyTransitioning
-(NSTimeInterval)transitionDuration:(id<UIViewControllerContextTransitioning>)transitionContext
{
return 1.0;
}
-(void)animateTransition:(id<UIViewControllerContextTransitioning>)transitionContext
{
UIViewController* fromCtrl = [transitionContext viewControllerForKey:UITransitionContextFromViewControllerKey];
UIViewController* toCtrl = [transitionContext viewControllerForKey:UITransitionContextToViewControllerKey];
UIView* fromView = fromCtrl.view;
UIView* toView = toCtrl.view;
UIView* container = [transitionContext containerView];
CATransform3D transform = container.layer.transform;
transform.m34 = -0.01;
[container.layer setSublayerTransform:transform];
NSArray<UIView*>* fromViewParts = [self spliteView:fromView];
NSArray<UIView*>* toViewParts = [self spliteView:toView];
[self addViews:toViewParts ToContainer:container isFromView:NO];
[self addViews:fromViewParts ToContainer:container isFromView:YES];
[fromView removeFromSuperview];
[UIView animateWithDuration:[self transitionDuration:transitionContext] animations:^
{
[self strechViews:toViewParts];
[self compressViews:fromViewParts ToLeft:YES];
} completion:^(BOOL finished)
{
if (!finished)
{
NSLog(#"not finish");
}
[self removeViewsfromSuper:fromViewParts];
[self removeViewsfromSuper:toViewParts];
[container addSubview:toView];
[transitionContext completeTransition:!transitionContext.transitionWasCancelled];
}];
}
-(NSArray*)spliteView:(UIView*)view
{
self.partWidth = view.bounds.size.width / PARTS_COUNT;
self.partHeight = view.bounds.size.height;
CGRect region = CGRectMake(0, 0, self.partWidth, self.partHeight);
NSMutableArray<UIView*>* viewParts = [NSMutableArray array];
for (int i = 0; i < PARTS_COUNT; i++)
{
region.origin.x =self.partWidth * i;
UIView* partView = [view resizableSnapshotViewFromRect:region afterScreenUpdates:YES withCapInsets:UIEdgeInsetsZero];
[viewParts addObject:partView];
partView.frame = region;
}
return viewParts;
}
-(void)addViews:(NSArray<UIView*>*)views ToContainer:(UIView*)container isFromView:(BOOL)isFromView
{
isFromView ? [self strechViews:views] : [self compressViews:views ToLeft:NO];
for (UIView* view in views)
{
[container addSubview:view];
}
}
-(void)compressViews:(NSArray<UIView*>*)views ToLeft:(BOOL)toLeft
{
CGFloat x = toLeft ? 0 : self.partWidth * 4;
int isClockWise = -1;
CGPoint position = CGPointMake(x, self.partHeight / 2);
for (UIView* view in views) {
isClockWise *= -1;
view.layer.anchorPoint = CGPointMake(0.5 - isClockWise * 0.5, 0.5);
view.layer.position = position;
view.layer.transform = CATransform3DMakeRotation(M_PI_2 * isClockWise, 0, 1, 0);
}
}
-(void)strechViews:(NSArray<UIView*>*)views
{
int isClockWise = -1;
for (UIView* view in views)
{
isClockWise *= -1;
view.layer.anchorPoint = CGPointMake(0.5 - isClockWise * 0.5, 0.5);
NSLog(#"%#",NSStringFromCGPoint(view.layer.anchorPoint));
CGPoint position = view.layer.position;
position.x = self.partWidth * [views indexOfObject:view] + (isClockWise == 1 ? 0 : self.partWidth);
view.layer.position = position;
view.layer.transform = CATransform3DIdentity;
NSLog(#"%#",NSStringFromCGRect(view.frame));
}
}
-(void)removeViewsfromSuper:(NSArray<UIView*>*)views
{
for (UIView* view in views)
{
[view removeFromSuperview];
}
}
#end
ViewController:
#import "ViewController.h"
#import "MyTransitioning.h"
#import "SecondController.h"
#interface ViewController ()<UINavigationControllerDelegate>
//#interface ViewController ()<UIViewControllerTransitioningDelegate>
#end
#implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
//-(id<UIViewControllerAnimatedTransitioning>)animationControllerForPresentedController:(UIViewController *)presented presentingController:(UIViewController *)presenting sourceController:(UIViewController *)source
//{
// return [MyTransitioning new];
//}
-(void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
self.navigationController.delegate = self;
// SecondController* ctrl = [segue destinationViewController];
// ctrl.transitioningDelegate = self;
}
-(id<UIViewControllerAnimatedTransitioning>)navigationController:(UINavigationController *)navigationController animationControllerForOperation:(UINavigationControllerOperation)operation fromViewController:(UIViewController *)fromVC toViewController:(UIViewController *)toVC
{
if (operation == UINavigationControllerOperationPush) {
return [MyTransitioning new];
}
return nil;
}
#end
If your question is difference between PresentViewController and Push,pop view controller then,
PushViewController
Push View controller is a property of the Navigation controller. When you want to move forward from one controller to other you use this.
PopViewController
Pop view controller is also a property of the navigation controller. When you want to go backward in navigation stack you this.
PresentViewController / Model View controller
Present view controller is not a property of the navigation controller. To perform either push/pop your controller should be subclassed with UINavigationController either directly or indirectly. Whereas to present view controller you don't need to have reference of navigation controller, directly you call [self presentViewController..]

iOS - Creating a custom push segue animation

I am trying to create a push segue animation where the sourceVC drops down off screen vertically and the destinationVC appears upwards onto the screen vertically. My custom segue seems to almost make this animation, however, upon the destinationVC appearing the animation does not work. Here is my -perform segue.
-(void)perform
{
UIViewController *sourceVC = self.sourceViewController;
UIViewController *destVC = self.destinationViewController;
[sourceVC.view addSubview:destVC.view];
float width = sourceVC.view.frame.size.width;
float height = sourceVC.view.frame.size.height;
destVC.view.frame = CGRectMake(0, 560, width, height);
[UIView animateWithDuration:.2 delay:0 options:UIViewAnimationOptionCurveLinear
animations:^{
[destVC.view removeFromSuperview];
sourceVC.view.frame = CGRectMake(0, 560, width, height);
} completion:^(BOOL finished) {
[UIView animateWithDuration:.2 delay:0 options:UIViewAnimationOptionCurveLinear animations:^{
destVC.view.frame = CGRectMake(0, 0, destVC.view.frame.size.width, destVC.view.frame.size.height);
} completion:^(BOOL finished) {
[sourceVC.navigationController pushViewController:destVC animated:NO];
}];
}];
}
The second animation is the one that is not working.
Any ideas what is wrong with my code? Thanks for any help.
I needed to create a custom Animator class that conformed to UIViewControllerAnimatedTransitioning.
#import <Foundation/Foundation.h>
#import <UIKit/UIKit.h>
#interface SAAnimator : NSObject <UIViewControllerAnimatedTransitioning>
#end
I then implemented the required methods.
#implementation SAAnimator
-(NSTimeInterval)transitionDuration:(id<UIViewControllerContextTransitioning>)transitionContext
{
return 0.2;
}
-(void)animateTransition:(id<UIViewControllerContextTransitioning>)transitionContext
{
UIViewController *fromViewController = [transitionContext viewControllerForKey:UITransitionContextFromViewControllerKey];
UIViewController *toViewController = [transitionContext viewControllerForKey:UITransitionContextToViewControllerKey];
fromViewController.view.userInteractionEnabled = NO;
[[transitionContext containerView]addSubview:fromViewController.view];
[[transitionContext containerView]addSubview:toViewController.view];
toViewController.view.frame = CGRectMake(0, 560, toViewController.view.frame.size.width, toViewController.view.frame.size.height);
[UIView animateWithDuration:0.2 delay:0.0 options:UIViewAnimationOptionCurveLinear animations:^{
fromViewController.view.frame = CGRectMake(0, 560, fromViewController.view.frame.size.width, fromViewController.view.frame.size.height);
} completion:^(BOOL finished) {
[UIView animateWithDuration:0.2 delay:0 options:UIViewAnimationOptionCurveLinear animations:^{
toViewController.view.frame = CGRectMake(0, 0, toViewController.view.frame.size.width, toViewController.view.frame.size.height);
} completion:^(BOOL finished) {
[transitionContext completeTransition:YES];
}];
}];
}
#end
Then very simply, in my view controller performing the push segue, I made the class conform to the UINavigationControllerDelegate and implement this method.
#pragma mark - Animated Transiton
-(id<UIViewControllerAnimatedTransitioning>)navigationController:(UINavigationController *)navigationController animationControllerForOperation:(UINavigationControllerOperation)operation fromViewController:(UIViewController *)fromVC toViewController:(UIViewController *)toVC
{
if (operation == UINavigationControllerOperationPush) {
SAAnimator * animator = [SAAnimator new];
return animator;
}
return nil;
}
In prepareForSegue set the navigation controller's delegate
-(void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
if ([segue.identifier isEqualToString:#"toCreateVC"]) {
self.navigationController.delegate = self;
}
}

Custom push view controller with slide down animation

I would like to custom push and pop a view controller use pull down/up animation like this:
I try to change the y position but it doesn't work (it doesn't show up animation at all).
[self.navigationController pushViewController:nextController animated:NO];
self.view.frame = CGRectMake(self.view.frame.origin.x, self.view.frame.origin.y, self.view.frame.size.width, self.view.frame.size.height);
[UIView animateWithDuration:0.6 animations:^{
self.view.frame = CGRectMake(0, -self.view.frame.size.height, self.view.frame.size.width, self.view.frame.size.height);
} completion:nil];
Is there any suggestion?
P/s: I have to use push view controller in this case instead of presentViewController
Update:
I try to use UINavigationControllerDelegate like this:
PropertyViewController.h
#interface PropertyViewController : UIViewController <UINavigationControllerDelegate>{
}
PropertyViewController.m
- (void)navigationController:(UINavigationController *)navigationController willShowViewController:(UIViewController *)viewController animated:(BOOL)animated{
NSLog(#"willShowViewController");
}
- (void)navigationController:(UINavigationController *)navigationController didShowViewController:(UIViewController *)viewController animated:(BOOL)animated{
NSLog(#"didShowViewController");
}
-(id<UIViewControllerAnimatedTransitioning>)navigationController:(UINavigationController *)navigationController animationControllerForOperation:(UINavigationControllerOperation)operation fromViewController:(UIViewController *)fromVC toViewController:(UIViewController *)toVC {
// THIS METHOD IS NOT CALLED AT ALL
NSLog(#"animationControllerForOperation");
TLTransitionAnimator *animator = [TLTransitionAnimator new];
animator.presenting = (operation == UINavigationControllerOperationPush);
animator.duration = 0.5;
return animator;
}
- (void)viewGallery{
// PUSH VIEW CONTROLLER
GalleryViewController* galleryController = [[GalleryViewController alloc] initWithNibName:#"GalleryViewController" bundle:nil];
galleryController.navigationController.delegate = self;
[self.navigationController pushViewController:galleryController animated:YES];
}
Update 2:
After fix the problem method not called with this line in PropertyViewController.m
self.navigationController.delegate = self;
I face with another problem.
The slide down animation on push does work, but the slide up doesn't .Here is my custom animation:
- (void)animateTransition:(id <UIViewControllerContextTransitioning>)transitionContext {
UIViewController* toViewController = [transitionContext viewControllerForKey:UITransitionContextToViewControllerKey];
UIViewController* fromViewController = [transitionContext viewControllerForKey:UITransitionContextFromViewControllerKey];
[[transitionContext containerView] addSubview:toViewController.view];
if (self.presenting) { // push
fromViewController.view.transform = CGAffineTransformIdentity;
toViewController.view.transform = CGAffineTransformMakeTranslation(0, toViewController.view.frame.size.height);
}else{ // pop
fromViewController.view.transform = CGAffineTransformMakeTranslation(0, fromViewController.view.frame.size.height);
}
[UIView animateWithDuration:[self transitionDuration:transitionContext] animations:^{
if (self.presenting) { // push
fromViewController.view.transform = CGAffineTransformMakeTranslation(0, toViewController.view.frame.size.height);
toViewController.view.transform = CGAffineTransformMakeTranslation(0, toViewController.view.frame.size.height);
} else { // pop
fromViewController.view.transform = CGAffineTransformMakeTranslation(0, 0);
}
} completion:^(BOOL finished) {
toViewController.view.transform = CGAffineTransformIdentity;
[transitionContext completeTransition:![transitionContext transitionWasCancelled]];
}];
}
The problem 2:
The pull down animation only works on the first time, from the second times, layout renders wrong, I have no idea why this can happen.
Where am I wrong here?
You should Implement UIViewControllerAnimatedTransitioning.
Make your FromViewController.m conform to UINavigationControllerDelegate. Other sample code out there tells you to conform to UIViewControllerTransitioningDelegate, but that's only if you're presenting the ToViewController.
#interface ViewController : UIViewController <UINavigationControllerDelegate>
Return your custom transition animator object in the delegate callback method in FromViewController:
- (id <UIViewControllerAnimatedTransitioning>)navigationController:(UINavigationController *)navigationController
animationControllerForOperation:(UINavigationControllerOperation)operation
fromViewController:(UIViewController *)fromVC
toViewController:(UIViewController *)toVC {
TransitionAnimator *animator = [TransitionAnimator new];
animator.presenting = (operation == UINavigationControllerOperationPush);
return animator;
}
Create your custom TransitionAnimator animator class and paste these sample methods:
- (NSTimeInterval)transitionDuration:(id <UIViewControllerContextTransitioning>)transitionContext {
return 0.5f;
}
- (void)animateTransition:(id<UIViewControllerContextTransitioning>)transitionContext
{
UIViewController* toViewController = [transitionContext viewControllerForKey:UITransitionContextToViewControllerKey];
UIViewController* fromViewController = [transitionContext viewControllerForKey:UITransitionContextFromViewControllerKey];
[[transitionContext containerView] addSubview:toViewController.view];
if (self.presenting) {
toViewController.view.transform = CGAffineTransformMakeTranslation(0, toViewController.view.frame.size.height);
}
[UIView animateWithDuration:[self transitionDuration:transitionContext] animations:^{
if (self.presenting) {
toViewController.view.transform = CGAffineTransformIdentity;
} else {
fromViewController.view.transform = CGAffineTransformMakeTranslation(0, toViewController.view.frame.size.height);
}
} completion:^(BOOL finished) {
[transitionContext completeTransition:![transitionContext transitionWasCancelled]];
}];
}
Most of the implementation is from here, I just edited the transition method to your needs: https://stackoverflow.com/a/25026102/2242359
I still strongly recommend to go over some or all these guides:
http://www.teehanlax.com/blog/custom-uiviewcontroller-transitions/
http://www.objc.io/issue-5/view-controller-transitions.html
http://objectivetoast.com/2014/03/17/custom-transitions-on-ios/
Try this :
UIViewController *yourViewController = [[UIViewController alloc]init];
[UIView beginAnimations: #"Showinfo"context: nil];
[UIView setAnimationCurve: UIViewAnimationCurveEaseInOut];
[UIView setAnimationDuration:0.75];
[self.navigationController pushViewController: yourViewController animated:NO];
[UIView setAnimationTransition:UIViewAnimationTransitionFlipFromRight forView:self.navigationController.view cache:NO];
[UIView commitAnimations];

How to implement custom segue animations?

I subclassed UIStoryboardSegue to perform custom segue animations. To make the animation visible I have to add the view from the destination ViewController as a temp view. After performing the animations I am removing the temp view and presenting the final ViewController via (presentViewController:animated:NO).
This however leads to the following warning: "Unbalanced calls to begin/end appearance transitions for".
If I keep my temp-view and do not remove it the warning does not appear but the final view does not respond to touch events anymore. How to get rid of this warning?
My custom segue code:
-(void)perform {
UIViewController *sourceViewController = self.sourceViewController;
UIViewController *destinationViewController = self.destinationViewController;
destinationViewController.view.alpha = 0.;
destinationViewController.view.transform = CGAffineTransformScale(destinationViewController.view.transform, 4.0, 4.0);
[sourceViewController.view addSubview:destinationViewController.view];
[UIView animateWithDuration:kSSSpriteKitFadeOutDuration
delay:0.0
options:UIViewAnimationOptionCurveEaseInOut
animations:^{
destinationViewController.view.transform = CGAffineTransformScale(destinationViewController.view.transform, 0.25, 0.25);
destinationViewController.view.alpha = 1.;
}
completion:^(BOOL finished){
[destinationViewController.view removeFromSuperview]; // remove from temp super view
[sourceViewController presentViewController:destinationViewController animated:NO completion:NULL]; // present VC
}];
}
I am taking 4 UIStoryboardSegue type class. 2 for animation start and rest 2 for animation stop. So i am going to share all code for 4 classes. please try to solve this.
CustomSegue.h
#import <UIKit/UIKit.h>
#interface CustomSegue : UIStoryboardSegue
// Originating point for animation
#property CGPoint originatingPoint;
#property CGRect Startingframe;
#end
CustomSegue.m
#import "CustomSegue.h"
#implementation CustomSegue
- (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
float width = 320;
float height = 480;
float x_Scale = self.Startingframe.size.width/width;
float Y_Scale = self.Startingframe.size.height/height;
destinationViewController.view.transform = CGAffineTransformMakeScale(x_Scale, Y_Scale);
// 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
}];
}
#end
CustomUnwindSegue.h
#import <UIKit/UIKit.h>
#interface CustomUnwindSegue : UIStoryboardSegue
// Target point to animate to (on the button)
#property CGPoint targetPoint;
#property CGRect endFrame;
#end
CustomUnwindSegue.m
#import "CustomUnwindSegue.h"
#implementation CustomUnwindSegue
- (void)perform {
UIViewController *sourceViewController = self.sourceViewController;
UIViewController *destinationViewController = self.destinationViewController;
// Transformation End scale
float width = 320;
float height = 480;
float x_Scale = self.endFrame.size.width/width;
float Y_Scale = self.endFrame.size.height/height;
// Add view to super view temporarily
[sourceViewController.view.superview insertSubview:destinationViewController.view atIndex:0];
[UIView animateWithDuration:0.5
delay:0.0
options:UIViewAnimationOptionCurveEaseInOut
animations:^{
// Shrink!
sourceViewController.view.transform = CGAffineTransformMakeScale(x_Scale, Y_Scale);
sourceViewController.view.center = self.targetPoint;
}
completion:^(BOOL finished){
[destinationViewController.view removeFromSuperview]; // remove from temp super view
[sourceViewController dismissViewControllerAnimated:NO completion:NULL]; // dismiss VC
}];
}
#end
Just connect your action with this custom segue animation like below:

UIViewController custom transitions and state restoration

I have a view controller that is using a custom transition, and it is working well. It takes advantage of the fact that when using UIModalPresentationCustom, the presenting view controller is not removed, and places the new view controller over it with transparency.
However, when using this in combination with state restoration, the presenting view controller IS removed. It would seem that because the view controller is presented without animations, the custom transition code is never called. Is there any way to have the custom transition activated, even when the view controller is not being animated?
- (id<UIViewControllerAnimatedTransitioning>)animationControllerForPresentedController:(UIViewController *)presented
presentingController:(UIViewController *)presenting
sourceController:(UIViewController *)source
{
// never called if we aren't animating
return self;
}
- (id<UIViewControllerAnimatedTransitioning>)animationControllerForDismissedController:(UIViewController *)dismissed
{
return self;
}
- (NSTimeInterval)transitionDuration:(id <UIViewControllerContextTransitioning>)transitionContext
{
return 0.25;
}
- (void)animateTransition:(id <UIViewControllerContextTransitioning>)transitionContext
{
UIViewController *fromViewController = [transitionContext viewControllerForKey:UITransitionContextFromViewControllerKey];
UIViewController *toViewController = [transitionContext viewControllerForKey:UITransitionContextToViewControllerKey];
if (toViewController == self) {
[transitionContext.containerView addSubview:fromViewController.view];
[transitionContext.containerView addSubview:toViewController.view];
self.maskView.alpha = 0.0f;
self.menuView.frame = CGRectMake(0, self.view.bounds.size.height, self.view.bounds.size.width, 286.0f);
[UIView animateWithDuration:[self transitionDuration:transitionContext] animations:^{
fromViewController.view.tintAdjustmentMode = UIViewTintAdjustmentModeDimmed;
[self.menuView updateFrame:^(CGRect *frame) {
frame->origin.y = self.view.bounds.size.height - frame->size.height;
}];
self.maskView.alpha = 0.75f;
} completion:^(BOOL finished) {
self.maskView.userInteractionEnabled = YES;
[transitionContext completeTransition:YES];
}];
} else {
[transitionContext.containerView addSubview:toViewController.view];
[transitionContext.containerView addSubview:fromViewController.view];
self.maskView.userInteractionEnabled = NO;
[UIView animateWithDuration:[self transitionDuration:transitionContext] animations:^{
toViewController.view.tintAdjustmentMode = UIViewTintAdjustmentModeAutomatic;
[self.menuView updateFrame:^(CGRect *frame) {
frame->origin.y = self.view.bounds.size.height;
}];
self.maskView.alpha = 0.0f;
} completion:^(BOOL b){
[transitionContext completeTransition:YES];
[self.menuView updateFrame:^(CGRect *frame) {
frame->origin.y = self.view.bounds.size.height - frame->size.height;
}];
}];
}
}
I can't see how your presentingVC could be removed from hierarchy on state restoration, but what would helpful is to put the following in your app delegate:
- (UIViewController*)application:(UIApplication *)application viewControllerWithRestorationIdentifierPath:(NSArray *)identifierComponents coder:(NSCoder *)coder {
NSLog(#"Application restore state = %#", [identifierComponents componentsJoinedByString:#"."]);
return nil;
}
This way you can follow the state restoration logic if you do not implement custom state restoration classes and rely on Storyboard to do this for you. This may give a food for thoughts.

Resources