当前位置: 首页 > 编程日记 > 正文

自定义Push和Pop过渡动画

一、效果和源码

本文介绍如何实现一个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


相关文章:

centos 安装 mysql 5.7

一&#xff0c;wget http://dev.mysql.com/get/mysql57-community-release-el6-8.noarch.rpm 二&#xff0c;yum localinstall mysql57-community-release-el6-8.noarch.rpm 三&#xff0c;yum install mysql-server 四&#xff0c;mysqld --initialize --usermysql 五&#xf…

c语言:婚礼上的谎言

/* 三对新人参加婚礼&#xff0c;三位新郎A,B,C,三位新娘X,Y,Z。 有人想知道谁与谁结婚&#xff0c;于是就问他们&#xff1a; A说他将和X结婚&#xff1b; X说他的未婚夫是C&#xff1b; C说他将和Z结婚。 这人时候知道他们都在说谎。编程求谁与谁结婚&#xff01; */ /* 思路…

redis主从复制、高可用和集群

redis简介&#xff1a; redis是一个key-value存储系统.和Memcached类似&#xff0c;它支持存储的value类型相对更多&#xff0c;包括string(字符串)、list(链表)、set(集合)、zset(sorted set --有序集合)和hashs&#xff08;哈希类型&#xff09;;这些数据类型都支持push/pop、…

对学习编译原理的看法

我认为编译原理这本书是一门与代码做斗争的课程&#xff0c;学习编译原理能够追寻程序设计语言的本质&#xff0c;了解计算机各种语言编译的原理。学习了编译原理能够更加深入的了解计算机各种高级语言使用的原理&#xff0c;能使自己更加容易更加好的学习好程序语言&#xff0…

iOS提示气泡,带动画

1.效果如图&#xff1a; 从项目中抠出来的&#xff0c;做了简单的封装。 2.用法&#xff1a; //顶部提示HYNoticeView *noticeTop [[HYNoticeView alloc] initWithFrame:CGRectMake(50, 66, 250, 40) text:"这里可以查询全城婚礼人的档期哦&#xff01;" position:…

GIt/Github常用命令

1&#xff09;git init:初始化本地仓库 2&#xff09;创建文件&#xff1a;touch read.txt 3&#xff09;当操作本地的文件时&#xff0c;使用常用的命令&#xff0c;如&#xff08;mv&#xff0c;ls。。&#xff09;就可以操作&#xff0c;当操作暂存区的文件时需要在命令前家…

python练习题(python之“求一个数的阶乘并求结果中从后向前数第一个不为0(零)的数” 等)

实验环境&#xff1a;python2.7 题目1&#xff1a;python之“求一个数的阶乘并求结果中从后向前数第一个不为0(零)的数”程序&#xff1a; import math def factorial(n): #定义一个函数&#xff0c;返回一个数的阶乘 if n0: return 1 else: sumn*factorial(n-…

【动画1】UIView动画

讲一下动画。将分为以下5篇博客。 一&#xff09;UIView动画 二&#xff09;Layer动画 三&#xff09;3D动画 四&#xff09;转场动画 五&#xff09;第三方动画框架 相关代码&#xff1a;https://github.com/dolacmeng/AnimationDemo 参考资料&#xff1a;iOS Animation…

【python】解压文件

参考&#xff1a;http://essen.iteye.com/blog/1941489 tarfile模块 具体使用方法&#xff1a; https://docs.python.org/2/library/tarfile.html 例子&#xff1a;一次性解压所有文件 import tarfilet tarfile.open("abc.tgz", "r:gz")t.extractall(path…

JS设计模式——3.封装与信息隐藏

封装、信息隐藏与接口的关系 信息隐藏是目的&#xff0c;封装是手段。 接口提供了一份记载着可供公共访问的方法的契约。它定义了两个对象间可以具有的关系。只要接口不变&#xff0c;这个关系的双方都是可以替换的。 一个理想的软件系统应该为所有类定义接口。 创建对象的基本…

nginx源码编译、负载均衡及模块的扩展

1、nginx源码编译 实验环境&#xff1a; iptables和selinux关闭 redhat6.5 nginx&#xff1a;test1: 172.25.1.11 [roottest1 ~]# ls nginx-1.14.0.tar.gz [roottest1 ~]# tar zxf nginx-1.14.0.tar.gz [roottest1 ~]# useradd -s /sbin/nologin nginx [roottest1 ~]# i…

LinkedHashMap and LinkedHashSet

LinkedHashMap实现了Map接口&#xff0c;是HashMap的直接子类&#xff0c;它同时满足HashMap和linked list的某些特性。可将LinkedHashMap看作采用linked list增强的HashMap。 LinkedHashMap在HashMap的基础上&#xff0c;采用双向链表&#xff08;doubly-linked list&#xff…

Windows Phone开发(19):三维透视效果

Windows Phone开发&#xff08;19&#xff09;&#xff1a;三维透视效果 原文:Windows Phone开发&#xff08;19&#xff09;&#xff1a;三维透视效果 三维效果也可以叫透视效果&#xff0c;所以&#xff0c;我干脆叫三维透视效果。理论知识少讲&#xff0c;直接用例开场吧&am…

【动画2】CALayer动画

一&#xff09;UIView动画 二&#xff09;CoreAnimation动画 前言&#xff1a;上一篇已经介绍了UIKit给我们封装好的UIView动画的使用&#xff0c;UIKit动画是建立在CoreAnimation动画之上的&#xff0c;CoreAnimation是直接作用于CALayer上而非UIView。一、CoreAnimation动画…

nginx+tomcat+memcache实现负载均衡、session共享

实验架构图&#xff1a; Table of Contents 1、配置tomcat 2、安装memcache 3、查看tomcat和memcache是否配置好 4、nginx实现负载均衡&#xff1a; 5、客户端进行测试&#xff1a; 6、验证结论&#xff1a; 7、总结&#xff1a; 实验环境&#xff1a; linux redhat6.…

(转)二叉树系列面试问题

转自 &#xff1a;http://blog.csdn.net/luckyxiaoqiang/article/details/7518888/ 版权所有&#xff0c;转载请注明出处&#xff0c;谢谢&#xff01;http://blog.csdn.net/walkinginthewind/article/details/7518888 树是一种比较重要的数据结构&#xff0c;尤其是二叉树。二…

百度UEditor开发案例(JSP)

本案例的开发环境&#xff1a;MyEclipsetomcatjdk 本案例的开发内容&#xff1a;用百度编辑器发布新闻&#xff08;UEditor的初始化开发部署&#xff09;编辑已发过的新闻&#xff08;UEditor的应用——编辑旧文章&#xff09;上传附件、图片等 由于百度编辑器强大的功能&a…

iOS中的动力学:Dynamics【1】

iOS7建议我们创建的界面具有物理特性&#xff0c;而不只是像素的集合&#xff0c;可以响应触摸、手势、屏幕方向改变等事件&#xff0c;让用户与界面之间有更深入的交互&#xff0c;而不是像iOS6那样在软件界面上模仿现实世界的纹理而已。或许你会认为创建感觉上真实的界面比创…

自动化运维工具Saltstack(一)

1、saltstack简介&#xff1a; 什么是saltstack&#xff1f; saltstack是基于python开发的一套C/S架构配置管理工具 使用SSL证书签方的方式进行认证管理 号称世界上最快的消息队列ZeroMQ使得SaltStack能快速在成千上万台机器上进行各种操作 采用RSA Key方式确认身份 传输采用AE…

【UIDynamic例子】挂起的方块

通过前面的动力学小Demo&#xff08;本文默认你已经看过这篇Blog&#xff1a;传送门&#xff09;&#xff0c;我们对UIKit中的UIDynamic已经有了初步的认识。现在我们写个更加有趣的Demo&#xff1a;模拟一个用弹性绳子挂起的小方块&#xff0c;用户可以将它拖动到屏幕任意位置…

IIS7 配置PHP服务器

安装PHP Manager&#xff1a; 1&#xff09;访问 http://phpmanager.codeplex.com/releases/view/69115 下载PHP Manager。其中&#xff0c;x86 为32位 Windows 系统使用&#xff0c;x64 为64位 Windows 系统使用&#xff0c;请根据使用的 Windows 系统情况下载 2&#xff09;下…

在文本框中提示用户输入内容格式的方法

希望达到的效果&#xff1a; 方法一&#xff1a;鼠标点击文本框时文字消失 <input id"login_name" type"text" οnblur"javascript:check_login_name();" οnfοcus"if(this.value支持英文及数字组合) this.value;this.style.color#000&…

saltstack实现haproxy+keepalived负载均衡+高可用(二)

一键部署haproxykeepalived实现负载均衡高可用 实验环境&#xff1a; &#xff01;&#xff01;&#xff01;&#xff01; 特别注意&#xff1a; www.westos.org为test1的minion名字 test1: 172.25.1.11 nginx master minion test2: 172.25.…

iOS开发技巧(系列十八:扩展UIColor,支持十六进制颜色设置)

新建一个Category&#xff0c;命名为UIColorHex&#xff0c;表示UIColor支持十六进制Hex颜色设置。 UIColorHex.h文件&#xff0c; #import <UIKit/UIKit.h> #define RGBA_COLOR(R, G, B, A) [UIColor colorWithRed:((R) / 255.0f) green:((G) / 255.0f) blue:((B) / 255…

iOS顶部菜单栏

封装的一个顶部菜单栏&#xff0c;使用懒加载&#xff08;选择后加载当前页及前后各一页&#xff09;&#xff0c;自适应标题长度。 下载&#xff1a; Github&#xff1a;https://github.com/dolacmeng/JXChannelSegment 用法&#xff1a; //init Segment segment [[JXSegme…

Mac环境下svn的使用

CHENYILONG BlogMac环境下svn的使用 Mac环境下svn的使用 在Windows环境中&#xff0c;我们一般使用TortoiseSVN来搭建svn环境。在Mac环境下&#xff0c;由于Mac自带了svn的服务器端和客户端功能&#xff0c;所以我们可以在不装任何第三方软件的前提下使用svn功能&#xff0c;不…

zabbix简介及基本安装(一)

zabbix简单介绍&#xff1a; 官网&#xff1a;可以进官网查看一下&#xff1a;https://www.zabbix.com/cn/ //英语能力有限的读者可以将由上角的语言调成汉语方便查看 功能&#xff1a;网络监控、服务器监控、云监控、服务监控等。 介绍&#xff1a;zabbix&#xff08;[…

顺序表应用6:有序顺序表查询

顺序表应用6&#xff1a;有序顺序表查询 Time Limit: 7MS Memory Limit: 700KBSubmit StatisticProblem Description 顺序表内按照由小到大的次序存放着n个互不相同的整数&#xff08;1<n<20000)&#xff0c;任意输入一个整数&#xff0c;判断该整数在顺序表中是否存在。…

LA 5717枚举+最小生成树回路性质

1 /*LA 57172 《训练指南》P3433 最小生成树的回路性质4 在生成的最小生成树上&#xff0c;新增一条边e(u,v)5 若原图上u到v的路径的最大边大于e&#xff0c;则删除此边&#xff0c;加上e&#xff0c;否则不变。6 7 若原图上u到v的路径的最大边的产生&#xff1a;BFS/DFS都可 &…

【Runtime】动态添加方法demo

今天写一个小demo来演示下runtime的消息转发和动态添加方法。 一般项目中都会有保存当前登录用户资料的需求&#xff0c;我们可以直接将登录成功后的用户信息分别保存到NSUserDefaults中&#xff1a; [def setObject:"JackXu" forKey:"UserName"];[def set…