先上效果圖:

細(xì)心的小伙伴會(huì)發(fā)現(xiàn)躏鱼,現(xiàn)在 網(wǎng)易云音樂(lè)的廣告頁(yè) 以及 微信相冊(cè)中點(diǎn)擊查看評(píng)論 都用了該轉(zhuǎn)場(chǎng)動(dòng)畫(huà)。作為一名 iOS 程序員,本能的想去實(shí)現(xiàn)它稍途。
說(shuō)明:本篇博文參考了 onevcat 的 WWDC 2013 Session筆記 以及 GitHub 上的開(kāi)源項(xiàng)目劫瞳。不打算先理論了倘潜,直接拿 demo 項(xiàng)目開(kāi)擼。
項(xiàng)目結(jié)構(gòu)
很顯然志于,有兩個(gè) ViewController涮因,在本例中分別是 MainViewController(下文簡(jiǎn)稱(chēng) mainVC) 和 ForwardViewController(簡(jiǎn)稱(chēng) forwardVC)。
首先伺绽,我們讓 mainVC 聲明 UIViewControllerTransitioningDelegate 協(xié)議养泡,并實(shí)現(xiàn) - (id <UIViewControllerAnimatedTransitioning>)animationControllerForPresentedController:(UIViewController *)presented presentingController:(UIViewController *)presenting sourceController:(UIViewController *)source;
方法。
該方法需要你返回一個(gè)自定義的動(dòng)畫(huà)奈应,該動(dòng)畫(huà)類(lèi)型為 NSObject 澜掩,并需要實(shí)現(xiàn) UIViewControllerAnimatedTransitioning 協(xié)議。
因此杖挣,接下來(lái)我們需要實(shí)現(xiàn)這樣一個(gè)實(shí)現(xiàn) UIViewControllerAnimatedTransitioning 協(xié)議的 object输硝,不妨取名為 NeteaseTransitionAnimation。
實(shí)現(xiàn) NeteaseTransitionAnimation
在本例中程梦,我們著重看 UIViewControllerAnimatedTransitioning 協(xié)議中的兩個(gè)方法点把,一是 - (NSTimeInterval)transitionDuration:(nullable id <UIViewControllerContextTransitioning>)transitionContext;
,第二個(gè)是 - (void)animateTransition:(id <UIViewControllerContextTransitioning>)transitionContext
屿附。
第一個(gè)方法傳入動(dòng)畫(huà)的時(shí)間長(zhǎng)度郎逃,在這里我們?cè)O(shè)置為 0.8 秒,我們主要在第二個(gè)方法中設(shè)定具體的動(dòng)畫(huà)效果挺份。
第二個(gè)方法中有一個(gè)很重要的 UIViewControllerContextTransitioning 類(lèi)型的上下文對(duì)象 transitionContext褒翰,通過(guò)該對(duì)象我們可以獲得切出以及切入的 VC 從而設(shè)置動(dòng)畫(huà)的具體參數(shù)等。不多說(shuō),接下來(lái)直接上具體實(shí)現(xiàn)步驟及相應(yīng)代碼优训。
獲得切出和切入的 ViewController
UIViewController *fromVC = [transitionContext viewControllerForKey:UITransitionContextFromViewControllerKey];
UIViewController *toVC = [transitionContext viewControllerForKey:UITransitionContextToViewControllerKey];
獲得 containerView 并將待切入的 view 加入其中
UIView *containerView = [transitionContext containerView];
[containerView addSubview:toVC.view];
有人問(wèn)朵你,containerView 是用來(lái)干嘛的。官方定義: * The view that acts as the superview for the views involved in the transition. * 揣非。并且抡医,它會(huì)自動(dòng)的將當(dāng)前所在的 viewController 的 view 加入其中。
使用 CATransform3D 實(shí)現(xiàn)動(dòng)畫(huà)過(guò)程
這步應(yīng)該算是本篇中最核心的一步早敬。關(guān)于涉及到的動(dòng)畫(huà)知識(shí)忌傻,建議先看iOS 核心動(dòng)畫(huà)高級(jí)技巧中的 3D 變換這一章,在本篇博文中就不具體談了搞监。
代碼:
CATransform3D transform = CATransform3DIdentity;
transform.m34 = -0.002; // 設(shè)置透視效果水孩,一般設(shè)為 -0.002
[containerView.layer setSublayerTransform:transform]; // 將動(dòng)畫(huà)影響到父視圖下的所有子視圖
CGRect initialFrame = [transitionContext initialFrameForViewController:fromVC];
toVC.view.frame = initialFrame; // 給 toVC 設(shè)置初始 frame
讓我們重新看一下開(kāi)頭的效果圖,可以將整個(gè)動(dòng)畫(huà)過(guò)程分成 3 個(gè)階段琐驴。(假設(shè)我們將一個(gè)周期的總時(shí)間設(shè)為 t俘种,并規(guī)定逆時(shí)針轉(zhuǎn)動(dòng)為正,順時(shí)針轉(zhuǎn)動(dòng)為負(fù)绝淡,逆順指針均從視角的正上往正下看)
0 階段
fromVC 初始在原位宙刘,而 toVC 初始化在 pi / 2 的位置。見(jiàn)圖:
具體代碼:
toVC.view.layer.transform = CATransform3DMakeRotation(M_PI_2, 0.0, 1.0, 0.0);
0 ~ t / 2 階段
fromVC 順時(shí)針從 0 度轉(zhuǎn)到 - pi / 2 的位置够委,toVC 在 pi / 2 位置保持不動(dòng)荐类。(這時(shí)在視覺(jué)上二者重合)
t / 2 ~ t 階段
toVC 從初始的 pi / 2 位置順時(shí)針轉(zhuǎn)到 0 位置。
0 ~ pi 階段的具體代碼:
[UIView animateKeyframesWithDuration:duration delay:0.0 options:0 animations:^{
[UIView addKeyframeWithRelativeStartTime:0.0
relativeDuration:0.5
animations:^{
fromVC.view.layer.transform = CATransform3DMakeRotation(- M_PI_2, 0.0, 1.0, 0.0);
}];
[UIView addKeyframeWithRelativeStartTime:0.5
relativeDuration:0.5
animations:^{
toVC.view.layer.transform = CATransform3DMakeRotation(0.0, 0.0, 1.0, 0.0);
}];
} completion:^(BOOL finished) {
[transitionContext completeTransition:![transitionContext transitionWasCancelled]];
}];
值得提一下 [transitionContext completeTransition:![transitionContext transitionWasCancelled]];
茁帽,如果沒(méi)有取消動(dòng)畫(huà)的話(huà)玉罐,即為 [transitionContext completeTransition: YES]。在該方法中潘拨,* UIKit will ensure the final state is consistent and remove the fromView from the container. * 吊输,即,在我們這里铁追,該方法將會(huì)移除 fromVC.view 季蚂。
結(jié)尾
該動(dòng)畫(huà)源碼已上傳 GitHub,鏈接戳此琅束。有問(wèn)題可以提 issue 或者直接在本博文下方的評(píng)論框中進(jìn)行評(píng)論扭屁。
其實(shí)該動(dòng)畫(huà)并不難,建議對(duì)著源碼多比較涩禀,并按 option + 函數(shù)名 查看官方定義料滥,會(huì)很有收獲的。
參考鏈接也不另給了艾船,基本都是 Apple 官方的文檔葵腹,沒(méi)有什么資料比官方文檔更有說(shuō)服力了高每。
聯(lián)系我
- 微博:@CaiYue_
- 簡(jiǎn)書(shū):蔡越
- 郵箱:yuecai.nju@gmail.com