界面搭建好了:

然后想在Push的时候实现自定义转场动画首先要遵守一个协议UINavigationControllerDelegate
苹果在 UINavigationControllerDelegate 中给出了几个协议方法,通过返回类型就可以很清楚地知道各自的具体作用。
//用来自定义转场动画
- (nullable id)navigationController:(UINavigationController *)navigationController animationControllerForOperation:(UINavigationControllerOperation)operation fromViewController:(UIViewController *)fromVC toViewController:(UIViewController *)toVC NS_AVAILABLE_IOS(7_0);
//为这个动画添加用户交互
- (nullable id)navigationController:(UINavigationController *)navigationController interactionControllerForAnimationController:(id) animationController NS_AVAILABLE_IOS(7_0);
在第一个方法里只要返回一个准守UIViewControllerInteractiveTransitioning协议的对象,并在里面实现动画即可
创建继承自 NSObject 并且声明 UIViewControllerAnimatedTransitioning 的的动画类。 重载 UIViewControllerAnimatedTransitioning 中的协议方法。
//返回动画时间
- (NSTimeInterval)transitionDuration:(nullable id)transitionContext;
//将动画的代码写到里面即可
- (void)animateTransition:(id)transitionContext;
首先我自定义一个名为LRTransitionPushController的类继承于NSObject准守了UIViewControllerAnimatedTransitioning协议
- (void)animateTransition:(id)transitionContext{
self.transitionContext = transitionContext;
//获取源控制器 注意不要写成 UITransitionContextFromViewKey
LRTransitionPushController *fromVc = [transitionContext viewControllerForKey:UITransitionContextFromViewControllerKey];
//获取目标控制器 注意不要写成 UITransitionContextToViewKey
LRTransitionPopController *toVc = [transitionContext viewControllerForKey:UITransitionContextToViewControllerKey];
//获得容器视图
UIView *containView = [transitionContext containerView];
// 都添加到container中。注意顺序 目标控制器的view需要后面添加
[containView addSubview:fromVc.view];
[containView addSubview:toVc.view];
UIButton *button = fromVc.button;
//绘制圆形
UIBezierPath *startPath = [UIBezierPath bezierPathWithOvalInRect:button.frame];
//创建两个圆形的 UIBezierPath 实例;一个是 button 的 size ,另外一个则拥有足够覆盖屏幕的半径。最终的动画则是在这两个贝塞尔路径之间进行的
//按钮中心离屏幕最远的那个角的点
CGPoint finalPoint;
//判断触发点在那个象限
if(button.frame.origin.x > (toVc.view.bounds.size.width / 2)){
if (button.frame.origin.y < (toVc.view.bounds.size.height / 2)) {
//第一象限
finalPoint = CGPointMake(0, CGRectGetMaxY(toVc.view.frame));
}else{
//第四象限
finalPoint = CGPointMake(0, 0);
}
}else{
if (button.frame.origin.y < (toVc.view.bounds.size.height / 2)) {
//第二象限
finalPoint = CGPointMake(CGRectGetMaxX(toVc.view.frame), CGRectGetMaxY(toVc.view.frame));
}else{
//第三象限
finalPoint = CGPointMake(CGRectGetMaxX(toVc.view.frame), 0);
}
}
CGPoint startPoint = CGPointMake(button.center.x, button.center.y);
//计算向外扩散的半径 = 按钮中心离屏幕最远的那个角距离 - 按钮半径
CGFloat radius = sqrt((finalPoint.x-startPoint.x) * (finalPoint.x-startPoint.x) + (finalPoint.y-startPoint.y) * (finalPoint.y-startPoint.y)) - sqrt(button.frame.size.width/2 * button.frame.size.width/2 + button.frame.size.height/2 * button.frame.size.height/2);
UIBezierPath *endPath = [UIBezierPath bezierPathWithOvalInRect:CGRectInset(button.frame, -radius, -radius)];
//赋值给toVc视图layer的mask
CAShapeLayer *maskLayer = [CAShapeLayer layer];
maskLayer.path = endPath.CGPath;
toVc.view.layer.mask = maskLayer;
CABasicAnimation *maskAnimation =[CABasicAnimation animationWithKeyPath:@"path"];
maskAnimation.fromValue = (__bridge id)startPath.CGPath;
maskAnimation.toValue = (__bridge id)endPath.CGPath;
maskAnimation.duration = [self transitionDuration:transitionContext];
maskAnimation.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut];
maskAnimation.delegate = self;
[maskLayer addAnimation:maskAnimation forKey:@"path"];
}










