整體結(jié)構(gòu)##
封裝一個(gè)基本轉(zhuǎn)場動(dòng)畫的公共父類LZBBaseTransition.h,用于實(shí)現(xiàn)一些基本共同的操作 以及封裝block回調(diào),子類繼承LZBBaseTransition,重寫- (void)animateTransition:(id)transitionContext實(shí)現(xiàn)動(dòng)畫效果
LZBPageTransition.h 翻頁效果
LZBBubbleTransition.h 氣泡效果
LZBQQPhoneTransition.h 模擬QQ電話
LZBCustomModalTransition.h 自定義模態(tài)動(dòng)畫
LZBPresentDismissTransition.h 模擬系統(tǒng)的模態(tài)動(dòng)畫
LZBPushPopTransition.h 模擬系統(tǒng)的導(dǎo)航切換動(dòng)畫
這些可以直接分塊使用留储,耦合性不高翼抠,代碼包也不大
下載地址:各種轉(zhuǎn)場動(dòng)畫github下載鏈接
![自定義轉(zhuǎn)場動(dòng)畫.gif](https://upload-images.jianshu.io/upload_images/1886288-bc5c802a68de9f61.gif?imageMogr2/auto-orient/strip)
基本原理分析##
我們都應(yīng)該了解一個(gè)基本的知識(shí)是為什么我們的push/pop以及模態(tài)動(dòng)畫能實(shí)現(xiàn)系統(tǒng)的轉(zhuǎn)場視圖切換?
原因:與轉(zhuǎn)場代理有關(guān)获讳。
模態(tài)切換視圖與控制器的transitioningDelegate有關(guān)
導(dǎo)航切換與navigationController.delegate 有光
所以我們可以改變代理對(duì)象阴颖,并且重寫轉(zhuǎn)場的協(xié)議方法就可以實(shí)現(xiàn)自定義轉(zhuǎn)場動(dòng)畫
以下這三個(gè)協(xié)議很重要,我是重寫協(xié)議方法丐膝,轉(zhuǎn)換為block回調(diào)(個(gè)人習(xí)慣而已)
UIViewControllerAnimatedTransitioning //轉(zhuǎn)場動(dòng)畫協(xié)議
UIViewControllerTransitioningDelegate //轉(zhuǎn)場代理協(xié)議
UINavigationControllerDelegate //導(dǎo)航代理協(xié)議
一般的實(shí)現(xiàn)步驟####
第一步:重寫方法
- (void)animateTransition:(id <UIViewControllerContextTransitioning>)transitionContext;
第二步:通過轉(zhuǎn)場上下文拿到容器containerView
UIView *containerView = [transitionContext containerView];
第三步:拿到源控制器的View(A ->B,A是源控制器)量愧,拿到目的控制器(B是目的控制器)的View,并增加到容器containerView中,注意順序(一定是目的控制器的View在頂層)帅矗,并都要設(shè)置frame
- (UIView *)fromView:(id<UIViewControllerContextTransitioning>)transitionContext
{
UIView *fromView = nil;
//源控制器
UIViewController *fromVC = [transitionContext viewControllerForKey:UITransitionContextFromViewControllerKey];
if([transitionContext respondsToSelector:@selector(viewForKey:)])
{
fromView = [transitionContext viewForKey:UITransitionContextFromViewKey];
}
else
fromView = fromVC.view;
//初始位置的frame
fromView.frame = [transitionContext initialFrameForViewController:fromVC];
return fromView;
}
第四步:設(shè)置轉(zhuǎn)場動(dòng)畫
功能實(shí)現(xiàn)詳解析####
功能之高仿QQ電話切換效果#####
方法使用
twoQQPhoneViewController *twoVC = [[twoQQPhoneViewController alloc]init];
twoVC.modalPresentationStyle = UIModalPresentationCustom;
__weak typeof(self) weakSelf = self;
self.QQPhoneTransition = [[LZBQQPhoneTransition alloc]initWithPresent:^(UIViewController *presented, UIViewController *presenting, UIViewController *sourceVC, LZBBaseTransition *transition) {
LZBQQPhoneTransition *modalQQ = (LZBQQPhoneTransition*)transition;
modalQQ.targetView = weakSelf.presentButton;
} Dismiss:^(UIViewController *dismissVC, LZBBaseTransition *transition) {
}];
twoVC.transitioningDelegate = self.QQPhoneTransition;
[self presentViewController:twoVC animated:YES completion:nil];
由此可以見偎肃,自定義轉(zhuǎn)場動(dòng)畫,只是改變了控制器的轉(zhuǎn)場代理浑此,其實(shí)我只是把操作都封裝在了LZBQQPhoneTransition里面累颂,所以看起來簡單。現(xiàn)在就來看看LZBQQPhoneTransition這里面都在干什么凛俱。
第一步:LZBQQPhoneTransition 設(shè)置參數(shù)的初始化值
-(instancetype)initWithPresent:(LZBBaseTransitionPresent)presentCallBack Dismiss:(LZBBaseTransitionDismiss)dismissCallBack
{
if(self = [super initWithPresent:presentCallBack Dismiss:dismissCallBack])
{
self.scale = 3.0;
}
return self;
}
第二步:調(diào)用轉(zhuǎn)場動(dòng)畫的代理方法
- (void)animateTransition:(id<UIViewControllerContextTransitioning>)transitionContext
{
UIView *containerView = [transitionContext containerView];
if(containerView == nil) return;
self.transitionContext = transitionContext;
if(self.transitionType == kLZBBaseTransitionStyle_Present)
{
[self animationPresentTrasition:transitionContext WithContainerView:containerView];
}
else
{
[self animationDismissTrasition:transitionContext WithContainerView:containerView];
}
}
第三步:核心是過渡的動(dòng)畫紊馏,所以第三步才是關(guān)鍵哦
present 過程是動(dòng)畫組 + 形狀層的CABasicAnimation做成的,對(duì)于想了解動(dòng)畫的朋友有幫助哦
首先是畫動(dòng)畫路徑
//畫移動(dòng)曲線
CGPoint startPoint = self.targetView.center;
CGPoint endPoint = toView.center;
CGPoint controlPoint = CGPointMake(self.targetView.center.x, [UIScreen mainScreen].bounds.size.height * 0.5);
UIBezierPath *animationPath = [[UIBezierPath alloc]init];
[animationPath moveToPoint:startPoint];
[animationPath addQuadCurveToPoint:endPoint controlPoint:controlPoint];
然后在移動(dòng)過程中還需要放大朱监,所以有增加transform動(dòng)畫
//增加動(dòng)畫
CAAnimationGroup *group = [self groupAnimationWithBezierPath:animationPath durationTime:1.0 transform:CATransform3DMakeScale(self.scale, self.scale, 1)];
group.removedOnCompletion = NO;
group.fillMode = kCAFillModeForwards;
//用于后面找到這組動(dòng)畫
[group setValue:@"onePresentGroup" forKey:@"groupAnimation"];
[self.targetView.layer addAnimation:group forKey:@"keyAniamition"];
第一個(gè)動(dòng)畫組完成之后暖哨,才是過渡切換視圖動(dòng)畫(監(jiān)聽使用動(dòng)畫的代理方法-animationDidStop:(CAAnimation *)anim finished:(BOOL)flag)完成轉(zhuǎn)場動(dòng)畫
轉(zhuǎn)場動(dòng)畫
//用曲線畫兩個(gè)圓 -開始圓 + 結(jié)束圓
//求出半徑
CGFloat radius = sqrtf(containerView.frame.size.height *containerView.frame.size.height + containerView.frame.size.width *containerView.frame.size.width)*0.5;
//根據(jù)半徑畫 - 結(jié)束圓
UIBezierPath *endCircle = [UIBezierPath bezierPathWithArcCenter:containerView.center radius:radius startAngle:0 endAngle:2*M_PI clockwise:YES];
//QQPhone動(dòng)畫開始圓
UIBezierPath *startCicle = [UIBezierPath bezierPathWithOvalInRect:CGRectMake(([UIScreen mainScreen].bounds.size.width - self.targetView.frame.size.width * self.scale)*0.5, ([UIScreen mainScreen].bounds.size.height - self.targetView.frame.size.height * self.scale)*0.5 , self.targetView.frame.size.width*self.scale, self.targetView.frame.size.height*self.scale)];
//創(chuàng)建動(dòng)畫的形狀層
CAShapeLayer *maskLayer = [CAShapeLayer layer];
maskLayer.path = endCircle.CGPath;
toVC.view.layer.mask = maskLayer;
//創(chuàng)建過度路徑動(dòng)畫
CABasicAnimation *laryerAnimation = [CABasicAnimation animationWithKeyPath:@"path"];
laryerAnimation.fromValue =(__bridge id )startCicle.CGPath;
laryerAnimation.toValue =(__bridge id )endCircle.CGPath;
laryerAnimation.duration = 1.0;
laryerAnimation.delegate = self;
[maskLayer addAnimation:laryerAnimation forKey:@"path"];
self.targetView.hidden = YES;
toVC.view.alpha = 1.0;
以上只是實(shí)現(xiàn)的核心思想,具體實(shí)現(xiàn)可以看看源代碼下載地址各種轉(zhuǎn)場動(dòng)畫github下載鏈接
最后贈(zèng)言###
如果覺得文章對(duì)您有幫助篇裁,不要忘記star哦!??,star 是對(duì)程序猿最大的鼓勵(lì)达布!
參考鏈接:標(biāo)哥技術(shù)