Transition Animation

1、TransitionFromViewController

这种方法适合在childViewController之间切换

//翻页效果
// UIViewAnimationOptionTransitionCurlUp,
// UIViewAnimationOptionTransitionCurlDown
// 翻转效果
// UIViewAnimationOptionTransitionFlipFromLeft, 
// UIViewAnimationOptionTransitionFlipFromRight
// UIViewAnimationOptionTransitionFlipFromTop, 

UIViewAnimationOptionTransitionFlipFromDown
[self transitionFromViewController : self.childControllers[1]
                  toViewController : self.childControllers[2]
                          duration : 0.5
                           options : UIViewAnimationOptionTransitionFlipFromRight
                        animations : ^{
                                                  }
                        completion : ^(BOOL finished){
                                                            }];

2、Transition Animation

自定义转场动画一般需要两个对象

  • UIViewControllerTransitioningDelegate
    (指定UIViewControllerAnimatedTransitioning对象)
  • UIViewControllerAnimatedTransitioning(实现转场动画的所有细节)

FirstVC

- (void)goAction:(UIButton*)sender{
    
    SecondViewController *secondVC = [[SecondViewController alloc]init];
    secondVC.transitioningDelegate = self;
    secondVC.modalPresentationStyle = UIModalPresentationCustom;
    [self presentViewController:secondVC animated:YES completion:nil];
    
}

#pragma mark - UIViewControllerTransitionDelegate

- (id<UIViewControllerAnimatedTransitioning>)animationControllerForPresentedController:(UIViewController *)presented presentingController:(UIViewController *)presenting sourceController:(UIViewController *)source{
    AnimatorTransition *animatorTransition = [[AnimatorTransition alloc]init];
//    animatorTransition.animatorTransitionType = kAnimatorTransitionTypePresent;
    animatorTransition.animatorTransitionType = kAnimatorTransitionTypeBubble;
    animatorTransition.bubbleCenter = self.btn.center;
    return animatorTransition;  
}
- (id<UIViewControllerAnimatedTransitioning>)animationControllerForDismissedController:(UIViewController *)dismissed{
    
    AnimatorTransition *animatorTransition = [[AnimatorTransition alloc]init];
//    animatorTransition.animatorTransitionType = kAnimatorTransitionTypeDismiss;
    animatorTransition.animatorTransitionType = kAnimatorTransitionTypeBubbleBack;
    animatorTransition.bubbleCenter = self.btn.center;
    return animatorTransition;
}

AnimatorTransition

#import <UIKit/UIKit.h>
#import <Foundation/Foundation.h>

typedef NS_ENUM(NSInteger,AnimatorTransitionType) {
    
    kAnimatorTransitionTypePresent = 0,
    kAnimatorTransitionTypeDismiss,
    kAnimatorTransitionTypeBubble,
    kAnimatorTransitionTypeBubbleBack
    
};
@interface AnimatorTransition : NSObject<UIViewControllerAnimatedTransitioning>

//转场动画上下文
@property (nonatomic, weak) id<UIViewControllerContextTransitioning> transitionContext;

//转场动画过程中呈现出来的View
@property (nonatomic,retain) UIView *containerView;

//转场动画类型
@property (nonatomic,assign)AnimatorTransitionType animatorTransitionType;

@property (nonatomic,retain) UIViewController *from;
@property (nonatomic,retain) UIViewController *to;

@property (nonatomic,retain) UIView *fromView;
@property (nonatomic,retain) UIView *toView;


@property (nonatomic,assign) CGPoint bubbleCenter;
@end


@implementation AnimatorTransition
/**
 *  转场动画所需要的时间
 */
- (NSTimeInterval)transitionDuration:(id<UIViewControllerContextTransitioning>)transitionContext{
    return 1.0;
}
/**
 *  转场动画完成调用的方法
 */
- (void)animationEnded:(BOOL)transitionCompleted{
    
}
/**
 *  转场动画细节实现
 */
