一、效果和源码

本文介绍如何实现一个NavigationController的自定义Push和Pop过渡动画,运行效果如下:

源码:https://github.com/dolacmeng/TransitionDemo 或
http://download.csdn.net/detail/dolacmeng/9572384

二、准备工作

首先,新建两个ViewController的实例,分别为FirstViewController和SecondViewController,在FirstViewController中包含一个TableView列表,每个cell都展示了一张图片和标题,当用户点击任意cell时,将跳转到SecondViewController,并且cell中图片将以动画的形式移动到新的ViewController中,FirstViewController和SecondViewController的布局实现细节就不再累赘。

三、使用自定义过渡效果

为了让UINavigationController使用我们自定义的过渡动画而不是系统默认的动画,首先需要让FirstViewController遵循UINavigationControllerDelegate协议,并在viewDidAppear:中设置当前controller为navigationController的代理对象:

- (void)viewDidAppear:(BOOL)animated {[super viewDidAppear:animated];self.navigationController.delegate = self;
}

我们还应该在controller不可见时取消其作为navigation control的代理对象。

- (void)viewWillDisappear:(BOOL)animated {[super viewWillDisappear:animated];if (self.navigationController.delegate == self) {self.navigationController.delegate = nil;}
}

当使用push或pop将controller从navigation压栈或者出栈时,它都会询问它的代理来获得一个遵循UIViewControllerAnimatedTransitioning协议的对象,我们把这个对象命名为FirstTransition,我们只要实现UINavigationControllerDelegate的以下方法,返回FirstTransiton即可。

- (id<UIViewControllerAnimatedTransitioning>)navigationController:(UINavigationController *)navigationControlleranimationControllerForOperation:(UINavigationControllerOperation)operationfromViewController:(UIViewController *)fromVCtoViewController:(UIViewController *)toVC {if (fromVC == self && [toVC isKindOfClass:[SecondViewController class]]) {return [[FirstTransition alloc] init];}else {return nil;}
}
四、实现自定义过渡效果

FirstTransition现在报错,因为我们还没有定义这个类,那么我们新建一个NSObject的子类,并遵循UIViewControllerAnimatedTransitioning协议,命名为FirstTransition。

现在我们运行项目,并没有什么效果,而且FirstTransition有警告,说我们还没实现UIViewControllerAnimatedTransitioning的协议方法。因为我们必须实现此代理的这两个方法:animateTransition:和transitionDuration:

transitionDuration:只需要返回过渡动画的时间:

- (NSTimeInterval)transitionDuration:(id<UIViewControllerContextTransitioning>)transitionContext {return 0.3;
}

animateTransition:方法是本文的核心,它将负责处理整个过渡的动画方式。它传递了一个包含了我们需要用到的几个类的参数,还提供了下面这些方法

• viewControllerForKey:获得过渡的两个controllers

• containerView容纳两个viewcontroller的容器view

• initialFrameForViewController: 和finalFrameForViewController每个controller的view的开始和结束位置。

我们看下animateTransition:的实现,我们首先分别获得过渡的两个controller以及容器view的指针。

- (void)animateTransition:(id<UIViewControllerContextTransitioning>)transitionContext {FirstViewController *fromViewController = (FirstViewController*)[transitionContext viewControllerForKey:UITransitionContextFromViewControllerKey];SecondViewController *toViewController = (SecondViewController*)[transitionContext viewControllerForKey:UITransitionContextToViewControllerKey];UIView *containerView = [transitionContext containerView];NSTimeInterval duration = [self transitionDuration:transitionContext];

然后,我们获得要过渡的cell,获得imageview的快照,push操作时,我们移动这个快照和改变它的大小,同时隐藏cell的imageview,让人看着就像是imageview在移动。

//获得cell中的图片的快照JXTableViewCell *cell = (JXTableViewCell*)[fromViewController.tableView cellForRowAtIndexPath:[fromViewController.tableView indexPathForSelectedRow]];UIView *cellImageSnapshot = [cell.leftImageView snapshotViewAfterScreenUpdates:NO];cellImageSnapshot.frame = [containerView convertRect:cell.leftImageView.frame fromView:cell.leftImageView.superview];cell.leftImageView.hidden = YES;

再然后,我们设置第二个controller的view,将它设置为透明并将其放置在最终的位置上。我们会使它在过渡过程中逐渐出现。

//设置初始view的状态toViewController.view.frame = [transitionContext finalFrameForViewController:toViewController];toViewController.view.alpha = 0;toViewController.imageView.hidden = YES;[containerView addSubview:toViewController.view];[containerView addSubview:cellImageSnapshot];

现在我们开始编写view的动画,移动图片的快照、逐渐显示第二个controller的view,在动画结束的block中,移除快照并显示我们之前隐藏了的view,最后,我们需要调用completeTransition:来通知过渡上下文过渡已经完成。

 [UIView animateWithDuration:duration animations:^{toViewController.view.alpha = 1.0;CGRect frame = [containerView convertRect:toViewController.imageView.frame fromView:toViewController.view];cellImageSnapshot.frame = frame;}completion:^(BOOL finished) {toViewController.imageView.hidden = NO;cell.leftImageView.hidden = NO;[cellImageSnapshot removeFromSuperview];[transitionContext completeTransition:!transitionContext.transitionWasCancelled];}];
}

