先写一些通用部分
实现协议
在要添加自定义效果的视图控制器中实现代理协议UINavigationControllerDelegate
- (void)viewDidAppear:(BOOL)animated
{
[super viewDidAppear:animated];
self.navigationController.delegate = self;
}
实现代理方法
#pragma mark -UINavigationControllerDelegate
- (id<UIViewControllerAnimatedTransitioning>)navigationController:(UINavigationController *)navigationController animationControllerForOperation:(UINavigationControllerOperation)operation fromViewController:(UIViewController *)fromVC toViewController:(UIViewController *)toVC
{
if (operation == UINavigationControllerOperationPush) {
//返回我们自定义的效果
return [[PushTransition alloc]init];
}
else if (operation == UINavigationControllerOperationPop){
return [[PopTransition alloc]init];
}
//返回nil则使用默认的动画效果
return nil;
}
注:PushTransition、PopTransition为具体效果的实现
PushTransition的实现
这种效果的实现类需要实现UIViewControllerAnimatedTransitioning
协议
通用代码部分
//.h
#import <Foundation/Foundation.h>
#import <UIKit/UIKit.h>
@interface PushTransition : NSObject<UIViewControllerAnimatedTransitioning>
@end
//.m
#import "PushTransition.h"
@interface PushTransition ()
@end
@implementation PushTransition
// 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:(nullable id <UIViewControllerContextTransitioning>)transitionContext
{
//返回动画的执行时间
return 1.0f;
}
// This method can only be a nop if the transition is interactive and not a percentDriven interactive transition.
- (void)animateTransition:(id <UIViewControllerContextTransitioning>)transitionContext
{
self.transitionContext = transitionContext;
UIViewController *fromVC = [transitionContext viewControllerForKey:UITransitionContextFromViewControllerKey];
UIViewController *toVC = [transitionContext viewControllerForKey:UITransitionContextToViewControllerKey];
//不添加的话,屏幕什么都没有
UIView *containerView = [transitionContext containerView];
[containerView addSubview:fromVC.view];
[containerView addSubview:toVC.view];
//注意注意一定要注意这里。我们就是在这里添加我们所需要的动画效果。将动画效果的代码放在这里就行了。重要的事情要说好几遍
//如果取消了就设置为NO,反之,设置为YES。如果添加了动画,这句代码在动画结束之后再调用
[transitionContext completeTransition:![transitionContext transitionWasCancelled]];
}
实例程序一
实现了一个简单的扇形动画
//.m
#import "PushTransition.h"
@interface PushTransition ()
@property(nonatomic,strong) id<UIViewControllerContextTransitioning>transitionContext;
@end
@implementation PushTransition
// 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:(nullable id <UIViewControllerContextTransitioning>)transitionContext
{
return 1.0f;
}
// This method can only be a nop if the transition is interactive and not a percentDriven interactive transition.
- (void)animateTransition:(id <UIViewControllerContextTransitioning>)transitionContext
{
self.transitionContext = transitionContext;
UIViewController *fromVC = [transitionContext viewControllerForKey:UITransitionContextFromViewControllerKey];
UIViewController *toVC = [transitionContext viewControllerForKey:UITransitionContextToViewControllerKey];
//不添加的话,屏幕什么都没有
UIView *containerView = [transitionContext containerView];
[containerView addSubview:fromVC.view];
[containerView addSubview:toVC.view];
CGRect originRect = CGRectMake(0, 0, 50, 50);
UIBezierPath *maskStartPath = [UIBezierPath bezierPathWithOvalInRect:originRect];
UIBezierPath *maskEndPath = [UIBezierPath bezierPathWithOvalInRect:CGRectInset(originRect, -2000, -2000)];
//创建一个CAShapeLayer来负责展示圆形遮盖
CAShapeLayer *maskLayer = [CAShapeLayer layer];
// maskLayer.path = maskEndPath.CGPath;//将他的path指定为最终的path,来避免在动画完成后回弹
toVC.view.layer.mask = maskLayer;
CABasicAnimation *maskAnimation = [CABasicAnimation animationWithKeyPath:@"path"];
maskAnimation.fromValue = (id)maskStartPath.CGPath;
maskAnimation.toValue = (id)maskEndPath.CGPath;
maskAnimation.duration = [self transitionDuration:transitionContext];
maskAnimation.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut];
maskAnimation.fillMode = kCAFillModeForwards;
maskAnimation.removedOnCompletion = NO;
maskAnimation.delegate = self;
[maskLayer addAnimation:maskAnimation forKey:@"Path"];
}
- (void)animationDidStop:(CAAnimation *)anim finished:(BOOL)flag
{
NSLog(@"搞定结束");
[self.transitionContext completeTransition:![self.transitionContext transitionWasCancelled]];
//去除mask
[self.transitionContext viewControllerForKey:UITransitionContextFromViewControllerKey].view.layer.mask = nil;
[self.transitionContext viewControllerForKey:UITransitionContextToViewControllerKey].view.layer.mask = nil;
}
@end
实例程序二
实现从下方弹出的效果
NSTimeInterval duration = [self transitionDuration:transitionContext];
CGRect screenBounds = [[UIScreen mainScreen]bounds];
CGRect finalFrame = [transitionContext finalFrameForViewController:toVC];
toVC.view.frame = CGRectOffset(finalFrame, 0, screenBounds.size.height);
[UIView animateWithDuration:duration delay:0.0 usingSpringWithDamping:0.6 initialSpringVelocity:0.0 options:UIViewAnimationOptionCurveLinear animations:^{
toVC.view.frame = finalFrame;
} completion:^(BOOL finished) {
[transitionContext completeTransition:![transitionContext transitionWasCancelled]];
}];
网友评论