iOS自定义转场动画

作者: hjmengx | 来源:发表于2016-10-26 20:18 被阅读50次

    先看效果图:

    Transition.gif

    上面就是要实现的Modal转场效果

    首先,如果要自定义转场动画的话,需要设置

    transitioningDelegate = [FFTransitionDelegateshareInstance];

    modalPresentationStyle = UIModalPresentationCustom;

    FFTransitionDelegate是实现了UIViewControllerTransitioningDelegate protocol,并实现它的代理方法,我在这里使用了单例模式。

    staticFFTransitionDelegate* _instance;

    + (instancetype)shareInstance{

    if(!_instance){

    _instance= [[FFTransitionDelegatealloc]init];

    }

    return_instance;

    }

    + (instancetype)allocWithZone:(struct_NSZone*)zone{

    if(!_instance){staticdispatch_once_tonce;

    dispatch_once(&once, ^{

    _instance= [superallocWithZone:zone];

    });

    }return_instance;

    }

    dispatch_once(&once, ^{

    _instance= [superinit];

    });

    return_instance;

    }

    - (UIPresentationController*)presentationControllerForPresentedViewController:(UIViewController*)presented presentingViewController:(UIViewController*)presenting sourceViewController:(UIViewController*)source{

    FFPresentationController* presentController = [[FFPresentationControlleralloc]initWithPresentedViewController:presentedpresentingViewController:presenting];

    returnpresentController;

    }

    - (id)animationControllerForDismissedController:(UIViewController*)dismissed{

    FFAnimatedTransitioning* animated = [[FFAnimatedTransitioningalloc]init];

    animated.type=Dismiss;

    animated.duration=2;

    returnanimated;

    }

    - (id)animationControllerForPresentedController:(UIViewController*)presented presentingController:(UIViewController*)presenting sourceController:(UIViewController*)source{

    FFAnimatedTransitioning* animated = [[FFAnimatedTransitioningalloc]init];

    animated.type=Presented;

    animated.duration=2;

    returnanimated;

    }

    继而在实现创建一个类来实现动画效果UIViewControllerAnimatedTransitioning,在这个方法里实现

    - (void)animateTransition:(id)transitionContext

    - (NSTimeInterval)transitionDuration:(id)transitionContext

    还有个非常的重要的地方

    创建一个继承自UIPresentationController的类后

    要记得在

    - (void)presentationTransitionWillBegin

    加上

    [self.containerViewaddSubview:self.presentedView];

    然后

    - (void)dismissalTransitionDidEnd:(BOOL)completed

    [self.presentedViewremoveFromSuperview];

    上面都是自定义转场动画的前置条件

    现在开始分析页面,页面动画效果是由三部分构成,上半部分,中间部分,和下半部分

    Transition.png

    查看运动轨迹,可以发现上半圆是与上半部分一起运动的,所以这一块是Path描绘出来的

    直接上代码

    _UpPath= [UIBezierPathbezierPath];

    [_UpPathmoveToPoint:LeftStartPoint];

    [_UpPathaddLineToPoint:LeftendPoint];

    UIBezierPath* UpCirclePath = [UIBezierPathbezierPath];

    [UpCirclePathaddArcWithCenter:CircleCenterradius:RADIUSstartAngle:0endAngle:M_PIclockwise:NO];

    [_UpPathappendPath:UpCirclePath];

    [_UpPathmoveToPoint:RightStartPoint];

    [_UpPathaddLineToPoint:RightEndPoint];

    下半部分类似,只是描绘点不一样,中间部分这是由三角形构成

    [_ToPathmoveToPoint:CGPointMake(RADIUS*2*cos(M_PI/6) -RectLength,0)];

    [_ToPathaddLineToPoint:CGPointMake(RADIUS*2*cos(M_PI/6) -RectLength,RectLength)];

    [_ToPathaddLineToPoint:CGPointMake(RectLength,RectLength/2)];

    [_ToPathclosePath];

    _ToPath.lineWidth=3;

    closePath方法会将曲线连接起来,形成闭合

    好啦,现在基础图形已经有了,要开始做动画效果了

    上半部分的向上移动只需要设置position,y就可以啦,使用 CABasicAnimation

    CABasicAnimation* UpAnimation = [CABasicAnimationanimationWithKeyPath:@"position.y"];

    UpAnimation.fromValue= [NSNumbernumberWithFloat:self.UpLayer.position.y];

    UpAnimation.toValue= [NSNumbernumberWithFloat:-self.UpLayer.position.y];

    UpAnimation.removedOnCompletion=NO;

    UpAnimation.repeatCount=1;

    UpAnimation.duration=self.duration;

    UpAnimation.autoreverses=NO;

    UpAnimation.fillMode=kCAFillModeForwards;

    效果如下:

    Up,gif

    向下的实现和上半部分差不多,只是值不一样

    CABasicAnimation* DownAnimation = [CABasicAnimationanimationWithKeyPath:@"position.y"];

    DownAnimation.toValue= [NSNumbernumberWithFloat:self.DownLayer.position.y+self.DownLayer.bounds.size.height];

    DownAnimation.fromValue= [NSNumbernumberWithFloat:self.DownLayer.position.y];

    DownAnimation.removedOnCompletion=NO;

    DownAnimation.repeatCount=1;

    DownAnimation.duration=self.duration;

    DownAnimation.autoreverses=NO;

    DownAnimation.fillMode=kCAFillModeForwards;

    中间部分的旋转,需要设置ShapeLayer的Frame,否则会绕着圆心旋转,设置了Frame之后可以改变锚点(anchorPoint)的值,会影响旋转的轴,这个可以随意发挥想象让它按照想要的方向去转

    CABasicAnimation* MiddleRotateAnimation = [CABasicAnimationanimationWithKeyPath:@"transform.rotation.z"];

    MiddleRotateAnimation.fromValue= [NSNumbernumberWithFloat:0];

    MiddleRotateAnimation.toValue= [NSNumbernumberWithFloat:-M_PI_2];

    MiddleRotateAnimation.duration=self.duration/2;

    MiddleRotateAnimation.repeatCount=1;

    MiddleRotateAnimation.removedOnCompletion=NO;

    MiddleRotateAnimation.fillMode=kCAFillModeForwards;

    MiddleRotateAnimation.autoreverses=NO;

    由于向上旋转,三角形会发生假上移现象

    rotate.gif

    所以需要添加一个下移的动画啦

    CABasicAnimation* MiddleDownAnimation = [CABasicAnimationanimationWithKeyPath:@"position.y"];

    MiddleDownAnimation.fromValue= [NSNumbernumberWithFloat:_MiddleLayer.position.y];

    MiddleDownAnimation.toValue= [NSNumbernumberWithFloat:_MiddleLayer.position.y+RectLength/2];

    MiddleDownAnimation.duration=self.duration/2;

    MiddleDownAnimation.repeatCount=1;

    MiddleDownAnimation.removedOnCompletion=NO;

    MiddleDownAnimation.fillMode=kCAFillModeForwards;

    MiddleDownAnimation.autoreverses=NO;

    创建一个动画组,组合旋转和下移的动画效果

    CAAnimationGroup*MiddleAnimationGroup = [CAAnimationGroupanimation];

    MiddleAnimationGroup.animations=@[MiddleRotateAnimation];

    MiddleAnimationGroup.duration=self.duration/2;

    MiddleAnimationGroup.repeatCount=MAXFLOAT;

    MiddleAnimationGroup.removedOnCompletion=NO;

    MiddleAnimationGroup.fillMode=kCAFillModeForwards;

    MiddleAnimationGroup.autoreverses=NO;

    上移就没有啦

    rotate.gif

    最后在这些动画做完之后,整个view还有一个淡化的效果,这个只需要给

    其中一个动画 设置 CAAnimationDelegate

    delegate = self;

    并实现 

    - (void)animationDidStop:(CAAnimation*)anim finished:(BOOL)flag
    {

    [UIViewanimateWithDuration:1animations:^{

    self.AnimationView.alpha=0;

    }completion:^(BOOLfinished) {

    [self.contextcompleteTransition:YES];

    [self.AnimationViewremoveFromSuperview];

    }];

    }

    一定要记住,在结束动画之后要 调用

    [self.contextcompleteTransition:YES];

    否则页面会卡住,不会再跳转了。

    Dismiss回来的动画相差不多,在方向上进行改变就行

    完整项目地址,使用的话只需要设置代理的时候设置为

    ViewController.transitionDelegate = [FFTransitionDelegate shareInstance];

    就能使用这个效果啦,大家喜欢的可以点一下star

    相关文章

      网友评论

        本文标题:iOS自定义转场动画

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