自定义Push和Pop的动画效果

先写一些通用部分

实现协议

在要添加自定义效果的视图控制器中实现代理协议UINavigationControllerDelegate

- (void)viewDidAppear:(BOOL)animated
{
    [super viewDidAppear:animated];
    self.navigationController.delegate = self;
}

实现代理方法

#pragma mark -UINavigationControllerDelegate
- (id)navigationController:(UINavigationController *)navigationController animationControllerForOperation:(UINavigationControllerOperation)operation fromViewController:(UIViewController *)fromVC toViewController:(UIViewController *)toVC
{
    if (operation == UINavigationControllerOperationPush) {
        //返回我们自定义的效果
        return [[PushTransition alloc]init];
    }
    else if (operation == UINavigationControllerOperationPop){
        return [[PopTransition alloc]init];
    }
    //返回nil则使用默认的动画效果
    return nil;
}

注:PushTransition、PopTransition为具体效果的实现

PushTransition的实现

这种效果的实现类需要实现UIViewControllerAnimatedTransitioning协议

通用代码部分

//.h
#import 
#import 

@interface PushTransition : NSObject

@end

//.m
#import "PushTransition.h"

@interface PushTransition ()

@end

@implementation PushTransition

// This is used for percent driven interactive transitions, as well as for container controllers that have companion animations that might need to
// synchronize with the main animation.
- (NSTimeInterval)transitionDuration:(nullable id )transitionContext
{
    //返回动画的执行时间
    return 1.0f;
}
// This method can only  be a nop if the transition is interactive and not a percentDriven interactive transition.
- (void)animateTransition:(id )transitionContext
{    
    self.transitionContext = transitionContext;

    UIViewController *fromVC = [transitionContext viewControllerForKey:UITransitionContextFromViewControllerKey];
    UIViewController *toVC = [transitionContext viewControllerForKey:UITransitionContextToViewControllerKey];
    //不添加的话,屏幕什么都没有
    UIView *containerView = [transitionContext containerView];
    [containerView addSubview:fromVC.view];
    [containerView addSubview:toVC.view];

    //注意注意一定要注意这里。我们就是在这里添加我们所需要的动画效果。将动画效果的代码放在这里就行了。重要的事情要说好几遍

    //如果取消了就设置为NO,反之,设置为YES。如果添加了动画,这句代码在动画结束之后再调用
    [transitionContext completeTransition:![transitionContext transitionWasCancelled]];
}

实例程序一

实现了一个简单的扇形动画

//.m
#import "PushTransition.h"

@interface PushTransition ()

@property(nonatomic,strong) idtransitionContext;

@end

@implementation PushTransition

// This is used for percent driven interactive transitions, as well as for container controllers that have companion animations that might need to
// synchronize with the main animation.
- (NSTimeInterval)transitionDuration:(nullable id )transitionContext
{
    return 1.0f;
}
// This method can only  be a nop if the transition is interactive and not a percentDriven interactive transition.
- (void)animateTransition:(id )transitionContext
{
    self.transitionContext = transitionContext;

    UIViewController *fromVC = [transitionContext viewControllerForKey:UITransitionContextFromViewControllerKey];
    UIViewController *toVC = [transitionContext viewControllerForKey:UITransitionContextToViewControllerKey];
    //不添加的话,屏幕什么都没有
    UIView *containerView = [transitionContext containerView];
    [containerView addSubview:fromVC.view];
    [containerView addSubview:toVC.view];    
CGRect originRect = CGRectMake(0, 0, 50, 50);

    UIBezierPath *maskStartPath = [UIBezierPath bezierPathWithOvalInRect:originRect];
    UIBezierPath *maskEndPath = [UIBezierPath bezierPathWithOvalInRect:CGRectInset(originRect, -2000, -2000)];

    //创建一个CAShapeLayer来负责展示圆形遮盖
CAShapeLayer *maskLayer = [CAShapeLayer layer];
//    maskLayer.path = maskEndPath.CGPath;//将他的path指定为最终的path,来避免在动画完成后回弹
toVC.view.layer.mask = maskLayer;

    CABasicAnimation *maskAnimation = [CABasicAnimation animationWithKeyPath:@"path"];
    maskAnimation.fromValue = (id)maskStartPath.CGPath;
    maskAnimation.toValue = (id)maskEndPath.CGPath;
    maskAnimation.duration = [self     transitionDuration:transitionContext];
    maskAnimation.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut];
    maskAnimation.fillMode = kCAFillModeForwards;
    maskAnimation.removedOnCompletion = NO;
    maskAnimation.delegate = self;
    [maskLayer addAnimation:maskAnimation forKey:@"Path"];
}

- (void)animationDidStop:(CAAnimation *)anim finished:(BOOL)flag
{
    NSLog(@"搞定结束");
    [self.transitionContext completeTransition:![self.transitionContext transitionWasCancelled]];
    //去除mask
    [self.transitionContext viewControllerForKey:UITransitionContextFromViewControllerKey].view.layer.mask = nil;
    [self.transitionContext viewControllerForKey:UITransitionContextToViewControllerKey].view.layer.mask = nil;
}

@end

实例程序二

实现从下方弹出的效果

NSTimeInterval duration = [self transitionDuration:transitionContext];
CGRect screenBounds = [[UIScreen mainScreen]bounds];
CGRect finalFrame = [transitionContext finalFrameForViewController:toVC];
toVC.view.frame = CGRectOffset(finalFrame, 0, screenBounds.size.height);

[UIView animateWithDuration:duration delay:0.0 usingSpringWithDamping:0.6 initialSpringVelocity:0.0 options:UIViewAnimationOptionCurveLinear animations:^{
    toVC.view.frame = finalFrame;
} completion:^(BOOL finished) {
    [transitionContext completeTransition:![transitionContext transitionWasCancelled]];
}];

你可能感兴趣的:(自定义Push和Pop的动画效果)