什么也不說了饭庞,作為一名樂于分享技術(shù)的小開發(fā),直接先上個(gè)樣式最為直觀貼切轧膘,有需要的朋友可以直接拿過去用钞螟。
在這個(gè)demo中,核心為選用畫布CAShapeLayer谎碍,因?yàn)橐话愣际怯盟鼇硖幚硇螤钪惖膭?dòng)畫鳞滨,結(jié)合了貝塞爾曲線來控制路徑,然后使用CABasicAnimation核心動(dòng)畫來產(chǎn)生所有效果蟆淀。
首先封裝一個(gè)自定義的動(dòng)畫拯啦。
///動(dòng)畫自定義封裝
-(void)animationWithView:(UIView *)view{
//1.創(chuàng)建layer
CAShapeLayer *layer = [[CAShapeLayer alloc]init];
//2.創(chuàng)建貝塞爾路徑(參數(shù)為圓的外接矩形)
//間距
CGFloat margin = 20;
//半徑
CGFloat radius = 25;
//屏幕尺寸
CGFloat viewWidth = [UIScreen mainScreen].bounds.size.width;
//屏幕高度
CGFloat viewHeight = [UIScreen mainScreen].bounds.size.height;
//屏幕對(duì)角線
CGFloat endRadius =sqrt(viewHeight*viewHeight +viewWidth*viewWidth);
//起始路徑
CGRect startRect = CGRectMake(viewWidth-2*radius-margin, margin, radius*2, radius*2);
UIBezierPath *startPath = [UIBezierPath bezierPathWithOvalInRect:startRect];
//終止路徑
UIBezierPath *endPath = [UIBezierPath bezierPathWithOvalInRect:CGRectInset(startRect, -endRadius, -endRadius) ];
//3.設(shè)置貝塞爾屬性
//填充顏色
layer.fillColor = [UIColor redColor].CGColor;
//4.將貝塞爾作為layer的路徑
layer.path = startPath.CGPath;
//將layer作為父視圖的遮罩圖層.
view.layer.mask = layer;
//5.將path添加到視圖中
//[self.view.layer addSublayer:layer];
//使用核心動(dòng)畫實(shí)現(xiàn)
CABasicAnimation *animation = [CABasicAnimation animationWithKeyPath:@"path"];
//這個(gè)屬性是判斷是動(dòng)畫之前還是動(dòng)畫之后的。
if (self.isPresent) {
animation.fromValue = (__bridge id _Nullable)(startPath.CGPath);
animation.toValue = (__bridge id _Nullable)(endPath.CGPath);
}else{
animation.fromValue = (__bridge id _Nullable)(endPath.CGPath);
animation.toValue = (__bridge id _Nullable)(startPath.CGPath);
}
animation.delegate = self;
//設(shè)置動(dòng)畫屬性
animation.fillMode = kCAFillModeForwards;
animation.duration = 2;
animation.removedOnCompletion = NO;
//添加動(dòng)畫到圖層
[layer addAnimation:animation forKey:nil];
}
! 這里要注意這個(gè)mask的屬性熔任,設(shè)置之后就不需要再額外的add進(jìn)去褒链,它是一種用于遮罩視圖的效果,并且設(shè)置的顏色會(huì)失效
在這個(gè)動(dòng)畫中疑苔,有三個(gè)重要的屬性甫匹,號(hào)稱“轉(zhuǎn)場(chǎng)三劍客”。
UIViewControllerAnimatedTransitioning,主要負(fù)責(zé)轉(zhuǎn)場(chǎng)的動(dòng)畫時(shí)間和動(dòng)畫具體內(nèi)容惦费。
#pragma mark - UIViewControllerAnimatedTransitioning
///轉(zhuǎn)場(chǎng)動(dòng)畫時(shí)間
- (NSTimeInterval)transitionDuration:(nullable id <UIViewControllerContextTransitioning>)transitionContext{
return 2;
}
///轉(zhuǎn)場(chǎng)動(dòng)畫的內(nèi)容
- (void)animateTransition:(id <UIViewControllerContextTransitioning>)transitionContext{
//1.獲取上下文的容器視圖
UIView *containerView = transitionContext.containerView;
//2.獲取目標(biāo)視圖
UIView *fromView = [transitionContext viewForKey:UITransitionContextFromViewKey];
UIView *toView = [transitionContext viewForKey:UITransitionContextToViewKey];
//3.將目標(biāo)視圖添加到容器視圖
UIView *aniView = self.isPresent?toView:fromView;
[containerView addSubview:aniView];
//4.開始動(dòng)畫
[self animationWithView:aniView];
self.context = transitionContext;
}
CAAnimationDelegate兵迅,主要負(fù)責(zé)監(jiān)控動(dòng)畫開始和動(dòng)畫結(jié)束之后。
#pragma mark - CAAnimationDelegate
///動(dòng)畫開始
- (void)animationDidStart:(CAAnimation *)anim{
}
///每次動(dòng)畫結(jié)束調(diào)用
- (void)animationDidStop:(CAAnimation *)anim finished:(BOOL)flag{
//5.告訴上下文完成轉(zhuǎn)場(chǎng),否則上下文將會(huì)一直等待系統(tǒng)通知是否完成.
[self.context completeTransition:YES];
}
UIViewControllerTransitioningDelegate薪贫,主要負(fù)責(zé)告訴系統(tǒng)由哪個(gè)控制器提供轉(zhuǎn)場(chǎng)恍箭,哪個(gè)控制器來解除轉(zhuǎn)場(chǎng)。
#pragma mark - UIViewControllerTransitioningDelegate
///告訴由誰提供轉(zhuǎn)場(chǎng)
- (nullable id <UIViewControllerAnimatedTransitioning>)animationControllerForPresentedController:(UIViewController *)presented presentingController:(UIViewController *)presenting sourceController:(UIViewController *)source{
self.isPresent = YES;
return self;
}
///由誰解除轉(zhuǎn)場(chǎng)
- (nullable id <UIViewControllerAnimatedTransitioning>)animationControllerForDismissedController:(UIViewController *)dismissed{
self.isPresent = NO;
return self;
}
最后只需要在需要轉(zhuǎn)場(chǎng)的控制器中使用這個(gè)封裝的類即可
-(void)awakeFromNib{
[super awakeFromNib];
//1.設(shè)置跳轉(zhuǎn)樣式
self.modalPresentationStyle = UIModalPresentationCustom;
//2.設(shè)置代理
self.animation = [[JanCustomAnimation alloc]init];
self.transitioningDelegate = self.animation;
}
-(void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event{
[self dismissViewControllerAnimated:YES completion:nil];
}
需要注意的是設(shè)置樣式和代理瞧省,必須要優(yōu)先于viewdidload之前設(shè)置扯夭,因?yàn)檫@里涉及到控制器的生命周期的問題。
好了臀突,到這里就可以實(shí)現(xiàn)完整的自定義轉(zhuǎn)場(chǎng)的酷炫效果了勉抓。