- (void)animateTransition:(id<UIViewControllerContextTransitioning>)transitionContext{
    
    //得到转场过程中的View
    _transitionContext = transitionContext;
    _containerView  = [transitionContext containerView];
    _containerView.backgroundColor = [UIColor whiteColor];
    
    //得到转场的两上VC
    _from = [transitionContext viewControllerForKey:UITransitionContextFromViewControllerKey];
    _to = [transitionContext viewControllerForKey:UITransitionContextToViewControllerKey];
    
    // 得到
    // iOS8之后才有
    if ([transitionContext respondsToSelector:@selector(viewForKey:)]) {
        
        _fromView = [transitionContext viewForKey:UITransitionContextFromViewKey];
          _toView = [transitionContext viewForKey:UITransitionContextToViewKey];
    } else {
        
        _fromView = _from.view;
          _toView = _to.view;
    }
    if (self.animatorTransitionType == kAnimatorTransitionTypePresent) {
        [self animatorPresent];
    }
    if (self.animatorTransitionType == kAnimatorTransitionTypeDismiss) {
        [self animatorDismiss];
    }
    if (self.animatorTransitionType == kAnimatorTransitionTypeBubble){
        [self animatorBubble];
    }
    if (self.animatorTransitionType == kAnimatorTransitionTypeBubbleBack) {
        [self animatorBubbleBack];
    }
}

下面是两种动画的实现过程,大致原理都相近,相比而言spring动画在效果上可能会更好一点。另外如果项目中有多种复杂的自定义页面的话最好就建基类进行继承

#pramgarm mark - bubble动画
- (void)animatorBubble{
    
    // 在toView的下边, 添加了一个bubbleView, 从最初的bubble的center位置开始, 通过scale动画呈现出来.
    // BubbleView与toView的背景色一致.
    UIView *bubbleView = [[UIView alloc] init];
    bubbleView.backgroundColor = self.toView.backgroundColor;
    CGSize toViewSize = self.toView.frame.size;
    CGFloat x = fmax(_bubbleCenter.x, toViewSize.width);
    CGFloat y = fmax(_bubbleCenter.y, toViewSize.height);
    CGFloat radius = sqrt(x * x + y * y);
    bubbleView.frame = CGRectMake(0, 0, radius * 2, radius * 2);
    bubbleView.layer.cornerRadius = CGRectGetHeight(bubbleView.frame) / 2;
    bubbleView.transform = CGAffineTransformMakeScale(0.001, 0.001);
    bubbleView.center = _bubbleCenter;
    [self.containerView addSubview:bubbleView];
    
    // toView要跟随bubbleView一起做动画
    self.toView.frame = [self.transitionContext finalFrameForViewController:self.to];
    self.toView.transform = CGAffineTransformMakeScale(0.001, 0.001);
    self.toView.center = _bubbleCenter;
    self.toView.alpha = 0.0;
    [self.containerView addSubview:self.toView];

    
    [UIView animateWithDuration:[self transitionDuration:self.transitionContext]
                     animations:^{
                         
        bubbleView.transform = CGAffineTransformIdentity;
        self.toView.transform = CGAffineTransformIdentity;
        self.toView.alpha = 1.0f;

                         
    } completion:^(BOOL finished) {
        [self.transitionContext completeTransition:![self.transitionContext transitionWasCancelled]];
    }];
   
    
    
}
- (void)animatorBubbleBack{
    
    self.toView.frame = [self.transitionContext finalFrameForViewController:self.to];
    [self.containerView insertSubview:self.toView belowSubview:self.fromView];

    
    // 与present bubble时的过程相反.
    UIView *bubbleView = [[UIView alloc] init];
    bubbleView.backgroundColor = self.fromView.backgroundColor;
    CGSize fromViewSize = self.fromView.frame.size;
    CGFloat x = fmax(_bubbleCenter.x, fromViewSize.width);
    CGFloat y = fmax(_bubbleCenter.y, fromViewSize.height);
    CGFloat radius = sqrt(x * x + y * y);
    bubbleView.frame = CGRectMake(0, 0, radius * 2, radius * 2);
    bubbleView.layer.cornerRadius = radius;
    bubbleView.layer.masksToBounds = YES;
//    bubbleView.transform = CGAffineTransformIdentity;
    bubbleView.center = _bubbleCenter;
    [self.containerView insertSubview:bubbleView belowSubview:self.fromView];
    
    
    [UIView animateWithDuration:[self transitionDuration:self.transitionContext]
                     animations:^{
        
        bubbleView.transform = CGAffineTransformMakeScale(0.001, 0.001);
        self.fromView.transform = CGAffineTransformMakeScale(0.001, 0.001);
        self.fromView.center = self.bubbleCenter;
                         
    } completion:^(BOOL finished) {
        [self.transitionContext completeTransition:![self.transitionContext transitionWasCancelled]];
        
    }];

    
}
#pragma mark - 简单的呈现动画
- (void)animatorPresent{
    
    //得到初始frame,fromView为全屏,toView为(0,0,0,0)
    self.fromView.frame = [self.transitionContext initialFrameForViewController:self.from];
    self.toView.frame = [self.transitionContext initialFrameForViewController:self.to];
    [self.containerView addSubview:self.toView];
    
    
    //从中间扩散
    self.toView.alpha = 0;
    self.toView.center = self.containerView.center;
    self.toView.transform = CGAffineTransformMakeScale(0.001, 0.001);
    
    [UIView animateWithDuration:[self transitionDuration:self.transitionContext]
                          delay:0
         usingSpringWithDamping:100// 弹簧效果,越小越明显
          initialSpringVelocity:3  //初始速度
                        options:UIViewAnimationOptionCurveLinear
                     animations:^{
                         self.toView.transform = CGAffineTransformIdentity;
                         self.toView.frame = [self.transitionContext finalFrameForViewController:self.to];
                         self.toView.alpha = 1;

                     } completion:^(BOOL finished) {
                         //这个方法代表告诉系统转都转场成功了
                         BOOL wasCancelled = [self.transitionContext transitionWasCancelled];
                         [self.transitionContext completeTransition:!wasCancelled];

                     }];
    
}
- (void)animatorDismiss{
   
    /**
     *  返回时toView,fromView的frame都是全屏
     */
    [self.containerView addSubview:self.fromView];
    //[self.containerView insertSubview:self.toView belowSubview:self.fromView];
    [UIView animateWithDuration:[self transitionDuration:self.transitionContext]
                          delay:0
         usingSpringWithDamping:100// 弹簧效果,越小越明显
          initialSpringVelocity:3 //初始速度
                        options:UIViewAnimationOptionCurveLinear
                     animations:^{
                         
                         self.fromView.transform = CGAffineTransformMakeScale(0.001, 0.001);
                         self.fromView.frame = CGRectZero;
                         self.fromView.center = self.containerView.center;
                     }
                     completion:^(BOOL finished) {
                         BOOL wasCancelled = [self.transitionContext transitionWasCancelled];
                         [self.transitionContext completeTransition:!wasCancelled];
                         [self.fromView removeFromSuperview];
                     }];


}