至此,我们运行项目,可以看到从FirstViewController跳转到SecondViewController时,将会看到图片移动的动画效果。

五、Pop动画

不过当我们点击返回时,仍然是系统默认动画。我们只要参照前面push的实现,既首先让SecondViewController遵循UINavigationControllerDelegate协议,实现UINavigationControllerDelegate的方法,并返回一个继承自NSObject、遵循UIViewControllerAnimatedTransitioning协议的实例(Demo中的SecondTransition)。在SecondTransition中实现transitionDuration: 和animateTransition:方法,分别返回过渡的时间、设置动画效果。详见Demo源码。

六、使用过渡交互

现在我们让用户可以通过屏幕左边进行交互,我们需要用到iOS7中的UIScreenEdgePanGestureRecognizer类。

我们在secondViewController的viewDidLoad方法中创建UIScreenEdgePanGestureRecognizer

- (void)viewDidLoad {[super viewDidLoad];...UIScreenEdgePanGestureRecognizer *popRecognizer = [[UIScreenEdgePanGestureRecognizer alloc] initWithTarget:self action:@selector(handlePopRecognizer:)];popRecognizer.edges = UIRectEdgeLeft;[self.view addGestureRecognizer:popRecognizer];
}

现在我们可以使用监听到的手势事件,更新另一个类:UIPercentDrivenInteractiveTransition,这将根据我们的手势改变过渡动画进度。

当手势开始,我们创建和存储一个UIPercentDrivenInteractiveTransition实例,然后通知navigation controller来弹栈。

当手势改变,我们根据手势的进度来更新UIPercentDrivenInteractiveTransition。

当手势结束,如果手势拖动足够大,过渡动画执行完成,或者其它情况如取消过渡等,我们根据情况调用finishInteractiveTransition或者cancelInteractiveTransition。

- (void)handlePopRecognizer:(UIScreenEdgePanGestureRecognizer*)recognizer {// Calculate how far the user has dragged across the viewCGFloat progress = [recognizer translationInView:self.view].x / (self.view.bounds.size.width * 1.0);progress = MIN(1.0, MAX(0.0, progress));if (recognizer.state == UIGestureRecognizerStateBegan) {// Create a interactive transition and pop the view controllerself.interactivePopTransition = [[UIPercentDrivenInteractiveTransition alloc] init];[self.navigationController popViewControllerAnimated:YES];}else if (recognizer.state == UIGestureRecognizerStateChanged) {// Update the interactive transition's progress[self.interactivePopTransition updateInteractiveTransition:progress];}else if (recognizer.state == UIGestureRecognizerStateEnded || recognizer.state == UIGestureRecognizerStateCancelled) {// Finish or cancel the interactive transitionif (progress > 0.5) {[self.interactivePopTransition finishInteractiveTransition];}else {[self.interactivePopTransition cancelInteractiveTransition];}self.interactivePopTransition = nil;}
}


现在我们创建和更新UIPercentDrivenInteractiveTransition实例,我们还需要告诉navigation controller来使用它,在SecondViewController中添加:

- (id<UIViewControllerInteractiveTransitioning>)navigationController:(UINavigationController *)navigationControllerinteractionControllerForAnimationController:(id<UIViewControllerAnimatedTransitioning>)animationController {// Check if this is for our custom transitionif ([animationController isKindOfClass:[DSLTransitionFromSecondToFirst class]]) {return self.interactivePopTransition;}else {return nil;}
}

运行Demo,在secondViewController中,在屏幕左边缘往中间水平滑动,将可以看到过渡进度随着我们的手势而不同。

参考文献:

http://dativestudios.com/blog/2013/09/29/interactive-transitions/
《iOS Animation by Tutorials 2.0》
觉得上面过程太复杂?现在可以简单几行代码实现神奇移动过渡啦,请看我的新文章哦:
http://blog.csdn.net/dolacmeng/article/details/56485140

