轉(zhuǎn)場動畫:
12.29
自己寫過一個轉(zhuǎn)場動畫以后,感覺這個轉(zhuǎn)場動畫設(shè)計的很好锦亦,邏輯清晰,自由度也比較大舔庶,而且實(shí)現(xiàn)起來也比較容易肚逸。
一朦促、present 動畫
問題:
1洒疚、為什么在+ animateTransition
方法中乏德,一定要自己調(diào)用
[containerview addSubview:toVc.view]
钝满。
這個有點(diǎn)想不明白悍引,不是應(yīng)該自己添加的嗎?帽氓?
我在第一次嘗試的時候,忘記把toVc.view 添加到上面去俩块,結(jié)果雖然最后調(diào)用了[transitionContext completeTransition:YES];
,但是還是transationView 還在視圖中黎休,造成界面不能夠再操作。
現(xiàn)在想想玉凯,自己添加其實(shí)是有了更多的自由度势腮,可以用來管理什么時候再把新的toVc.view 添加到容器上。
自定義轉(zhuǎn)場動畫的實(shí)現(xiàn):
1漫仆、在要實(shí)現(xiàn)自定義轉(zhuǎn)場動畫的viewController 的初始化方法里面里面設(shè)置轉(zhuǎn)場動畫的代理和style:
self.transitioningDelegate = self;
self.modalPresentationStyle = UIModalPresentationCustom;
2捎拯、實(shí)現(xiàn)轉(zhuǎn)場動畫的代理方法。 這里只實(shí)現(xiàn)了最基本的兩個方法盲厌,即present 和dismiss動畫署照。另外還有手勢操作和動畫被打斷時的的代理方法。
這兩個代理方法都返回一個遵守<UIViewControllerAnimatedTransitioning>協(xié)議的對象吗浩,我這里是 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>協(xié)議的類懂扼,我這里是 CircleTransitionAnimation類禁荸。
在這個類中實(shí)現(xiàn)相關(guān)協(xié)議方法來完成轉(zhuǎn)場動畫:
#pragma mark UIViewControllerTransitioning
//這個方法返回轉(zhuǎn)場動畫的持續(xù)時長
- (NSTimeInterval)transitionDuration:(nullable id <UIViewControllerContextTransitioning>)transitionContext;
{
return 0.5;
}
//這個方法是 轉(zhuǎn)場時要執(zhí)行的動畫,我把代碼分到兩個私有方法里面了
- (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];
//創(chuàng)建CAShapeLayer進(jìn)行遮蓋
CAShapeLayer *maskLayer = [CAShapeLayer layer];
maskLayer.fillColor = [UIColor greenColor].CGColor;
maskLayer.path = endCycle.CGPath;
fromVC.view.layer.mask = maskLayer;
//創(chuàng)建路徑動畫
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"];
}
這樣就完成了一個簡單的轉(zhuǎn)場動畫,最終的效果圖如下: