UIViewController 的转场效果

当viewController通过push 或 present 进行转场时, 系统自带的动画是从右侧push进来一个新的viewControler (或从下面present 一个新的ViewController),  接下来我们要做的就是要自定义系统的这个动画效果.

原理: 比如当viewController  调用 dismiss 后, 系统会检查当前 vc 是否实现<UIViewControllerTransitioningDelegate> 协议, 该协议会返回 自定义 的转场动画

例: 通过pan手势, dismiss 当前viewController

1. 在调用dimiss的 VC 中实现 <UIViewControllerTransitioningDelegate> 协议

#import "SecondViewController.h"
#import "CustomInteractiveTransition.h"
#import "CustomDissmissAnimation.h" @interface SecondViewController () <UIViewControllerTransitioningDelegate> @property (nonatomic, strong) CustomInteractiveTransition *interactiveAnimator;
@property (nonatomic, strong) CustomDissmissAnimation *dismissAnimator; @end @implementation SecondViewController - (instancetype)init {
if (self = [super init]) {
self.transitioningDelegate = self;
}
return self;
} - (void)viewDidLoad {
[super viewDidLoad]; self.view.backgroundColor = [UIColor cyanColor]; UIButton *button = [UIButton buttonWithType:UIButtonTypeSystem];
[button setTitle:@"dismiss" forState:UIControlStateNormal];
button.frame = CGRectMake(, , , );
[button addTarget:self action:@selector(btnClick:) forControlEvents:UIControlEventTouchUpInside];
[self.view addSubview:button]; self.interactiveAnimator = [[CustomInteractiveTransition alloc] initWithViewController:self]; self.dismissAnimator = [[CustomDissmissAnimation alloc] init]; UIPanGestureRecognizer *panGestureRecognizer =[[UIPanGestureRecognizer alloc] initWithTarget:self.interactiveAnimator action:@selector(panGestureAction:)];
[self.view addGestureRecognizer:panGestureRecognizer]; [self.transitionCoordinator notifyWhenInteractionEndsUsingBlock:^(id<UIViewControllerTransitionCoordinatorContext> _Nonnull context) { }];
} - (void)viewWillAppear:(BOOL)animated {
[super viewWillAppear:animated]; [self.transitionCoordinator animateAlongsideTransition:^(id<UIViewControllerTransitionCoordinatorContext> _Nonnull context) {
UIView *view = [context viewForKey:UITransitionContextFromViewKey];
view.transform = CGAffineTransformMakeScale(0.7, 0.7); } completion:^(id<UIViewControllerTransitionCoordinatorContext> _Nonnull context) {
// UIView *view = [context viewForKey:UITransitionContextFromViewKey];
// view.transform = CGAffineTransformIdentity;
}];
}

- (void)viewWillDisappear:(BOOL)animated {
[super viewWillDisappear:animated]; [self.transitionCoordinator animateAlongsideTransition:^(id<UIViewControllerTransitionCoordinatorContext> _Nonnull context) {
UIView *view = [context viewForKey:UITransitionContextToViewKey];
view.transform = CGAffineTransformMakeScale(, ); } completion:^(id<UIViewControllerTransitionCoordinatorContext> _Nonnull context) {
// UIView *view = [context viewForKey:UITransitionContextToViewKey];
// view.transform = CGAffineTransformIdentity;
}];
} - (void)dealloc
{
self.interactiveAnimator = nil;
self.dismissAnimator = nil;
} - (void)btnClick:(UIButton *)sender {
[self dismissViewControllerAnimated:YES completion:nil];
} #pragma mark - UIViewControllerTransitioningDelegate
// return 动画对象,该动画对象符合 UIViewControllerAnimatedTransitioning 协议,负责显示 present 动画。
- (id<UIViewControllerAnimatedTransitioning>)animationControllerForPresentedController:(UIViewController *)presented presentingController:(UIViewController *)presenting sourceController:(UIViewController *)source {
return nil;
}
// return 动画对象,负责显示 dismiss 动画。
- (id<UIViewControllerAnimatedTransitioning>)animationControllerForDismissedController:(UIViewController *)dismissed {
return self.dismissAnimator;
}
// return 交互式动画对象,该动画符合 UIViewControllerInteractiveTransitioning 协议,采用触摸手势或手势识别器作为动画的驱动,显示 present 动画。
- (id<UIViewControllerInteractiveTransitioning>)interactionControllerForPresentation:(id<UIViewControllerAnimatedTransitioning>)animator {
return nil;
}
// return 交互式动画,显示 dismiss 动画
- (id<UIViewControllerInteractiveTransitioning>)interactionControllerForDismissal:(id<UIViewControllerAnimatedTransitioning>)animator {
// 如果直接返回 interactive 会与系统的 dismiss 动画有冲突,导致点击 button 无法 dismiss 界面。
// 同时如果返回 interactiveAnimator,那么 animationControllerForDismissedController: 则必须实现
return self.interactiveAnimator.isInteractive? self.interactiveAnimator: nil;
// return self.interactiveAnimator;
} // return UIPresentationController,系统已经提供了各个演示样式。
//- (nullable UIPresentationController *)presentationControllerForPresentedViewController:(UIViewController *)presented presentingViewController:(UIViewController *)presenting sourceViewController:(UIViewController *)source NS_AVAILABLE_IOS(8_0); @end

