現(xiàn)在的app很少只有一個(gè)頁面的丽蝎,在不同頁面間的跳轉(zhuǎn)成為了iOS開發(fā)人員需要知道的技術(shù)點(diǎn)。UIKit 中已經(jīng)為我們實(shí)現(xiàn)了一些系統(tǒng)自帶的頁面跳轉(zhuǎn)方法霎桅,但是程序員這種充滿腦洞的特殊人群怎么能夠只滿足于那些不fashion的跳轉(zhuǎn)呢巾钉?因此本著您可將自己累死也要讓用戶酷炫(不爽瘫镇?)的態(tài)度沽一,我們還是很有必要去知道如何實(shí)現(xiàn)一個(gè)自定義的頁面跳轉(zhuǎn)的盖溺。
一, UINavigationController 和 present view controller
在學(xué)習(xí)自定義頁面跳轉(zhuǎn)之前铣缠,我們可以先了解一下UIKit已經(jīng)為我們實(shí)現(xiàn)的頁面跳轉(zhuǎn)方法烘嘱。當(dāng)然已經(jīng)清楚的同學(xué)可以往下看了。
首先我們需要明白的一點(diǎn)是蝗蛙,UINavigationController其實(shí)是一種 Container View Controller
Container view controllers are a way to combine the content from multiple view controllers into a single user interface. Container view controllers are most often used to facilitate navigation and to create new user interface types based on existing content. Examples of container view controllers in UIKit include UINavigationController, UITabBarController, and UISplitViewController, all of which facilitate navigation between different parts of your user interface.
從上面的定義我們可以明白以下三點(diǎn)
一蝇庭,Container view controller 是用來將多個(gè)view controller中的內(nèi)容結(jié)合到同一個(gè)用戶交互界面的。
二捡硅,Container view controller可以很方便的進(jìn)行頁面導(dǎo)航并且基于已有的內(nèi)容創(chuàng)建新的頁面交互類型哮内。
三,UINavigationController, UITabBarController, and UISplitViewController這些在UIKit中的類都屬于Container view controller壮韭。
接下來讓我們看看UINavigationViewController的一般用法
##創(chuàng)建 UINavigationViewController并設(shè)置root view controller
UIViewController *vc = [[UIViewController alloc] init];
UINavigationController *nav = [[UINavigationController alloc] initWithRootViewController:vc];
self.window.rootViewController = nav;
##通過push跳轉(zhuǎn)頁面
UIViewController *viewController = [[UIViewController alloc] init];
[self.navigationController pushViewController:viewController animated:YES];
##通過pop跳轉(zhuǎn)頁面
[self.navigationController popViewControllerAnimated:YES];
在這里我們大概應(yīng)該明白北发,navigation controller通過一個(gè)數(shù)組來維護(hù)加入的view controller纹因,并實(shí)現(xiàn)了棧的原理來push和pop已經(jīng)在數(shù)組中的view controller。
以下兩個(gè)實(shí)例方法屬于UIViewController鲫竞,通過以下兩個(gè)實(shí)例方法可以很方便的實(shí)現(xiàn)跳轉(zhuǎn)辐怕。
- (void)presentViewController:(UIViewController *)viewControllerToPresent
animated:(BOOL)flag
completion:(void (^)(void))completion;
- (void)dismissViewControllerAnimated:(BOOL)flag
completion:(void (^)(void))completion;
二逼蒙,A Custom Present Transition & A Custom Dismiss Transition
對(duì)于一個(gè)自定義的跳轉(zhuǎn)來說我們首先要明白跳轉(zhuǎn)都做了些什么从绘?
- 規(guī)范跳轉(zhuǎn)發(fā)生所需的時(shí)間和跳轉(zhuǎn)時(shí)所需的交互方法
- 提供具體的交互方法對(duì)象,也就是實(shí)現(xiàn)一個(gè)交互方法提供給系統(tǒng)跳轉(zhuǎn)時(shí)調(diào)用
清楚了以上兩點(diǎn)我們就比較好理解以下兩個(gè)我們需要實(shí)現(xiàn)的協(xié)議了
UIViewControllerTransitioningDelegate的定義
An object that implements the UIViewControllerTransitioningDelegate protocol vends the objects used to manage a fixed-length or interactive transition between view controllers. When you want to present a view controller using a custom modal presentation type, set its modalPresentationStyle property to UIModalPresentationCustom and assign an object that conforms to this protocol to its transitioningDelegate property. When you present that view controller, UIKit queries your transitioning delegate for the objects to use when animating the view controller into position.
UIViewControllerAnimatedTransitioning的定義
Adopt the UIViewControllerAnimatedTransitioning protocol in objects that implement the animations for a custom view controller transition. The methods in this protocol let you define an animator object, which creates the animations for transitioning a view controller on or off screen in a fixed amount of time. The animations you create using this protocol must not be interactive. To create interactive transitions, you must combine your animator object with another object that controls the timing of your animations.
以上的定義我就不再翻譯了是牢,相信通過或者沒通過四級(jí)考試的你都是可以看懂的僵井。??
** 從上面的關(guān)系圖我們可以明白不同模塊之間的關(guān)系,首先需要有一個(gè)UIViewController類去實(shí)現(xiàn)UIViewControllerTransitioningDelegate驳棱。UIViewControllerTransitioningDelegate會(huì)從Animation Controller獲得一個(gè)交互對(duì)象批什,Animation Controller通過實(shí)現(xiàn)UIViewControllerAnimatedTransitioning協(xié)議來提供交互,Transitioning Context對(duì)象實(shí)現(xiàn)UIViewContextTransitioning協(xié)議社搅,通過Transitioning Context我們可以獲得有關(guān)view controller的上下文信息驻债。**
好了,不寫代碼講解的程序員都是耍流氓形葬,讓我們開始耍流氓吧合呐!??
1, 實(shí)現(xiàn)一個(gè)animator object
#import <Foundation/Foundation.h>
//敲黑板1
@interface BouncePresentAnimationController : NSObject<UIViewControllerAnimatedTransitioning>
@end
#import "BouncePresentAnimationController.h"
@implementation BouncePresentAnimationController
//敲黑板2
-(NSTimeInterval) transitionDuration:(id<UIViewControllerContextTransitioning>)transitionContext {
return 1.0;
}
//敲黑板3
-(void) animateTransition:(id<UIViewControllerContextTransitioning>)transitionContext {
//敲黑板4
UIViewController *toViewController = [transitionContext viewControllerForKey:UITransitionContextToViewControllerKey];
CGRect finalFrame = [transitionContext finalFrameForViewController:toViewController];
//敲黑板5
UIViewController *fromViewController = [transitionContext viewControllerForKey:UITransitionContextFromViewControllerKey];
//敲黑板6
UIView *containerView = [transitionContext containerView];
CGRect screenBounds = [[UIScreen mainScreen] bounds];
toViewController.view.frame = CGRectOffset(finalFrame, 0, screenBounds.size.height);
[containerView addSubview:toViewController.view];
NSTimeInterval duration = [self transitionDuration:transitionContext];
//敲黑板7
[UIView animateWithDuration:duration delay:0.0 usingSpringWithDamping:0.6 initialSpringVelocity:0.0 options:UIViewAnimationOptionCurveLinear animations:^{
fromViewController.view.alpha = 0.5;
toViewController.view.frame = finalFrame;
} completion:^(BOOL finished){
fromViewController.view.alpha = 1.0;
[transitionContext completeTransition:YES];
}
];
}
@end
1, 創(chuàng)建一個(gè)實(shí)現(xiàn)動(dòng)畫的類繼承自NSObject并且實(shí)現(xiàn)UIViewControllerAnimatedTransitioning協(xié)議笙以。
2淌实,實(shí)現(xiàn)transitionDuration方法,這個(gè)方法UIKit會(huì)自動(dòng)調(diào)用這個(gè)方法來獲得跳轉(zhuǎn)動(dòng)畫所需的時(shí)間猖腕。我們?cè)诤竺鎸@式調(diào)用這個(gè)方法拆祈。
3, 實(shí)現(xiàn)animateTransition方法倘感,UIKit會(huì)掉用這個(gè)方法放坏,這個(gè)方法將告訴動(dòng)畫對(duì)象如何實(shí)現(xiàn)我們所需的動(dòng)畫效果。
4老玛, 通過transitionContext獲得toViewController,toViewController是我們將要顯示的視圖控制器淤年。
5,通過transitionContext獲得fromViewController逻炊,fromViewController是我們?cè)谶M(jìn)行跳轉(zhuǎn)前正在顯示的視圖控制器互亮。
6,通過transitionContext獲得containerView,containerView是進(jìn)行動(dòng)畫跳轉(zhuǎn)的容器余素。我們需要將toViewController.view加入這個(gè)containerView,這樣toViewController.view將被加入視圖結(jié)構(gòu)中豹休。我們才能在跳轉(zhuǎn)之后顯示這個(gè)view。
7桨吊,UIView的動(dòng)畫方法來實(shí)現(xiàn)跳轉(zhuǎn)動(dòng)畫威根。
上面這幅圖描述了在presentation和dismissal這兩個(gè)跳轉(zhuǎn)過程中頁面對(duì)應(yīng)的關(guān)系凤巨。有興趣的同學(xué)可以查看
2,實(shí)現(xiàn)UIViewControllerTransitioningDelegate
接下來我們需要在進(jìn)行頁面跳轉(zhuǎn)的view controller中實(shí)現(xiàn)UIViewControllerTransitionsingDelegate協(xié)議,并且將要跳轉(zhuǎn)顯示的toViewController.transitioningDelegate = self.
在這里我們需要實(shí)現(xiàn)一個(gè)UIViewControllerTransitioningDelegate方法洛搀。
-(id<UIViewControllerAnimatedTransitioning>) animationControllerForPresentedController:(UIViewController *)presented presentingController:(UIViewController *)presenting sourceController:(UIViewController *)source {
return _bouncePresentAnimationController;
}
在這里敢茁,UIKit在頁面跳轉(zhuǎn)的時(shí)候掉用以上的方法,我們?cè)谶@里返回一個(gè)我們已經(jīng)實(shí)現(xiàn)并且創(chuàng)建的動(dòng)畫對(duì)象留美,UIKit通過這個(gè)已經(jīng)實(shí)現(xiàn)的動(dòng)畫對(duì)象完成頁面跳轉(zhuǎn)過程中的動(dòng)畫效果彰檬。
3,如何實(shí)現(xiàn)頁面dismissal
其實(shí)頁面的消失也是一樣的道理,通過實(shí)現(xiàn)以上所提到的兩個(gè)協(xié)議我們就可以實(shí)現(xiàn)相關(guān)的動(dòng)畫效果了谎砾。有興趣的同學(xué)可以看Demo逢倍。
三,參考內(nèi)容
1,《iOS 7 By Tutorials》
2, UIViewControllerTransitioningDelegate
3, UIViewControllerAnimatedTransitioning
4, View Controller Programming Guide for iOS