ViewController转场动画的切换

关于转场动画的切换这方便一直想研究好久了,但是奈何都下不了决心,

http://blog.csdn.net/hmt20130412/article/details/39079905 这篇博客对于转场动画,我认为讲解得比较详细了

在iOS7中,苹果官方提供了几个关键性的API,我这边再次简单总结下

1.在我们做转场动画的时候,需要实现几个代理

A.动画控制器 (Animation Controllers) 遵从 UIViewControllerAnimatedTransitioning 协议,并且负责实际执行动画。
B.交互控制器 (Interaction Controllers) 通过遵从 UIViewControllerInteractiveTransitioning 协议来控制可交互式的转场《暂时先不做》。

 //我这边就直接上例子,定义一个动画继承自NSObject,实现代理UIViewControllerAnimatedTransitioning

#import <UIKit/UIKit.h>
typedef NS_ENUM(NSUInteger, AnimationType) {
    AnimationTypePush,
    AnimationTypePop,
};
@interface ChangeVCAnimationDele : NSObject<UIViewControllerAnimatedTransitioning>
@property (nonatomic,assign)AnimationType actionType; /**< 当前的动画是push还是pop*/
@property (nonatomic,assign)CGPoint center;/**< 消失,显示的中心点*/
@end
.h文件

#import "ChangeVCAnimationDele.h"

#define kAnimtionTime   0.5f
@interface ChangeVCAnimationDele ()
@property (nonatomic,strong)CAShapeLayer *maskLayer;
@property (nonatomic,strong)id<UIViewControllerContextTransitioning> transitionContext;
@property (nonatomic,weak)UIViewController *toVC;/**< 目标的VC*/
@property (nonatomic,weak)UIViewController *fromeVC; /**< 来源的VC*/
@end

@implementation ChangeVCAnimationDele

- (CAShapeLayer *)maskLayer {
    if (!_maskLayer) {
        _maskLayer = [[CAShapeLayer alloc] init];
    }
    return _maskLayer;
}
// 系统给出一个切换上下文,我们根据上下文环境返回这个切换所需要的花费时间
- (NSTimeInterval)transitionDuration:(id<UIViewControllerContextTransitioning>)transitionContext
{
   return kAnimtionTime;
}
// 完成容器转场动画的主要方法,我们对于切换时的UIView的设置和动画都在这个方法中完成
- (void)animateTransition:(id<UIViewControllerContextTransitioning>)transitionContext
{
    // 可以看做为destination ViewController 目标VC
    UIViewController *toViewController = [transitionContext viewControllerForKey:UITransitionContextToViewControllerKey];
    // 可以看做为source ViewController 
    UIViewController *fromViewController = [transitionContext viewControllerForKey:UITransitionContextFromViewControllerKey];  
    self.toVC = toViewController;
    self.fromeVC = fromViewController;
    self.transitionContext = transitionContext;
    if (AnimationTypePush == self.actionType) {
        [[transitionContext containerView] addSubview:toViewController.view];
        //防止闪动,需要提前处理动画结束的代码
        [NSTimer scheduledTimerWithTimeInterval:kAnimtionTime target:self selector:@selector(animationFinish:) userInfo:nil repeats:NO];
        [self show];
    }
    else {
        [[transitionContext containerView] addSubview:toViewController.view];
        [[transitionContext containerView] addSubview:fromViewController.view];
        [self dismiss];
    }
}
- (UIBezierPath *)bezierPathWithCenter:(CGPoint)center Radius:(CGFloat)radius {
    CGRect rect = CGRectMake(center.x - radius, center.y - radius, radius * 2, radius * 2);   
    return [UIBezierPath bezierPathWithRoundedRect:rect cornerRadius:radius];
}
#pragma mark -
#pragma mark - push
- (void)show {
    self.toVC.view.layer.mask = self.maskLayer;
    CABasicAnimation *pathAnimation = [CABasicAnimation animationWithKeyPath:@"path"];
    pathAnimation.fromValue = (__bridge id _Nullable)([self bezierPathWithCenter:self.center Radius:0].CGPath);
    pathAnimation.toValue = (__bridge id _Nullable)([self bezierPathWithCenter:self.center Radius:1000].CGPath);
    pathAnimation.duration = kAnimtionTime + 0.1;
//    pathAnimation.delegate = self;
    pathAnimation.removedOnCompletion = YES;
    [self.maskLayer addAnimation:pathAnimation forKey:@"show"];
}
#pragma mark -
#pragma mark - POP
- (void)dismiss {
    self.fromeVC.view.layer.mask = self.maskLayer;
    CABasicAnimation *pathAnimation = [CABasicAnimation animationWithKeyPath:@"path"];
    pathAnimation.fromValue = (__bridge id _Nullable)([self bezierPathWithCenter:_center Radius:1000].CGPath);
    pathAnimation.toValue = (__bridge id _Nullable)([self bezierPathWithCenter:_center Radius:0].CGPath);
    pathAnimation.duration = kAnimtionTime;
    pathAnimation.delegate = self;
    pathAnimation.removedOnCompletion = YES;
    [self.maskLayer addAnimation:pathAnimation forKey:@"dismiss"];
}
#pragma mark -
#pragma mark - 时间差,这个时候等动画完成了,中间需要一段时间才会执行代理,所以在push的时候需要提前处理操作,pop的时候需要延后处理,也就不要写计时器的
//pop的时候用到
- (void)animationDidStop:(CAAnimation *)anim finished:(BOOL)flag {
    if (flag) {
        [self.fromeVC.view removeFromSuperview];
        [self.transitionContext completeTransition:![self.transitionContext transitionWasCancelled]];
        self.toVC.view.layer.mask = nil;
    }   
}
//push的时候用到
- (void)animationFinish:(NSTimer *)timer {
    [self.transitionContext completeTransition:![self.transitionContext transitionWasCancelled]];
    self.toVC.view.layer.mask = nil;
}
@end

.m文件

到此时,基本动画已经完成了,最后就是在适当的时候插入动画了,来到push的VC

定义Navigation的代理《我这里只做了push的,present是一样的》

self.navigationController.delegate = self;

然后实现Navigation的代理

- (nullable id <UIViewControllerAnimatedTransitioning>)navigationController:(UINavigationController *)navigationController
                                            animationControllerForOperation:(UINavigationControllerOperation)operation
                                                         fromViewController:(UIViewController *)fromVC
                                                           toViewController:(UIViewController *)toVC {
    ChangeVCAnimationDele *animation = [[ChangeVCAnimationDele alloc]init];
    if (operation == UINavigationControllerOperationPush) {
        animation.actionType = AnimationTypePush;
    }else {
        animation.actionType = AnimationTypePop;
    }
    animation.center = self.customBtn.center;
    return animation;
}



发布了24 篇原创文章 · 获赞 1 · 访问量 4万+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章