2. 实现一个动画对象, 实现 <UIViewControllerAnimatedTransitioning>协议

- (NSTimeInterval)transitionDuration:(id<UIViewControllerContextTransitioning>)transitionContext {
return 0.35f;
} - (void)animateTransition:(id<UIViewControllerContextTransitioning>)transitionContext {
UIViewController *srcVC = [transitionContext viewControllerForKey:UITransitionContextToViewControllerKey]; UIViewController *secondVC = [transitionContext viewControllerForKey:UITransitionContextFromViewControllerKey]; UIView *containerView = [transitionContext containerView]; [containerView addSubview:srcVC.view]; [containerView addSubview:secondVC.view]; [UIView animateWithDuration:[self transitionDuration:transitionContext] animations:^{
secondVC.view.frame = CGRectMake(, [UIScreen mainScreen].bounds.size.height, secondVC.view.bounds.size.width, secondVC.view.bounds.size.height);
} completion:^(BOOL finished) {
[transitionContext completeTransition:!transitionContext.transitionWasCancelled];
}];
}

3. 交互式动画效果, 需要实现<UIViewControllerInteractiveTransitioning>协议 ; 或者继承UIPercentDrivenInteractiveTransition 类

* 可选实现. 在本例中, 通过pan手势下滑跟随dismiss, 需要通过交互式动画来实现

#import "CustomInteractiveTransition.h"
@interface CustomInteractiveTransition : UIPercentDrivenInteractiveTransition @property (nonatomic, assign, readonly) BOOL isInteractive; - (instancetype)initWithViewController:(UIViewController *)viewController; - (void)panGestureAction:(UIPanGestureRecognizer *)gestureRecognizer; @end
//.m
@interface CustomInteractiveTransition () @property (nonatomic, weak) UIViewController *viewController; @property (nonatomic, assign) CGFloat startScale; @property (nonatomic, assign, readwrite) BOOL isInteractive; @end @implementation CustomInteractiveTransition - (instancetype)initWithViewController:(UIViewController *)viewController {
if (self = [super init]) {
_isInteractive = NO;
_viewController = viewController;
}
return self;
} - (void)panGestureAction:(UIPanGestureRecognizer *)recognizer {
CGFloat progress = [recognizer translationInView:self.viewController.view].y / (self.viewController.view.bounds.size.height * 1.0);
progress = MIN(1.0, MAX(0.0, progress)); self.isInteractive = YES; if (recognizer.state == UIGestureRecognizerStateBegan) { [self.viewController dismissViewControllerAnimated:YES completion:^{ }];
}
else if (recognizer.state == UIGestureRecognizerStateChanged) {
[self updateInteractiveTransition:progress];
}
else if (recognizer.state == UIGestureRecognizerStateEnded || recognizer.state == UIGestureRecognizerStateCancelled) {
if (progress > 0.5) {
[self finishInteractiveTransition];
}
else {
[self cancelInteractiveTransition];
} self.isInteractive = NO;
}
} @end
在 iOS中,可以取消一个过渡。这意味着,第二个视图的 -viewWillApear 被调用,但 -viewDidApear不一定被调用。
如果代码写的假定 -viewDidAppear 总是在 -viewWillAppear 之后执行则需要重新考虑逻辑实现。
这种情况下UIViewControllerTransitionCoordinator 就有用了。在交互式过渡结束的时候,会在 block 中收到通知。

参考:

present:   https://www.jianshu.com/p/aed8a3a15c82

push/pop: https://www.jianshu.com/p/28b9523d70a9

