iOS自定义转场动画

先看效果图:

iOS自定义转场动画_第1张图片
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];

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

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


iOS自定义转场动画_第2张图片
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;

效果如下:


iOS自定义转场动画_第3张图片
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;

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


iOS自定义转场动画_第4张图片
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;

上移就没有啦


iOS自定义转场动画_第5张图片
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自定义转场动画)