类似

  • UINavigationControllerDelegate
  • UITabBarControllerDelegate
self.navigationController.delegate = self;
[self.navigationController pushViewController:itemVC animated:YES];

代理方法

- (id <UIViewControllerAnimatedTransitioning>)navigationController:(UINavigationController *)navigationController
                                   animationControllerForOperation:(UINavigationControllerOperation)operation
                                                fromViewController:(UIViewController *)fromVC
                                                  toViewController:(UIViewController *)toVC;

- (nullable id <UIViewControllerInteractiveTransitioning>)navigationController:(UINavigationController *)navigationController
                          interactionControllerForAnimationController:(id <UIViewControllerAnimatedTransitioning>) animationController ;


            
- (id <UIViewControllerAnimatedTransitioning>)tabBarController:(UITabBarController *)tabBarController
            animationControllerForTransitionFromViewController:(UIViewController *)fromVC
                                              toViewController:(UIViewController *)toVC;
         
- (id <UIViewControllerInteractiveTransitioning>)tabBarController:(UITabBarController *)tabBarController
                      interactionControllerForAnimationController:(id <UIViewControllerAnimatedTransitioning>)animationController;

PS:

参考文档1提供了具体的Demo,参考文档2有详细的讲解。
时间有限不能深入学习,先就到这儿。
参考文档1
参考文档2

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 216,470评论 6 501
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,393评论 3 392
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 162,577评论 0 353
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,176评论 1 292
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,189评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,155评论 1 299
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,041评论 3 418
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,903评论 0 274
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,319评论 1 310
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,539评论 2 332
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,703评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,417评论 5 343
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,013评论 3 325
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,664评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,818评论 1 269
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,711评论 2 368
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,601评论 2 353

推荐阅读更多精彩内容