Transition 过渡/转场动画(一)的更多相关文章

  1. 【CSS3】transition过渡和animation动画

    转自:http://blog.csdn.net/XIAOZHUXMEN/article/details/52003135 写在前面的话: 最近写css动画发现把tansition和animation弄 ...

  2. 自己总结的CSS3中transform变换、transition过渡、animation动画的基本用法

    <!DOCTYPE html> <html lang="en"> <head> <meta charset="utf-8&quo ...

  3. iOS 动画学习之视图控制器转场动画

    一.概述 1.系统会创建一个转场相关的上下文对象,传递到动画执行器的animateTransition:和transitionDuration:方法,同样,也会传递到交互Controller的star ...

  4. 转场动画CALayer (Transition)

    1.将对应UI控件的层调用以下接口即可 1.1 .h文件 // // 文 件 名:CALayer+Transition.h // // 版权所有:Copyright © 2018年 leLight. ...

  5. 基于 React 实现一个 Transition 过渡动画组件

    过渡动画使 UI 更富有表现力并且易于使用.如何使用 React 快速的实现一个 Transition 过渡动画组件? 基本实现 实现一个基础的 CSS 过渡动画组件,通过切换 CSS 样式实现简单的 ...

  6. iOS:核心动画之转场动画CATransition

    转场动画——CATransition CATransition是CAAnimation的子类,用于做转场动画,能够为层提供移出屏幕和移入屏幕的动画效果.iOS比Mac OS X的转场动画效果少一点 U ...

  7. iOS 转场动画探究(一)

    什么是转场动画: 转场动画说的直接点就是你常见的界面跳转的时候看到的动画效果,我们比较常见的就是控制器之间的Push和Pop,还有Present和Dismiss的时候设置一下系统给我们的modalTr ...

  8. iOS 转场动画探究(二)

    这篇文章是接着第一篇写的,要是有同行刚看到的话建议从前面第一篇看,这是第一篇的地址:iOS 转场动画探究(一) 接着上一篇写的内容: 上一篇iOS 转场动画探究(一)我们说到了转场要素的第四点,把那个 ...

  9. iOS转场动画封装

    写在前面 iOS在modal 或push等操作时有默认的转场动画,但有时候我们又需要特定的转场动画效果,从iOS7开始,苹果就提供了自定义转场的API,模态推送present和dismiss.导航控制 ...

随机推荐

  1. FastReport使用教程

    FastReport使用心得 一.准备 1.这次开发使用的是FastReport桌面版(FastReport.Net Version 201731.16 Demo) 2.引用类库FastReport. ...

  2. php abs函数怎么用?

    php abs函数怎么用? abs()函数的作用是返回一个数的绝对值.语法是abs(number),如果参数 number 是 float,则返回的类型也是 float,否则返回 integer(因为 ...

  3. Ubuntu下的图形化多线程下载器XDM

    目录 1.下载 2.安装 3.浏览器支持 使用Ubuntu下载东西经常过于缓慢,因此需要多进程下载器. 1.下载 下载链接:http://xdman.sourceforge.net/#download ...

  4. 设置div标签可以输入文字

    1.contenteditable 属性可以设置div标签为克输入标签,   2.input和textarea虽然是常用的输入标签,但是这两个标签不能设置最大高度和最小高度, 随意如果想随着输入的内容 ...

  5. HR面试总结

    求职面试HR最欣赏的自我介绍 2015-02-25 来源:www.cnrencai.com 浏览:391   明明很有能力的你,在面试中却不能发挥出色?来看看是不是自我介绍环节出了问题. 回答面试题目 ...

  6. c#模板化生成接口

    最近打算做这样一个事情,一个桌面系统项目既可以一体化部署,作为一个软件一个进程部署,也可以把业务服务化部署. 那一般意味着我们要完全写2套东西,一套是直接UI调用业务,一套是Ui调用RPC.这样比较多 ...

  7. PCA算法和实例

    PCA算法 算法步骤: 假设有m条n维数据. 1. 将原始数据按列组成n行m列矩阵X 2. 将X的每一行(代表一个属性字段)进行零均值化,即减去这一行的均值 3. 求出协方差矩阵C=1/mXXT 4. ...

  8. js中的对象类型的基本操作

    示例 /** * 对象属于一种复合数据类型,在对象中可以保存多个不同数据类型的属性 * 对象的分类: * 1.内建对象 * - 由ES标准定义的对象,在任何ES的实现中都可以使用,比如:Math, * ...

  9. 模板引擎( art-template)

    <!DOCTYPE html> <html lang="zh-CN"> <head> <meta charset="UTF-8& ...

  10. scp - 安全复制(远程文件复制程序)

    总览 SYNOPSIS scp -words [-pqrvBC1246 ] [-F ssh_config ] [-S program ] [-P port ] [-c cipher ] [-i ide ...