本文主要依赖于飘金-iOS 在控制器间跳转实现过渡动画的文章, 文章介绍了两个方法, 一个是简单的系统方法, 就是开篇的跳转前, 设置keyWindow的layer, 这个demo相信自己写出来没难度.
然后我在看第二个方法的时候, 有点疑问, 就那个UIViewControllerAnimatedTransitioning
, 这玩意到底写在哪, 主要是蒙了, 然后我搜到了另一篇文章不会抽烟-iOS UIViewControllerAnimatedTransitioning 自定义转场动画, 开头直言: 1.自定义转场:继承NSObject,并遵循UIViewControllerAnimatedTransitioning协议。
, 然后才反应过来.
现在整理了一下整个动画过程
首先, 主界面跳转页面, 我们正常操作(采纳协议<UIViewControllerTransitioningDelegate>
获取跳转过程中的方法)
- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event {
NewToViewController *toVC = [[NewToViewController alloc] init];
// 因为我需要拿到这个跳转过程,
// 所以设置代理, 实现UIViewControllerTransitioningDelegate协议方法
toVC.transitioningDelegate = self;
[self presentViewController:toVC animated:YES completion:nil];
}
实现代理方法
// 这个协议里面有好几个方法, 基本差不多, 看自己需要
- (nullable id <UIViewControllerAnimatedTransitioning>)animationControllerForPresentedController:(UIViewController *)presented presentingController:(UIViewController *)presenting sourceController:(UIViewController *)source {
return [NewAnimationTransition new];
}
以下截取原文, 如果你要带导航的专场效果, 请参考
@protocol UINavigationControllerDelegate
这是修改Navigation跳转动画需要实现的协议,当我们通过pop或者push进行跳转时,都会调用下面的方法(协议的其他方法由于暂时用不到,所以就不介绍了),我们可以看到返回值是id <UIViewControllerAnimatedTransitioning>,就是我们之前编写的动画对象。
- (nullable id <UIViewControllerAnimatedTransitioning>)navigationController:(UINavigationController *)navigationController
animationControllerForOperation:(UINavigationControllerOperation)operation
fromViewController:(UIViewController *)fromVC
toViewController:(UIViewController *)toVC;
方法中的operation参数是一个枚举类型,我们可以判断它的值是 UINavigationControllerOperationPush还是
UINavigationControllerOperationPop来区别当前的跳转方式。
这个转场对象怎么来的呢?
新建一个转场对象NewAnimationTransition
, 继承自NSObject
, 采纳协议<UIViewControllerAnimatedTransitioning>
@interface NewAnimationTransition : NSObject<UIViewControllerAnimatedTransitioning>
@end
.m实现代码, 首先是UIViewControllerAnimatedTransitioning
协议的两个方法, 这个飘金-iOS 在控制器间跳转实现过渡动画里面写的比我详细, 如果想看代码释义可以看这个
//这个方法中我们只要返回页面跳转动画的执行时间
-(NSTimeInterval)transitionDuration:(id < UIViewControllerContextTransitioning >)transitionContext {
return 0.5;
}
//在这个方法中实现具体动画
-(void)animateTransition:(id < UIViewControllerContextTransitioning >)transitionContext {
// 方法中的参数transitionContext是当前临时控制器界面的上下文。
self.transitionContext = transitionContext;
// 通过上下文,我们先拿到临时视图控制器的背景视图containerView,他已经有一个子视图,即fromViewController.view。
// 我们要做的是,先获得toViewController
UIViewController *toVC = [transitionContext viewControllerForKey:UITransitionContextToViewControllerKey];
[[transitionContext containerView] addSubview:toVC.view];
// 要实现Demo里的效果,我们需要CAShapeLayer来给toView做遮挡,
// 然后从修改ShapeLayer.path属性,从一个小圆变成一个囊括全屏的大圆,小圆大圆我们通过UIBezierPath画出来
CGFloat kWindowH = [UIScreen mainScreen].bounds.size.height;
CGFloat kWindowW = [UIScreen mainScreen].bounds.size.width;
CGRect circleCenterRect = CGRectMake(120, kWindowH, 50, 50);
//圆圈1--小圆
UIBezierPath *smallCircleBP = [UIBezierPath bezierPathWithOvalInRect:circleCenterRect];
//圆圈2--大圆
//以_circleCenterRect的中心为圆心
CGFloat centerX = circleCenterRect.origin.x+circleCenterRect.size.width/2;
CGFloat centerY = circleCenterRect.origin.y+circleCenterRect.size.height/2;
//找出圆心到页面4个角 最长的距离 作为半径
CGFloat r1 = (kWindowW-centerX)>centerX?(kWindowW-centerX):centerX;
CGFloat r2 = (kWindowW-centerY)>centerY?(kWindowW-centerY):centerY;
CGFloat radius = sqrt((r1 * r1) + (r2 * r2));
UIBezierPath *bigCircleBP = [UIBezierPath bezierPathWithOvalInRect:CGRectInset(circleCenterRect, -radius, -radius)];
// 画完圆后通过CABasicAnimation执行:
//设置maskLayer
CAShapeLayer *maskLayer = [CAShapeLayer layer];//将它的 path 指定为最终的 path 来避免在动画完成后会回弹
toVC.view.layer.mask = maskLayer;
maskLayer.path = bigCircleBP.CGPath;
//执行动画
CABasicAnimation *maskLayerAnimation = [CABasicAnimation animationWithKeyPath:@"path"];
maskLayerAnimation.fromValue = (__bridge id)(smallCircleBP.CGPath);
maskLayerAnimation.toValue = (__bridge id)((bigCircleBP.CGPath));
maskLayerAnimation.duration = [self transitionDuration:transitionContext];
maskLayerAnimation.delegate = self;
[maskLayer addAnimation:maskLayerAnimation forKey:@"path"];
}
然后该对象采纳协议, 就是<CAAnimationDelegate>
实现方法
- (void)animationDidStop:(CAAnimation *)anim finished:(BOOL)flag{
//告诉 系统这个 transition 完成
[self.transitionContext completeTransition:![self.transitionContext transitionWasCancelled]];
//清除 fromVC 的 mask
[self.transitionContext viewControllerForKey:UITransitionContextFromViewControllerKey].view.layer.mask = nil;
[self.transitionContext viewControllerForKey:UITransitionContextToViewControllerKey].view.layer.mask = nil;
}
以上是转场动画对象
到这, 我们跳转页面, 然后自定义转场动画就搞定
然后我顺便把第一种系统自带的方法, 放在demo里面, 一起看吧
界面丑陋, 担待, 主要就是想做个demo出来, 自带界面, 我随机采用一种动画效果, label显示的就是效果名称, 这个你们自己去研究吧
网友评论