自定义转场动画步骤:bash
自定义动画的主要代码都在管理类中实现,在须要动画的时候调用这个类的方法便可。动画
ZZFTransition.hui
#import <Foundation/Foundation.h>#import <UIKit/UIKit.h>
typedef NS_ENUM(NSUInteger, ZZFTransitionType) { ZZFTransitionTypePush, ZZFTransitionTypePop,};
@interface ZZFTransition : NSObject<UIViewControllerAnimatedTransitioning,CAAnimationDelegate>+(ZZFTransition *)transitionAnimationWithType:(ZZFTransitionType)type;@end复制代码
定义枚举类型ZZFTransitionType,包含两个值,分别是push类型和pop类型。spa
定义类方法transitionAnimationWithType,传入动画类型,返回实例对象。代理
ZZFTransition.mcode
+(ZZFTransition *)transitionAnimationWithType:(ZZFTransitionType)type{
ZZFTransition *transition = [[ZZFTransition alloc]init];
transition.type = type;
return transition;
}
复制代码
在.m文件中实现transitionAnimationWithType类方法,初始化实例对象,设置动画类型,返回对象。cdn
-(NSTimeInterval)transitionDuration:(id<UIViewControllerContextTransitioning>)transitionContext{
return 3;
}
-(void)animateTransition:(id<UIViewControllerContextTransitioning>)transitionContext{
self.transitionContext = transitionContext;
switch (_type) {
case ZZFTransitionTypePush:
{
[self pushAnimation:transitionContext];
}
break;
case ZZFTransitionTypePop:
{
[self popAnimation:transitionContext];
}
break;
}
}
复制代码
-(NSTimeInterval)transitionDuration:(id<UIViewControllerContextTransitioning>)transitionContext;这个方法返回转场动画执行的时间。对象
-(void)animateTransition:(id<UIViewControllerContextTransitioning>)transitionContext;在这个方法内部实现动画的主要代码。开发
这里根据建立管理对象的时候传进来的动画类型,来分别处理不一样的动画逻辑。把push和pop的动画实现放到一个方法中去,这里的代码更简洁。animation
- (void)pushAnimation:(id<UIViewControllerContextTransitioning>)transitionContext{
// 得到即将消失的vc的v
UIView *fromeView = [transitionContext viewForKey:UITransitionContextFromViewKey];
// 得到即将出现的vc的v
UIView *toView = [transitionContext viewForKey:UITransitionContextToViewKey];
// 得到容器view
UIView *containerView = [transitionContext containerView];
[containerView addSubview:fromeView];
[containerView addSubview:toView];
UIBezierPath *startBP = [UIBezierPath bezierPathWithOvalInRect:CGRectMake((containerView.frame.size.width)/2, (containerView.frame.size.height)/2, 12, 12)];
CGFloat radius = containerView.frame.size.height - 100;
UIBezierPath *finalBP = [UIBezierPath bezierPathWithOvalInRect:CGRectMake(150 - radius, 150 -radius, radius*2, radius*2)];
CAShapeLayer *maskLayer = [CAShapeLayer layer];
maskLayer.path = finalBP.CGPath;
toView.layer.mask = maskLayer;
//执行动画
CABasicAnimation *animation = [CABasicAnimation animationWithKeyPath:@"path"];
animation.fromValue = (__bridge id _Nullable)(startBP.CGPath);
animation.toValue = (__bridge id _Nullable)(finalBP.CGPath);
animation.duration = [self transitionDuration:transitionContext];
animation.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut];
animation.delegate = self;
[maskLayer addAnimation:animation forKey:@"path"];
}
复制代码
参数transitionContext是执行动画的上下文,里面包含动画执行所须要的全部元素。
经过键值的方式,从上下文对象中能够的到须要执行动画的上一个VC和view,下一个VC和view。
UITransitionContextFromViewKey 即将消失的view
UITransitionContextToViewKey 即将出现的view
UITransitionContextFromViewControllerKey 即将消失的控制器
UITransitionContextToViewControllerKey 即将出现的控制器
而后经过上下文的containerView方法能够获得一个容器view,全部的动画都是在这个容器view内进行的,因此须要把fromView和toView都加入到containerView中。
下边用贝塞尔曲线画两个圆,而后用CABasicAnimation执行从小圆到大圆的动画。
到这里一个自定义的push动画就完成了,下边是使用的方法。
在须要执行自定义动画的控制器中,遵照UINavigationControllerDelegate协议,并实现-(id<UIViewControllerAnimatedTransitioning>)navigationController:(UINavigationController *)navigationController animationControllerForOperation:(UINavigationControllerOperation)operation fromViewController:(UIViewController *)fromVC toViewController:(UIViewController *)toVC;代理方法。
在执行push或pop操做时,这个代理方法会回调,在方法内部拿到跳转的动画类型,而后执行本身的动画代码就能够实现自定义转场动画。
-(id<UIViewControllerAnimatedTransitioning>)navigationController:(UINavigationController *)navigationController animationControllerForOperation:(UINavigationControllerOperation)operation fromViewController:(UIViewController *)fromVC toViewController:(UIViewController *)toVC{
if (operation == UINavigationControllerOperationPush) {
ZZFTransition *pushTranstion = [ZZFTransition transitionAnimationWithType:ZZFTransitionTypePush];
return pushTranstion;
}
return nil;
}
复制代码
这里只实现了push,要实现pop自定义动画,同理。
执行push动画后,能够发现一个问题,界面的全部交互失效了,是由于执行动画时控制器view上加了遮罩layer,在动画执行完成后把遮罩去掉就能够了。
-(void)animationDidStop:(CAAnimation *)anim finished:(BOOL)flag{
[self.transitionContext completeTransition:YES];
//清除相应控制器视图的mask
[self.transitionContext viewForKey:UITransitionContextFromViewKey].layer.mask = nil;
[self.transitionContext viewForKey:UITransitionContextToViewKey].layer.mask = nil;
}
复制代码