这篇文章是接着第一篇写的,要是有同行刚看到的话建议从前面第一篇看,这是第一篇的地址:iOS 转场动画探究(一)

接着上一篇写的内容:

上一篇iOS 转场动画探究(一)我们说到了转场要素的第四点,把那个小实例解释完,这篇还有一点我们接着总结:

Demo的下载地址这里再发一次: 这里是Demo的下载地址

5、  转场协调器协议 UIViewControllerTransitionCoordinator

可以通过需要产生动画效果的视图控制器的transitionCoordinator属性来获取转场协调器,转场协调器只在转场动画的执行过程中存在。也正是因为有了UIViewControllerTransitionCoordinator ,我们才可在转场动画发生的同时并行执行其他的动画。比如像我们第三个小例子里面后面半透明背景动画,就是通过这个UIViewControllerTransitionCoordinator我们来做的,主要在 Modal 转场和交互转场取消时使用,其他时候很少用到,我们看看它里面的几个方法:

// Any animations specified will be run in the same animation context as the
// transition. If the animations are occurring in a view that is a not
// descendent of the containerView, then an ancestor view in which all of the
// animations are occuring should be specified. The completionBlock is invoked
// after the transition completes. (Note that this may not be after all the
// animations specified by to call complete if the duration is not inherited.)
// It is perfectly legitimate to only specify a completion block. This method
// returns YES if the animations are successfully queued to run. The completions
// may be run even if the animations are not. Note that for transitioning
// animators that are not implemented with UIView animations, the alongside
// animations will be run just after their animateTransition: method returns.
//
- (BOOL)animateAlongsideTransition:(void (^ __nullable)(id <UIViewControllerTransitionCoordinatorContext>context))animation
completion:(void (^ __nullable)(id <UIViewControllerTransitionCoordinatorContext>context))completion; // This alternative API is needed if the view is not a descendent of the container view AND you require this animation
// to be driven by a UIPercentDrivenInteractiveTransition interaction controller.
- (BOOL)animateAlongsideTransitionInView:(nullable UIView *)view
animation:(void (^ __nullable)(id <UIViewControllerTransitionCoordinatorContext>context))animation
completion:(void (^ __nullable)(id <UIViewControllerTransitionCoordinatorContext>context))completion; // When a transition changes from interactive to non-interactive then handler is
// invoked. The handler will typically then do something depending on whether or
// not the transition isCancelled. Note that only interactive transitions can
// be cancelled and all interactive transitions complete as non-interactive
// ones. In general, when a transition is cancelled the view controller that was
// appearing will receive a viewWillDisappear: call, and the view controller
// that was disappearing will receive a viewWillAppear: call. This handler is
// invoked BEFORE the "will" method calls are made.
- (void)notifyWhenInteractionEndsUsingBlock: (void (^)(id <UIViewControllerTransitionCoordinatorContext>context))handler NS_DEPRECATED_IOS(7_0, 10_0,"Use notifyWhenInteractionChangesUsingBlock"); // This method behavior is identical to the method above. On 10.0, however, the behavior has
// changed slightly to account for the fact that transitions can be interruptible. For interruptible transitions
// The block may be called multiple times. It is called each time the transition moves from an interactive to a
// non-interactive state and vice-versa. The block is now also retained until the transition has completed.
- (void)notifyWhenInteractionChangesUsingBlock: (void (^)(id <UIViewControllerTransitionCoordinatorContext>context))handler NS_AVAILABLE_IOS(10_0);

结合上面的英文注释看看这几个方法,在博客上看到关于这个协议的翻译,肯定翻译,再吧一些地方自己总结了一下,直接写出来,对照着上面的理解一下这个协议:

1、 你可以使用一个转场协调器对象执行一个与转场相关的任务,它将分离动画控制器正在做的事。在转场期间,动画控制器对象负责把视图控制器的内容呈现在屏幕上,但是可能也有一些其他的可视元素同样需要被展示。比如,一个显示控制器可能想执行显示或者使一些装饰视图消失从视图控制器内容里分离出的动画。这种情况下,可以使用转场协调器来执行这些动画。

2、转场协调器和动画控制器对象一块工作,确保任何额外动画被执行在同样的动画组中,就像转场动画一样。在一样的组拥有动画,意味着它们在同样的时间执行,并且可以响应一个动画控制器对象提出的任何时间改变。这些时间调整会自动发生,不需要写额外的代码在你的项目中。

3、使用转场协调器处理视图层次动画比在viewWillappear:方法中做出同样的改变,或者相同的方法在你的视图控制器中要好很多。你用这个协议中的方法所注册的block会确保执行一样的转场动画。更重要的是,转场协调器会提供重要的信息关于转场的状态,比如是否它会被取消,对于你的动画block而言,通过

