iOS核心动画CoreAnimation系统进阶(自定义转场动画)

这里写图片描述

想要实现自定义转场动画,需要分两个步骤

一.实现相关协议

@interface CustomTransitionViewController ()<UINavigationControllerDelegate>
-(void)viewWillAppear:(BOOL)animated{
    [super viewWillAppear:animated];
    self.navigationController.delegate = self;
}
//告诉nav,想自己自定义一个转场
-(id<UIViewControllerAnimatedTransitioning>)navigationController:(UINavigationController *)navigationController animationControllerForOperation:(UINavigationControllerOperation)operation fromViewController:(UIViewController *)fromVC toViewController:(UIViewController *)toVC{
    if (operation == UINavigationControllerOperationPush) {
        WTCircleTransition *trans =[WTCircleTransition new];

        return trans;
    }
    return nil;
}

二.做动画

创建WTCircleTransition协议类

#import <Foundation/Foundation.h>
#import <UIKit/UIKit.h>

@interface WTCircleTransition : NSObject<UIViewControllerAnimatedTransitioning>

@end

实现UIViewControllerAnimatedTransitioning中的协议

这里写图片描述

WTCircleTransition.m

-(NSTimeInterval)transitionDuration:(id<UIViewControllerContextTransitioning>)transitionContext{
    return .8f;
}
-(void)animateTransition:(id<UIViewControllerContextTransitioning>)transitionContext{
    //1.持有transitionContext上下文
    _context = transitionContext;
    //2.获取view的容器
    UIView *containerView = [transitionContext containerView];
    //3.初始化toVc,把toVc的view添加到容器view
    UIViewController *toVc =[transitionContext viewControllerForKey:UITransitionContextToViewControllerKey];

    //4.添加动画
    /*
     拆分动画
     4.1 2个圆(大小圆的中心点一致)
     4.2 贝塞尔
     4.3 蒙版
     */
    UIButton *btn;
    CustomTransitionViewController * VC1;
    SecondViewController * VC2;
    if (_isPush) {
        VC1 =[transitionContext viewControllerForKey:UITransitionContextFromViewControllerKey];
        VC2 = [transitionContext viewControllerForKey:UITransitionContextToViewControllerKey];
        btn = VC1.customTransitionBtn;
    }else{
        VC2 =[transitionContext viewControllerForKey:UITransitionContextFromViewControllerKey];
        VC1 = [transitionContext viewControllerForKey:UITransitionContextToViewControllerKey];
        btn = VC2.backBtn;
    }
     [containerView addSubview:VC1.view];
     [containerView addSubview:VC2.view];
    //5.画出小圆
    UIBezierPath *smallPath =[UIBezierPath bezierPathWithOvalInRect:btn.frame];//内切圆
    CGPoint centerP;
    centerP = btn.center;
    //6.求大圆半径 勾股定理
    CGFloat radius;
    CGFloat y = CGRectGetHeight(toVc.view.bounds)-CGRectGetMaxY(btn.frame)+CGRectGetHeight(btn.bounds)/2;
    CGFloat x = CGRectGetWidth(toVc.view.bounds)-CGRectGetMaxX(btn.frame)+CGRectGetWidth(btn.bounds)/2;
    if (btn.frame.origin.x >CGRectGetWidth(toVc.view.bounds)/2) {
        //位于14象限
        if (CGRectGetMaxY(btn.frame)< CGRectGetHeight(toVc.view.bounds)/2) {
            //第一象限
            //sqrtf(求平方根)
            radius = sqrtf(btn.center.x *btn.center.x +y*y);
        }else{
            //第四象限
            radius = sqrtf(btn.center.x * btn.center.x + btn.center.y*btn.center.y);
        }
    }else{
        if (CGRectGetMaxY(btn.frame)<CGRectGetHeight(toVc.view.frame)) {
            //第二象限
            radius = sqrtf(x*x+y*y);
        }else{
            //第三象限
            radius = sqrtf(x*x + btn.center.y*btn.center.y);
        }
    }
    //7.画大圆
    UIBezierPath * bigPath = [UIBezierPath bezierPathWithArcCenter:centerP radius:radius startAngle:0 endAngle:2*M_PI clockwise:YES];
    //8.
    CAShapeLayer *shapeLayer =[CAShapeLayer layer];

    if (_isPush) {
        shapeLayer.path = bigPath.CGPath;
    } else{
        shapeLayer.path = smallPath.CGPath;
    }

    //9.添加蒙版
//    [toVc.view.layer addSublayer:shapeLayer];
    UIViewController *VC;
    if (_isPush) {
        VC = [transitionContext viewControllerForKey:UITransitionContextToViewControllerKey];
    }else{
        VC = [transitionContext viewControllerForKey:UITransitionContextFromViewControllerKey];
    }
    VC.view.layer.mask = shapeLayer;

    //10.给layer添加动画
    CABasicAnimation *anim =[CABasicAnimation animationWithKeyPath:@"path"];
    if (_isPush) {
         anim.fromValue = (id)smallPath.CGPath;
    }else{
         anim.fromValue = (id)bigPath.CGPath;
    }
    //重要,动画时间要和转场时间一致
    anim.duration = [self transitionDuration:transitionContext];
    anim.delegate = self;
    [shapeLayer addAnimation:anim forKey:nil];
}
#pragma mark - CAAnimationDelegate
-(void)animationDidStop:(CAAnimation *)anim finished:(BOOL)flag{
    [_context completeTransition:YES];
    //去掉蒙版
    if (_isPush) {
        UIViewController * toVc =[_context viewControllerForKey:UITransitionContextToViewControllerKey];
        toVc.view.layer.mask = nil;
    }else{
        UIViewController * toVc =[_context viewControllerForKey:UITransitionContextFromViewControllerKey];
        toVc.view.layer.mask = nil;
    }

}

大圆半径

大圆半径

这里写图片描述

勾股定理求半径

这里写图片描述

判断象限

在做自定义转场动画时,我们需要进行几个步骤:

  1. 实现相关协议 push/pop motal segue
  2. 添加实现了UIViewControllerAnimatedTransitioning的类
  3. 在类里面实现动画协议,然后添加转场动画
  4. 告诉上下文,动画完成

总结:自定义切换并不会改变VC的组织结构,只是负责提供了view的效果

实现效果:

这里写图片描述

gitHub代码参考

猜你喜欢

转载自blog.csdn.net/wtdask/article/details/81632530