在有些情况下,系统自带的导航的push动画无法满足我们APP的设计需求,我们需要自定义VC的转场动画,下面是我参照别人博客,写的一个一个自定义转场动画.
(一) push
这里有一个push的自定义动画:
-(void)viewDidAppear:(BOOL)animated{
[super viewDidAppear:animated];
self.navigationController.delegate = self;
}
-(void)viewWillDisappear:(BOOL)animated{
[super viewWillDisappear:animated];
if (self.navigationController.delegate == self) {
self.navigationController.delegate = nil;
}
}
- (id)navigationController:(UINavigationController *)navigationController
animationControllerForOperation:(UINavigationControllerOperation)operation
fromViewController:(UIViewController *)fromVC
toViewController:(UIViewController *)toVC {
if (fromVC == self && [toVC isKindOfClass:[SecondViewController class]]) {
return [[FirstTransition alloc] init];
}
else {
return nil;
}
}
这里需要实现导航的代理,实现导航的代理方法.其中,
FirstTransition
是自己定义的一个动画效果,具体代码如下:
- (NSTimeInterval)transitionDuration:(id)transitionContext {
return 0.5;
}
- (void)animateTransition:(id)transitionContext {
FirstViewController *fromViewController = (FirstViewController*)[transitionContext viewControllerForKey:UITransitionContextFromViewControllerKey];
SecondViewController *toViewController = (SecondViewController*)[transitionContext viewControllerForKey:UITransitionContextToViewControllerKey];
UIView *containerView = [transitionContext containerView];
NSTimeInterval duration = [self transitionDuration:transitionContext];
//设置初始view的状态
NSLog(@"frame = %@",NSStringFromCGRect([transitionContext finalFrameForViewController:toViewController]));
toViewController.view.frame = CGRectMake(0, 667, 375, 667);
[containerView addSubview:toViewController.view];
[UIView animateWithDuration:duration animations:^{
toViewController.view.frame = CGRectMake(0, 0, 375, 667);
fromViewController.view.frame = CGRectMake(0, -667, 375, 667);
}completion:^(BOOL finished) {
[transitionContext completeTransition:!transitionContext.transitionWasCancelled];
}];
}
其中,
UIView *containerView = [transitionContext containerView];
类似动画的画布,这里可以处理我们需要设置的一些坐标类等参数.这里我做的是一个向上推出的动画效果.
(二) pop
同样的,先上代码:
- (void)viewDidAppear:(BOOL)animated {
[super viewDidAppear:animated];
self.navigationController.delegate = self;
}
- (void)viewWillDisappear:(BOOL)animated {
[super viewWillDisappear:animated];
if (self.navigationController.delegate == self) {
self.navigationController.delegate = nil;
}
}
-(id)navigationController:(UINavigationController *)navigationController animationControllerForOperation:(UINavigationControllerOperation)operation fromViewController:(UIViewController *)fromVC toViewController:(UIViewController *)toVC{
if (fromVC == self && [toVC isKindOfClass:[FirstViewController class]]) {
return [[SecondTransition alloc] init];
}
return nil;
}
-(id)navigationController:(UINavigationController *)navigationController interactionControllerForAnimationController:(id)animationController{
if ([animationController isKindOfClass:[SecondTransition class]]) {
return self.interactivePopTransition;
}
return nil;
}
-(void)handlePopRecognizer:(UIScreenEdgePanGestureRecognizer*)recognizer{
//计算用户拖动距离
CGFloat progress = [recognizer translationInView:self.view].x / (self.view.bounds.size.width * 1.0);
progress = MIN(1.0, MAX(0.0, progress));
if (recognizer.state == UIGestureRecognizerStateBegan) {
self.interactivePopTransition = [[UIPercentDrivenInteractiveTransition alloc] init];
[self.navigationController popViewControllerAnimated:YES];
}
else if(recognizer.state == UIGestureRecognizerStateChanged){
[self.interactivePopTransition updateInteractiveTransition:progress];
}
else if(recognizer.state == UIGestureRecognizerStateEnded || recognizer.state == UIGestureRecognizerStateCancelled){
if (progress > 0.5) {
[self.interactivePopTransition finishInteractiveTransition];
}else{
[self.interactivePopTransition cancelInteractiveTransition];
}
self.interactivePopTransition = nil;
}
}
这里的 self.interactivePopTransition的是UIPercentDrivenInteractiveTransition的实例,关于UIPercentDrivenInteractiveTransition,这里有篇详细介绍:
https://onevcat.com/2013/10/vc-transition-in-ios7/
这样可以根据手势来控制动画的进行程度,因为这里我写的是与pop相反的动画效果.
SecondTransition
里面的代码如下:
-(NSTimeInterval)transitionDuration:(id)transitionContext{
return 0.3;
}
-(void)animateTransition:(id)transitionContext{
// 获取两个互相切换的VC
SecondViewController *fromViewController = (SecondViewController*)[transitionContext viewControllerForKey:UITransitionContextFromViewControllerKey];
FirstViewController *toViewController = (FirstViewController*)[transitionContext viewControllerForKey:UITransitionContextToViewControllerKey];
// 获得画布及动画时间
UIView *containerView = [transitionContext containerView];
NSTimeInterval duration = [self transitionDuration:transitionContext];
//设置初始view的状态
[containerView insertSubview:toViewController.view belowSubview:fromViewController.view];
[UIView animateWithDuration:duration animations:^{
fromViewController.view.alpha = 1.0;
toViewController.view.frame = CGRectMake(0, 0, 375, 667);
fromViewController.view.frame = CGRectMake(0, 667, 375, 667);
} completion:^(BOOL finished) {
[transitionContext completeTransition:!transitionContext.transitionWasCancelled];
}];
}
对应的手势为:
UIScreenEdgePanGestureRecognizer *popRegognizer = [[UIScreenEdgePanGestureRecognizer alloc] initWithTarget:self action:@selector(handlePopRecognizer:)];
popRegognizer.edges = UIRectEdgeLeft;
[self.view addGestureRecognizer:popRegognizer];
以上代码均来自他人博客,只有动画是我自己写到的,只为自己查询方便,见谅.