UIViewControllerTransitionCoordinatorContext对象。

4、除了在转场期间执行注册动画,你可以调用notifyWhenInteractionChangesUsingBlock: 方法注册一个block来清理和用户交互的转场动画。清理非常重要,当用户取消转场交互时,当取消的时候,你需要返回一个原始的视图层次状态,就像之前转场存在的一样。

我们在协议的最上面会看到这样一句话:

翻译说明:一个采用UIViewControllerTransitionCoordinator协议的对象可以给控制器转场动画提供相关支持。一般情况下,你不需要采用这个协议在自己定义的类中。当presentation/dismissal一个视图控制器时,UIKit会自动创建一个转场协调器对象,并且给视图控制器的transitionCoordinator属性赋值(这一点在接下来的实例中,你会看的到的),这个转场协调器对象是短暂的,并且延续到转场动画的结束。

说第三个小例子之前我们还得熟悉一下这个:UIPresentationController,它提供了四个函数来定义present和dismiss动画开始前后的操作:

1、presentationTransitionWillBegin: present将要执行时

2、presentationTransitionDidEnd:    present执行结束后

3、dismissalTransitionWillBegin:    dismiss将要执行时

4、dismissalTransitionDidEnd:         dismiss执行结束后

这四个方法在我们的实例中有用到,我们在下面代码里面还会说。

EXAMPLE-THREE:

看上面效果图的第三个实例:

在第三个Demo中,也就是底部卡片的呈现形式中,我们把UIViewControllerTransitioningDelegate和UIViewControllerAnimatedTransitioning都写在了CustomPresentationController当中,这个CustomPresentationController就是集成与我们前面提到过的UIPresentationController,这个UIPresentationController前面提到的时候说的什么可以回忆一下,再在代码中去理解:

从初始化方法开始了解,说说我们需要注意的地方:

1、初始化

/**
初始化 @param presentedViewController presentedViewController 跳转到这个控制器
@param presentingViewController presentingViewController 由这个控制器开始跳转
@return return value description
*/
- (instancetype)initWithPresentedViewController:(UIViewController *)presentedViewController presentingViewController:(nullable UIViewController *)presentingViewController{ self =[super initWithPresentedViewController:presentedViewController presentingViewController:presentingViewController];
if (self) { // 自定义modalPresentationStyle
presentedViewController.modalPresentationStyle= UIModalPresentationCustom; }
return self;
}

这里主要的只有一点:presentedViewController.modalPresentationStyle= UIModalPresentationCustom

2、presentationTransitionWillBegin 这个方法

在这个方法里面背景图的动画就是在我们第五点强调的UIViewControllerTransitionCoordinator当中

