想寫(xiě)簡(jiǎn)書(shū)很久了 一直沒(méi)時(shí)間 剛好項(xiàng)目做完了 現(xiàn)在來(lái)寫(xiě)篇簡(jiǎn)書(shū)吧 有很多不足之處希望大家多多指正批評(píng) 好 下面進(jìn)入正題
先上效果圖

這其實(shí)一個(gè)自定義push轉(zhuǎn)場(chǎng)動(dòng)畫(huà) 關(guān)于轉(zhuǎn)場(chǎng)動(dòng)畫(huà) 網(wǎng)上資料也很多 我現(xiàn)在貼出一篇我覺(jué)得寫(xiě)的很好的傳送門(mén)
分析動(dòng)畫(huà)
先要了解幾個(gè)概念 from 和 to 在代碼中經(jīng)常看到fromView和toView這類(lèi)的
1.fromView表示當(dāng)前視圖
2.toView表示要跳轉(zhuǎn)到的視圖
我們似乎可以看到是fromView旋轉(zhuǎn)了180° 其實(shí)不是這樣的 我是這樣處理的 先讓toView旋轉(zhuǎn)90° 然后此時(shí)fromView和頭view形成了一個(gè)+形狀 然后讓fromView旋轉(zhuǎn)90° 完成后 toView在旋轉(zhuǎn)90° 這樣就達(dá)到這個(gè)動(dòng)畫(huà) 當(dāng)然要注意旋轉(zhuǎn)的方向 這些在代碼中有詳細(xì)的注釋
定義轉(zhuǎn)場(chǎng)動(dòng)畫(huà)
首先定義一個(gè)遵循了UIViewControllerAnimatedTransitioning協(xié)議的類(lèi)。并且實(shí)現(xiàn)下面2個(gè)方法
- (NSTimeInterval)transitionDuration:(id<UIViewControllerContextTransitioning>)transitionContext ;
- (void)animateTransition:(id<UIViewControllerContextTransitioning>)transitionContext;
第一個(gè)方法是返回轉(zhuǎn)場(chǎng)的時(shí)間 第二個(gè)方法可以拿到轉(zhuǎn)場(chǎng)的上下文(上下文大家很明白吧)這個(gè)上下文里面就包含我們轉(zhuǎn)場(chǎng)需要的幾乎所有元素 包括fromView fromVC toView 等等 然后我們這里寫(xiě)我們的動(dòng)畫(huà)的邏輯就可以了
需要注意的一點(diǎn)就是 我們要把push 和 pop的動(dòng)畫(huà)分開(kāi) 所以我是這樣處理的
- (void)animateTransition:(id<UIViewControllerContextTransitioning>)transitionContext{
switch (self.type) {
case XWPushTransitionManagerPush:
[self doPushAnimation:transitionContext];
break;
case XWPushTransitionManagerPop:
[self doPopAnimation:transitionContext];
break;
default:
break;
}
}
最后貼出我動(dòng)畫(huà)的邏輯
- (void)ThrerDPushAnimation:(id<UIViewControllerContextTransitioning>)transitionContext{
// 將要轉(zhuǎn)場(chǎng)出來(lái)的view
UIView *toView =[transitionContext viewForKey:UITransitionContextToViewKey];
// 當(dāng)前的view
UIView *formView = [transitionContext viewForKey:UITransitionContextFromViewKey];
// 轉(zhuǎn)場(chǎng)的容器
UIView *contaniView = [transitionContext containerView];
contaniView.backgroundColor = [UIColor orangeColor];
CATransform3D percatier = CATransform3DIdentity;
// 設(shè)置m34 才有立體效果
percatier.m34 = -1.0/500;
//sublayerTranform
// 設(shè)置了父視圖的sublayerTranform 子視圖就都有這個(gè)transform
contaniView.layer.sublayerTransform = percatier;
[contaniView addSubview:toView];
[contaniView addSubview:formView];
//toview 默認(rèn)旋轉(zhuǎn)90
CATransform3D tranform1 = CATransform3DMakeRotation(-M_PI_2,0,1,0);
toView.layer.transform = tranform1;
// formview 的旋轉(zhuǎn)角度 也是90 當(dāng)formview旋轉(zhuǎn)到90度時(shí)候 移除formview 并且toview開(kāi)始動(dòng)畫(huà)
// 其實(shí)2個(gè)view 各自只旋轉(zhuǎn)了90度
CATransform3D tranform2 = CATransform3DMakeRotation(M_PI_2,0,1,0);
// 關(guān)鍵幀動(dòng)畫(huà)
// StartTime:動(dòng)畫(huà)開(kāi)始時(shí)間 取值0-1 指的是比例
// relativeDuration: 動(dòng)畫(huà)持續(xù)時(shí)間 取值0-1 指的是比例
[UIView animateKeyframesWithDuration:Time delay:0 options:UIViewKeyframeAnimationOptionCalculationModeLinear animations:^{
[UIView addKeyframeWithRelativeStartTime:0 relativeDuration:0.5 animations:^{
// 當(dāng)前的view 旋轉(zhuǎn)90度
formView.layer.transform = tranform2;
}];
// formview 動(dòng)畫(huà)完成后 toView 進(jìn)行動(dòng)畫(huà)
[UIView addKeyframeWithRelativeStartTime:0.5 relativeDuration:0.5 animations:^{
toView.layer.transform = CATransform3DIdentity;
}];
} completion:^(BOOL finished) {
// 動(dòng)畫(huà)完成之后 要告訴系統(tǒng) 轉(zhuǎn)場(chǎng)完成了 不然會(huì)出現(xiàn)bug
[transitionContext completeTransition:![transitionContext transitionWasCancelled]];
[formView removeFromSuperview];
}];
}
最后我們?cè)O(shè)置轉(zhuǎn)場(chǎng)的代理并且設(shè)置UINavigationControllerDelegate 在代理方法中返回我們定義的類(lèi)
#pragma mark -- 代理
- (id<UIViewControllerAnimatedTransitioning>)navigationController:(UINavigationController *)navigationController animationControllerForOperation:(UINavigationControllerOperation)operation fromViewController:(UIViewController *)fromVC toViewController:(UIViewController *)toVC{
//分pop和push兩種情況分別返回動(dòng)畫(huà)過(guò)渡代理相應(yīng)不同的動(dòng)畫(huà)操作
return [XWPushTransitionManager transitionWithType:operation == UINavigationControllerOperationPush ? XWPushTransitionManagerPush : XWPushTransitionManagerPop];
}
這里的UINavigationControllerOperation 這個(gè)枚舉就是來(lái)區(qū)分是push 還是 pop 我們只需要返回對(duì)應(yīng)的就可以拉
至此 我們的瞎搞push轉(zhuǎn)場(chǎng)就完成了 當(dāng)然你還得實(shí)現(xiàn)pop 這很簡(jiǎn)單 就動(dòng)畫(huà)的反向
手勢(shì)驅(qū)動(dòng)
最后我們?cè)诩由弦粋€(gè)效果 就是手勢(shì)驅(qū)動(dòng) 啥事手勢(shì)驅(qū)動(dòng)呢 系統(tǒng)默認(rèn)的 Push 和 Pop 動(dòng)畫(huà)都支持手勢(shì)驅(qū)動(dòng) 并且可以根據(jù)手勢(shì)移動(dòng)距離改變動(dòng)畫(huà)完成度 在iOS7以后 蘋(píng)果為我們提供了一個(gè)UIPercentDrivenInteractiveTransition這個(gè)類(lèi) 這個(gè)類(lèi)就是專門(mén)來(lái)做手勢(shì)驅(qū)動(dòng)的 廢話不多說(shuō) 下面直接開(kāi)搞
1.自定義一個(gè)類(lèi) 繼承于UIPercentDrivenInteractiveTransition 重寫(xiě)初始化方法 傳入一個(gè)控制器(一般是push出來(lái)的vc)
2.個(gè)該vc添加一個(gè)Pan手勢(shì)
3.在手勢(shì)的監(jiān)聽(tīng)方法里面計(jì)算手勢(shì)移動(dòng)的百分比 并使用 UIPercentDrivenInteractiveTransition 屬性的 updateInteractiveTransition 方法實(shí)時(shí)更新百分比
4.最后實(shí)現(xiàn)UINavigationControllerDelegate的一個(gè)代理方法
- (nullable id <UIViewControllerInteractiveTransitioning>)navigationController:(UINavigationController *)navigationController
interactionControllerForAnimationController:(id <UIViewControllerAnimatedTransitioning>) animationController NS_AVAILABLE_IOS(7_0){
// 這里要判斷 是pop返回 還是手勢(shì)返回
return self.manager.isInteractive?self.manager:nil;
}
至此 手勢(shì)驅(qū)動(dòng)也完成了啊 是不是很簡(jiǎn)單呢 其實(shí)不是 這里面水很深的 有很多細(xì)節(jié) 尤其加入了手勢(shì)驅(qū)動(dòng) pop動(dòng)畫(huà)尤其得注意了 具體的我在代碼里面注釋了 貼出demo地址demo地址
最后希望大家pi'p