前言
以前一直在做产品,感觉技术已经大幅度落后时代了,这是实话,但是最近换了工作,比较闲一点了可以有自己的时间去实现一点自己感兴趣的东西。
正文
好吧,其实这一块的知识点可以追溯到2013年,IOS7刚刚推出来,只怪那时候也刚换工作,而且日复一日的重复体力劳动,完全失去了学习的方向。
闲话不多说,我们知道Push Pop 以及Present可以实现基本的页面跳转,但是由于IOS更多的工程师加入,我们也不再满足这简单的动画跳转,于是页面跳转的方式也变的多样化,我会从简单的ViewControl跳转讲起,然后再去探索哪个抽屉控件的实现,其实知识点是由一定的关联性的,不得不佩服,苹果在IOS7的时候对ViewControl做出的惊人改革。
我们可能了解,如果要实现页面跳转实现一些动画该怎么实现。没错
[self addChildViewController:toVC];
[fromVC willMoveToParentViewController:nil];
[self.view addSubview:toVC.view];
__weak id weakSelf = self;
[self transitionFromViewController:fromVC
toViewController:toVC duration:0.3
options:UIViewAnimationOptionTransitionCrossDissolve
animations:^{}
completion:^(BOOL finished) {
[fromVC.view removeFromSuperView];
[fromVC removeFromParentViewController];
[toVC didMoveToParentViewController:weakSelf];
}];
我们可以使用一些系统提供的封装过的,或者自己实现,但是这样做无疑是高耦合度的,所以苹果引入了一套新的东西,就是需要解耦开两个页面的跳转问题。
IOS7新增的API:
@protocol UIViewControllerTransitioningDelegate <NSObject>
我希望大家只要理解这个就可以,因为下面的一些协议或者方法,其实都是服务于这个产生的,他负责了页面跳转的对方开发,看看里面方法吧,非常简单:
- (id <UIViewControllerAnimatedTransitioning>)animationControllerForPresentedController:(UIViewController *)presented presentingController:(UIViewController *)presenting sourceController:(UIViewController *)source;
- (id <UIViewControllerAnimatedTransitioning>)animationControllerForDismissedController:(UIViewController *)dismissed;
- (id <UIViewControllerInteractiveTransitioning>)interactionControllerForPresentation:(id <UIViewControllerAnimatedTransitioning>)animator;
- (id <UIViewControllerInteractiveTransitioning>)interactionControllerForDismissal:(id <UIViewControllerAnimatedTransitioning>)animator;
- (UIPresentationController *)presentationControllerForPresentedViewController:(UIViewController *)presented presentingViewController:(UIViewController *)presenting sourceViewController:(UIViewController *)source NS_AVAILABLE_IOS(8_0);
当然最下面是IOS8新加的我们暂时不看,看前面4个就知道了啊,1,3负责POP ,2,4后面两个负责Dismiss,那么好,我们先看Pop,也就是1,3,看他们的返回
@protocol UIViewControllerInteractiveTransitioning <NSObject>
- (void)startInteractiveTransition:(id <UIViewControllerContextTransitioning>)transitionContext;
@optional
- (CGFloat)completionSpeed;
- (UIViewAnimationCurve)completionCurve;
@end
@protocol UIViewControllerAnimatedTransitioning <NSObject>
// This is used for percent driven interactive transitions, as well as for container controllers that have companion animations that might need to
// synchronize with the main animation.
- (NSTimeInterval)transitionDuration:(id <UIViewControllerContextTransitioning>)transitionContext;
// This method can only be a nop if the transition is interactive and not a percentDriven interactive transition.
- (void)animateTransition:(id <UIViewControllerContextTransitioning>)transitionContext;
@optional
// This is a convenience and if implemented will be invoked by the system when the transition context's completeTransition: method is invoked.
- (void)animationEnded:(BOOL) transitionCompleted;
@end
返回的就是这两个协议
他们一个负责交互,一个负责交互的动画,如果简单的讲,我们只要实现交互动画,就能替换掉那些系统的low的动画了,那么交互协议呢?有什么用,我们看到里面也十分简单,其实不然,他的作用还是主要服务于手势动画,我们后面会讲。
那就变的很简单了,我们只要实现这些交互动画,就能实现自定义的页面跳转了,so easy!!
为了封装性,我们将动画封装成一个类:PushAnimation
他需要继承的协议就是
UIViewControllerAnimatedTransitioning
然后实现的两个协议方法:
- (NSTimeInterval)transitionDuration:(id <UIViewControllerContextTransitioning>)transitionContext
{
return 10.8f;
}
- (void)animateTransition:(id <UIViewControllerContextTransitioning>)transitionContext
{
// 1. Get controllers from transition context
UIViewController *toVC = [transitionContext viewControllerForKey:UITransitionContextToViewControllerKey];
// 2. Set init frame for toVC
CGRect screenBounds = [[UIScreen mainScreen] bounds];
CGRect finalFrame = [transitionContext finalFrameForViewController:toVC];
toVC.view.frame = CGRectOffset(finalFrame, 0, - screenBounds.size.height);
// 3. Add toVC's view to containerView
UIView *containerView = [transitionContext containerView];
[containerView addSubview:toVC.view];
// 4. Do animate now
NSTimeInterval duration = [self transitionDuration:transitionContext];
[UIView animateWithDuration:duration
delay:0.0
usingSpringWithDamping:0.6
initialSpringVelocity:0.0
options:UIViewAnimationOptionCurveLinear
animations:^{
toVC.view.frame = finalFrame;
} completion:^(BOOL finished) {
// 5. Tell context that we completed.
[transitionContext completeTransition:YES];
}];
}
OK拉,这时候引出来了另一个东西
@protocol UIViewControllerContextTransitioning
这个是神马鬼!,看名字了交互的上下文,也就是我们能够从上下文中拿到我们需要的一些东西咯,看API
- (CGRect)initialFrameForViewController:(UIViewController *)vc;
- (CGRect)finalFrameForViewController:(UIViewController *)vc;
- (UIViewController *)viewControllerForKey:(NSString *)key;
- (UIView *)viewForKey:(NSString *)key;
- (UIView *)containerView;
里面的API众多,但是我只挑选了比较实用的几条,前面的两条其实从方法名就十分清楚,可以得到ViewController的初始化和最终展现的Frame,至于是FromViewController还是ToViewController,我们可以通过第三条API取到,Key目前就开放了两个
UIKIT_EXTERN NSString *const UITransitionContextFromViewControllerKey NS_AVAILABLE_IOS(7_0);
UIKIT_EXTERN NSString *const UITransitionContextToViewControllerKey NS_AVAILABLE_IOS(7_0);
至于以后会不会增加不得而知了,相信两个Key表达的意思再清楚不过了吧。
这样我们就拿到了一些我们需要实现交互动画的信息了,比如frame,比如位置啊神马的。
看吧是不是很简单,这样我们就实现了最简单的一个自动义转场动画了,然后再需要用的地方
- (void)viewDidLoad {
[super viewDidLoad];
UIButton * button = [UIButton buttonWithType:UIButtonTypeCustom];
button.frame = CGRectMake(50, 50, 100, 30);
button.backgroundColor = [UIColor redColor];
[button setTitle:@"push" forState:UIControlStateNormal];
[button addTarget:self action:@selector(pushNext) forControlEvents:UIControlEventTouchUpInside];
[self.view addSubview:button];
// Do any additional setup after loading the view, typically from a nib.
}
- (void)pushNext
{
NextViewController * next = [[NextViewController alloc] init];
next.transitioningDelegate = self;
[self presentViewController:next animated:YES completion:NULL];
}
- (id <UIViewControllerAnimatedTransitioning>)animationControllerForPresentedController:(UIViewController *)presented presentingController:(UIViewController *)presenting sourceController:(UIViewController *)source;
{
return [PushAnimation new];
}
简单吧!
那么另外的一个协议就是我们刚刚讲到的
UIViewControllerInteractiveTransitioning
他的作用就是手势转场了。
我们在下一篇再讲咯!