自定义Push和Pop过渡动画相关推荐

  1. iOS精仿唱吧下载按钮、仿知乎日报、自定义提示视图、过渡动画、记录应用等源码

    iOS精选源码 IOS之分段控制器OC/Swift通用 Swift4.0_组件化:APP启动引导页页 精仿唱吧App音乐下载按钮,完美快速集成使用 iOS指纹解锁和手势解锁源码 OC _纯代码颜色选择 ...

  2. iOS精仿唱吧下载按钮、仿知乎日报、自定义提示视图、过渡动画、记录应用等源码...

    iOS精选源码 IOS之分段控制器OC/Swift通用 Swift4.0_组件化:APP启动引导页页 精仿唱吧App音乐下载按钮,完美快速集成使用 iOS指纹解锁和手势解锁源码 OC _纯代码颜色选择 ...

  3. android自定义过渡动画,11.自定义过渡动画

    11.1 问题 应用程序需要自定义Activity切换或Fragment切换时产生的过渡动画. 11.2 解决方案 (API Level 5) 要修改Activity间的过渡动画,可以使用overri ...

  4. iOS自定义过渡动画

    历时5天从各种英文教程中学习到的过渡动画,是一个很难忘的探索经历 比较好的参考文章自定义UIViewController过渡入门 ,动画入门. 转场方式 首先让我们来了解iOS转场的方式: UINav ...

  5. 【转】更改navigationController push和pop界面切换动画

    为什么80%的码农都做不了架构师?>>>    原文:http://blog.csdn.net/longlongago2000/article/details/7589706 有时候 ...

  6. 二、Vue(发送AJAX请求、Vue生命周期、计算属性、属性和方法、自定义指令、过渡(动画))

    一. 发送AJAX请求 1. 简介     vue本身不支持发送AJAX请求,需要使用vue-resource.axios等插件实现     axios是一个基于Promise的HTTP请求客户端,用 ...

  7. iOS自定义转场动画(1)——自定义Push转场动画

    版本:Xcode 7.0.1 语言:Objective-C 转场动画就是viewController之间切换的动画. 主要有以下三种自定义方法: 列Push & Pop Modal Segue ...

  8. iOS学习笔记-自定义过渡动画

    代码地址如下: http://www.demodashi.com/demo/11678.html 这篇笔记翻译自raywenderlick网站的过渡动画的一篇文章,原文用的swift,由于考虑到swi ...

  9. 手机端 自定义简单的下拉动画效果选择框 解决过渡失效

    手机端 自定义简单的下拉动画效果选择框 解决过渡失效 <template> // 弹出框触发 并显示选择结果<view class="header_top_sel" ...

最新文章

  1. MySQL 源码 需要 什么基础_MySQL 基础之 源码 部署
  2. 数据包注入重放工具aireplay-ng
  3. Chrome 浏览器提示adobe flash player不是最新版本
  4. 减小Delphi xe系列生成的exe文件大小
  5. Swift--控制流与oc不同的地方
  6. LeetCode 793. 阶乘函数后K个零(二分查找)
  7. 一个显示器分两个屏幕_桌面改造计划2.0:一个显示器不够那就两个,桌面好物分享...
  8. bash给脚本加进度条_shell脚本实现多彩进度条
  9. 数据中心操作人员:艰难地在针对VM构建的基础设施上运行容器
  10. 程序员输入法_解决Pycharm输入法不跟随光标
  11. [2019杭电多校第四场][hdu6614]AND Minimum Spanning Tree(贪心)
  12. URLSession实现iTunes搜索听歌
  13. java运行库下载_Java运行库下载-jdk1.7 64位下载1.8.0.20 官方最新版-东坡下载
  14. 推荐20个值得收藏的前端开源项目
  15. LabVIEW操作者框架(Actor Framework)范例集锦之三:网络搜索范例
  16. 2019医学电子书下载PDF电子版下载
  17. linux-CentOS7.6操作系统安装手册
  18. vue高德地图H5定位及城市选择器控件实现详细教程
  19. html网页随机一言,PHP简单实现一言 / 随机语录功能
  20. 养胃有道——送给胃不好的人 (转)

热门文章

  1. 【AHOI 2016初中组】 自行车比赛 - 贪心
  2. Angular4.0从入门到实战打造在线竞拍网站学习笔记之四--数据绑定管道
  3. lucene构建同义词分词器
  4. 【Java面试题】54 去掉一个Vector集合中重复的元素
  5. 一个老工程师对理工科学生的忠告
  6. valgrind——Callgrind检测程序代码的运行时间和调用过程,程序分析性能。
  7. c语言inline详解
  8. 为 ASP.NET Datagrid 创建自定义列
  9. 朴素、Select、Poll和Epoll网络编程模型实现和分析——Poll、Epoll模型处理长连接性能比较
  10. Ubuntu14.04下配置OpenGL及测试代码