美文网首页
【iOS开发】转场动画(一)-简单接触

【iOS开发】转场动画(一)-简单接触

作者: xiacheng | 来源:发表于2016-12-29 15:42 被阅读106次

    转场动画:
    12.29
    自己写过一个转场动画以后,感觉这个转场动画设计的很好,逻辑清晰,自由度也比较大,而且实现起来也比较容易。
    一、present 动画
    问题:
    1、为什么在+ animateTransition方法中,一定要自己调用
    [containerview addSubview:toVc.view]
    这个有点想不明白,不是应该自己添加的吗??
    我在第一次尝试的时候,忘记把toVc.view 添加到上面去,结果虽然最后调用了[transitionContext completeTransition:YES];,但是还是transationView 还在视图中,造成界面不能够再操作。
    现在想想,自己添加其实是有了更多的自由度,可以用来管理什么时候再把新的toVc.view 添加到容器上。

    自定义转场动画的实现:
    1、在要实现自定义转场动画的viewController 的初始化方法里面里面设置转场动画的代理和style:

    self.transitioningDelegate = self;
    self.modalPresentationStyle = UIModalPresentationCustom;
    

    2、实现转场动画的代理方法。 这里只实现了最基本的两个方法,即present 和dismiss动画。另外还有手势操作和动画被打断时的的代理方法。
    这两个代理方法都返回一个遵守<UIViewControllerAnimatedTransitioning>协议的对象,我这里是 CircleTransitionAnimation类。

    - (nullable id <UIViewControllerAnimatedTransitioning>)animationControllerForPresentedController:(UIViewController *)presented presentingController:(UIViewController *)presenting sourceController:(UIViewController *)source
    {
        return [CircleTransitionAnimation transitioningWithType:CircleTransitionAnimationTypePresent];
    }
    - (nullable id <UIViewControllerAnimatedTransitioning>)animationControllerForDismissedController:(UIViewController *)dismissed
    {
        return [CircleTransitionAnimation transitioningWithType:CircleTransitionAnimationTypeDismiss];
    }
    

    3、自定义遵守<UIViewControllerAnimatedTransitioning>协议的类,我这里是 CircleTransitionAnimation类。
    在这个类中实现相关协议方法来完成转场动画:

    #pragma mark UIViewControllerTransitioning
    //这个方法返回转场动画的持续时长
    - (NSTimeInterval)transitionDuration:(nullable id <UIViewControllerContextTransitioning>)transitionContext;
    {
        return 0.5;
    }
    
    //这个方法是 转场时要执行的动画,我把代码分到两个私有方法里面了
    - (void)animateTransition:(id <UIViewControllerContextTransitioning>)transitionContext{
        //animation
        switch (_type) {
            case CircleTransitionAnimationTypePresent:
                [self presentAnimationWithContext:transitionContext];
                break;
            case CircleTransitionAnimationTypeDismiss:
                [self dismissAnimationWithContext:transitionContext];
            default:
                break;
        }
    }
    
    // This is a convenience and if implemented will be invoked by the system when the transition context's completeTransition: method is invoked.
    - (void)animationEnded:(BOOL) transitionCompleted
    {
        NSLog(@"animation ended");
    }
    
    #pragma mark CAAnimationDelegate
    - (void)animationDidStop:(CAAnimation *)anim finished:(BOOL)flag
    {
        NSLog(@"animationDidStop");
        switch (_type) {
            case CircleTransitionAnimationTypePresent:{
                NSLog(@"animationDidStop:present");
                id<UIViewControllerContextTransitioning> transitionContext = [anim valueForKey:@"transitionContext"];
                [transitionContext completeTransition:YES];
                NSLog(@"%@",[transitionContext viewControllerForKey:UITransitionContextToViewKey].view);
                //这边为什么取不到 view???
                [transitionContext viewControllerForKey:UITransitionContextToViewKey].view.layer.mask = nil;
                
            }
                break;
            case CircleTransitionAnimationTypeDismiss:{
                NSLog(@"animationDidStop:dismiss");
                id<UIViewControllerContextTransitioning> transitionContext = [anim valueForKey:@"transitionContext"];
                [transitionContext completeTransition:![transitionContext transitionWasCancelled]];
                if ([transitionContext transitionWasCancelled]) {
                    [transitionContext viewControllerForKey:UITransitionContextFromViewControllerKey].view.layer.mask = nil;
                }
            }
                break;
        }
    }
    
    #pragma mark - custom delegates
    
    #pragma mark - event responses
    
    #pragma mark - public methods 
    + (instancetype)transitioningWithType:(CircleTransitionAnimationType)type
    {
        CircleTransitionAnimation *transitioning = [[self alloc]init];
        transitioning.type = type;
        return transitioning;
    }
    
    #pragma mark - private methods
    - (void)presentAnimationWithContext:(id <UIViewControllerContextTransitioning>)transitionContext
    {
        //vc
        ViewController *fromVc = [transitionContext viewControllerForKey:UITransitionContextFromViewControllerKey];
        UIViewController *toVc = [transitionContext viewControllerForKey:UITransitionContextToViewControllerKey];
        UIView *containerView = [transitionContext containerView];
        [containerView addSubview:toVc.view];
        //圆形放大动画
        //mask
        UIBezierPath *startPath = [UIBezierPath bezierPathWithOvalInRect:fromVc.Btnframe];
        float radius = sqrt(kScreenWidth * kScreenWidth + kScreenHeight * kScreenHeight) / 2.0;
        //没理解
    //    CGFloat x = MAX(fromVc.Btnframe.origin.x, containerView.frame.size.width - fromVc.Btnframe.origin.x);
    //    CGFloat y = MAX(fromVc.Btnframe.origin.y, containerView.frame.size.height - fromVc.Btnframe.origin.y);
    //    CGFloat radius = sqrtf(pow(x, 2) + pow(y, 2));
        UIBezierPath *endPath = [UIBezierPath bezierPathWithArcCenter:containerView.center radius:radius startAngle:0 endAngle:M_PI * 2 clockwise:YES];
        CAShapeLayer *maskLayer = [CAShapeLayer new];
        maskLayer.path = endPath.CGPath;
        maskLayer.fillColor = [UIColor greenColor].CGColor;
        toVc.view.layer.mask = maskLayer;
        //animation
        CAKeyframeAnimation *animation = [CAKeyframeAnimation animationWithKeyPath:@"path"];
        animation.values = @[(__bridge id)startPath.CGPath,(__bridge id)endPath.CGPath];
        animation.duration = [self transitionDuration:transitionContext];
        animation.keyTimes = @[@1];
        animation.beginTime = CACurrentMediaTime();
        animation.removedOnCompletion = YES;
        animation.delegate = self;
        [animation setValue:transitionContext forKey:@"transitionContext"];
        [maskLayer addAnimation:animation forKey:@"path"];
    }
    
    - (void)dismissAnimationWithContext:(id <UIViewControllerContextTransitioning>)transitionContext
    {
        UIViewController *fromVC = [transitionContext viewControllerForKey:UITransitionContextFromViewControllerKey];
        UINavigationController *toVC = [transitionContext viewControllerForKey:UITransitionContextToViewControllerKey];
        ViewController *temp = toVC;
        UIView *containerView = [transitionContext containerView];
        //画两个圆路径
        CGFloat radius = sqrtf(containerView.frame.size.height * containerView.frame.size.height + containerView.frame.size.width * containerView.frame.size.width) / 2;
        UIBezierPath *startCycle = [UIBezierPath bezierPathWithArcCenter:containerView.center radius:radius startAngle:0 endAngle:M_PI * 2 clockwise:YES];
        UIBezierPath *endCycle =  [UIBezierPath bezierPathWithOvalInRect:temp.Btnframe];
        //创建CAShapeLayer进行遮盖
        CAShapeLayer *maskLayer = [CAShapeLayer layer];
        maskLayer.fillColor = [UIColor greenColor].CGColor;
        maskLayer.path = endCycle.CGPath;
        fromVC.view.layer.mask = maskLayer;
        //创建路径动画
        CABasicAnimation *maskLayerAnimation = [CABasicAnimation animationWithKeyPath:@"path"];
        maskLayerAnimation.delegate = self;
        maskLayerAnimation.fromValue = (__bridge id)(startCycle.CGPath);
        maskLayerAnimation.toValue = (__bridge id)((endCycle.CGPath));
        maskLayerAnimation.duration = [self transitionDuration:transitionContext];
        maskLayerAnimation.delegate = self;
        maskLayerAnimation.timingFunction = [CAMediaTimingFunction  functionWithName:kCAMediaTimingFunctionEaseInEaseOut];
        [maskLayerAnimation setValue:transitionContext forKey:@"transitionContext"];
        [maskLayer addAnimation:maskLayerAnimation forKey:@"path"];
    }
    

    这样就完成了一个简单的转场动画,最终的效果图如下:

    CircleTransitioning.gif

    相关文章

      网友评论

          本文标题:【iOS开发】转场动画(一)-简单接触

          本文链接:https://www.haomeiwen.com/subject/lwzuvttx.html