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萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章