/* present将要执行时 */
- (void)presentationTransitionWillBegin
{ // 设置presentationWrappingView和dimmingView的UI效果
UIView * presentedViewControllerView = [super presentedView];
presentedViewControllerView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight; {
//
UIView *presentationWrapperView = [[UIView alloc] initWithFrame:self.frameOfPresentedViewInContainerView];
presentationWrapperView.layer.shadowOpacity = 0.44f; //设置阴影的透明度(0~1之间,0表示完全透明)
presentationWrapperView.layer.shadowRadius = 13.f; //设置阴影的圆角 //设置阴影的偏移量,如果为正数,则代表为往右边偏移
presentationWrapperView.layer.shadowOffset = CGSizeMake(0, -6.f);
self.presentationWrappingView = presentationWrapperView; // 圆角View
UIView *presentationRoundedCornerView = [[UIView alloc] initWithFrame:UIEdgeInsetsInsetRect(presentationWrapperView.bounds, UIEdgeInsetsMake(0, 0, -CORNER_RADIUS, 0))]; // autoresizingMask 这个属性 自动调整与父视图之间的边界距离
presentationRoundedCornerView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
presentationRoundedCornerView.layer.cornerRadius = CORNER_RADIUS;
presentationRoundedCornerView.layer.masksToBounds = YES;
[presentationRoundedCornerView addSubview:presentedViewControllerView]; //*** presentedViewControllerView
presentedViewControllerView.frame = UIEdgeInsetsInsetRect(presentationRoundedCornerView.bounds, UIEdgeInsetsMake(0, 0, CORNER_RADIUS, 0)); // ******************
[presentationWrapperView addSubview:presentationRoundedCornerView]; } {
// 背景图
UIView *dimmingView = [[UIView alloc] initWithFrame:self.containerView.bounds];
dimmingView.backgroundColor = [UIColor blackColor];
dimmingView.opaque = NO;
dimmingView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
[dimmingView addGestureRecognizer:[[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(dimmingViewTapped:)]];
self.dimmingView = dimmingView;
[self.containerView addSubview:dimmingView]; id<UIViewControllerTransitionCoordinator> transitionCoordinator = self.presentingViewController.transitionCoordinator; self.dimmingView.alpha = 0.f;
[transitionCoordinator animateAlongsideTransition:^(id<UIViewControllerTransitionCoordinatorContext> context) { self.dimmingView.alpha = 0.5f; } completion:NULL];
}
}

剩下的UIViewControllerAnimatedTransitioning和UIViewControllerTransitioningDelegate里面的东西我们就不在重复去说。

我们多看几个例子:

EXAMPLE-FOUR

这个弹性POP的例子主要是根据 CGAffineTransform 这个属性来展开的,你要了解这个就比较好写了,主要的全都在代码注释里面,效果图就在下面:

这个例子我就强调下面这一个地方,下面这段代码:

 BOOL isPresent   = (toViewController.presentingViewController == fromViewController);

        UIView *tempView = nil;
if (isPresent) { tempView = [fromViewController.view snapshotViewAfterScreenUpdates:NO]; tempView.frame = fromViewController.view.frame;
fromViewController.view.hidden = YES;
[contextView addSubview:tempView];
[contextView addSubview:toViewController.view];
toViewController.view.frame = CGRectMake(0, contextView.frame.size.height, contextView.frame.size.width, 400); }else{ //参照present动画的逻辑,present成功后,containerView的最后一个子视图就是截图视图,我们将其取出准备动画
NSArray *subviewsArray = contextView.subviews;
tempView = subviewsArray[MIN(subviewsArray.count, MAX(0, subviewsArray.count - 2))];
}

注意一下这个方法: snapshotViewAfterScreenUpdates: 剩下的看代码就OK了,这几个例子我感觉其实带的框架都是一样的,不一样的就是里面的动画具体的实现,先看看我们4、5、6说的这几个Demo的效果:

EXAMPLE-FIVE

圆点扩散这个Demo主要的就是灵活的使用了UIBezierPath 和 CABasicAnimation,其实还要掌握了转场的本质,感觉剩下的真的就看你能想到哪里了!哈哈.....

这个Demo所有的核心都在下面两个方法里面:

-(void)presentViewController:(id <UIViewControllerContextTransitioning>)transitionContext

-(void)dismissViewController:(id <UIViewControllerContextTransitioning>)transitionContext

具体的代码我就不再说了,代码上面的注释是足够了的,很详细.....还是看代码吧。

EXAMPLE-SIX

导航控制器的转场

最后的这个翻页效果的Demo,其实你看着它像3D的感觉,你想起了 CATransform3D 感觉就够了,通过下面这个方法来开始我们的导航转场:

-(void)presentNextControllerClicked{

    // 既然这里是导航控制器的转场,就要给导航设置代理。然后在第二个控制器遵守相应的协议之后,判断
// 是Push还是Pop,执行相应的动画
PageToViewController * pushVC = [PageToViewController new];
self.navigationController.delegate = pushVC;
[self.navigationController pushViewController:pushVC animated:YES];
}

下面要注意的就是导航操作的判断,是Push还是Pop,我们就在导航代理的下面方法里面判断,重点应用的就是代理方法里面的operation参数:

#pragma mark - UINavigationControllerDelegate
- (id<UIViewControllerAnimatedTransitioning>)navigationController:(UINavigationController *)navigationController animationControllerForOperation:(UINavigationControllerOperation)operation fromViewController:(UIViewController *)fromVC toViewController:(UIViewController *)toVC{ //分pop和push两种情况分别返回动画过渡代理相应不同的动画操作
return [[PageAnimation alloc]initWith:operation == UINavigationControllerOperationPush ? Push_type : Pop_type]; }

注意到上面说的两点,剩下的又回到我们最开始的--动画了!动画部分的代码就不粘贴出来占用篇幅了,还是那句下载下来自己去看看!

你看着上面给的效果图,要有兴趣就去下载代码看看,源码当中还是有很多的细节的,我也加了注释,希望上面所有的东西以及源码里面的内容能帮助到大家!

最后:

这个上面的暂时就告一段落了,后面有新的动向我会在接着更新,下面是我学习的过程中,看过的相关的博客!感谢作者......

Demo的下载地址这里再发一次: 这里是Demo的下载地址

iOS自定义转场动画实战讲解

iOS自定义转场动画

iOS视图控制器转场详解

WWDC 2013 Session笔记 - iOS7中的ViewController切换

iOS 转场动画探究(二)的更多相关文章

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

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

  2. iOS转场动画

    文顶顶 最怕你一生碌碌无为 还安慰自己平凡可贵 iOS开发UI篇—核心动画(转场动画和组动画) iOS开发UI篇—核心动画(转场动画和组动画) 一.转场动画简单介绍 CAAnimation的子类,用于 ...

  3. iOS - 转场动画

    苹果在 iOS7 定制了 ViewController 的切换效果 一 在iOS5和iOS6之前,ViewController的切换主要有4种 Push/Pop,NavigationViewCotnr ...

  4. iOS转场动画封装

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

  5. iOS 转场动画核心内容

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

  6. iOS转场动画初探

    一般我们就用两种转场push和present present /** 1.设置代理 - (instancetype)init { self = [super init]; if (self) { se ...

  7. 一步一步教你实现iOS音频频谱动画(二)

    如果你想先看看最终效果再决定看不看文章 -> bilibili 示例代码下载 第一篇:一步一步教你实现iOS音频频谱动画(一) 本文是系列文章中的第二篇,上篇讲述了音频播放和频谱数据计算,本篇讲 ...

  8. IOS 转场动画二和透明控制器视图

    一.透明视图控制器 WJListMenuViewController *VC = [[WJListMenuViewController alloc]init]; VC.modalPresentatio ...

  9. 一步一步教你实现iOS音频频谱动画(一)

    如果你想先看看最终效果再决定看不看文章 -> bilibili 示例代码下载 第二篇:一步一步教你实现iOS音频频谱动画(二) 基于篇幅考虑,本次教程分为两篇文章,本篇文章主要讲述音频播放和频谱 ...

随机推荐

  1. js获取一组不重复的随机数的方法

    一.基本思路: 建立一个数组存放所有可以取到的值,每次从该数组中随机取走一个,放到新的数组中,直到完成. 二.实现方法 1.方法一: (1)创建一个数组arr,数组元素为所有可能出现元素的集合: (2 ...

  2. poj1151 Atlanis 线段树+离散化求矩形面积的并

    题目链接:http://poj.org/problem?id=1151 很经典的题目,网上有很多模板代码,自己理解了一天,然后很容易就敲出来了... 代码: #include<iostream& ...

  3. [笔记]ACM笔记 - 利用FFT求卷积(求多项式乘法)

    卷积 给定向量:, 向量和: 数量积(内积.点积): 卷积:,其中 例如: 卷积的最典型的应用就是多项式乘法(多项式乘法就是求卷积).以下就用多项式乘法来描述.举例卷积与DFT. 关于多项式 对于多项 ...

  4. [刷题]算法竞赛入门经典(第2版) 6-7/UVa804 - Petri Net Simulation

    题意:模拟Petri网的执行.虽然没听说过Petri网,但是题目描述的很清晰. 代码:(Accepted,0.210s) //UVa804 - Petri Net Simulation //Accep ...

  5. JAVA 基础之Integer

    jdk1.5后增加了自动拆箱和自动装箱特性.java的八种 byte,short,int,long,float,double,char,boolean基本类型和各自对应的包装类型的相互转化. 装箱指的 ...

  6. 二叉树遍历 C#

    二叉树遍历 C# 什么是二叉树 二叉树是每个节点最多有两个子树的树结构 (1)完全二叉树——若设二叉树的高度为h,除第 h 层外,其它各层 (1-h-1) 的结点数都达到最大个数,第h层有叶子结点,并 ...

  7. 最优雅SSM框架:SpringMVC + Spring + MyBatis

    在写代码之前我们先了解一下这三个框架分别是干什么的? 相信大以前也看过不少这些概念,我这就用大白话来讲,如果之前有了解过可以跳过这一大段,直接看代码! SpringMVC:它用于web层,相当于con ...

  8. 教育类APP开发现新增长,多款APP该如何突围?

    "十二五"以来,国家共出台相关的重大教育政策文件741个,而进入到"十三五"时期教育领域综合改革深入推进的关键期,不断促进教育现代化的实现.加快迈入人力资源强国 ...

  9. 重构了cxlt-vue2-toastr插件

    距离上篇文章已经过去一个多月了,期间有很多想法,但时间真不是想挤就能挤出来的.其实这段时间我就做了一件事,一个小程序的项目,已上线半月有余,也迭代了几个版本,现在还在不断完善. 先说点题外话,我们做了 ...

  10. python 列表转字典

    def func_data(text): data = dict() for kv in text.split(','): k_v = kv.split(':') data[k_v[0]] = k_v ...