苹果在 iOS7 定制了 ViewController 的切换效果

一 在iOS5和iOS6之前,ViewController的切换主要有4种

  1. Push/Pop,NavigationViewCotnroller常做的事儿
  2. Tab, TabViewController点击
  3. Present Modal,调用viewController的presentViewController:animated:completion:方法
  4. add ChildViewController,调用addChildViewController:(UIViewController *)childController方法

注意:使用第四种方式时,一般使用transitionFromViewController:toViewController:的animation block中可以实现一些简单的切换效果,这样做有2大不足:

  1. 代码高度耦合,vc切换部分的代码直接写在container中,难以分离重用。
  2. 支持的切换效果比较有限,因为其职能使用UIView动画来切换,管理起来也略显麻烦。

二 iOS7中引入一些新的api,更松耦合地定义viewController的转换效果

从上图中可看出,新的api主要提供了2中vc切换方式。

一种是动画式切换,即定义一种从一个vc到另一个vc的动画效果,切换的时候自动播放。

一种是交互式切换,这种方式同样需要定义动画效果,只是这个动画效果会跟随交互手势来切换vc并同时播放动画效果。用法略有不同。

动画式切换:

  1. 首先定义一个动画类实现接口 UIViewControllerAnimatedTransitioning,实现接口的2个方法,一个是动画效果,一个是动画时间。实现动画效果时可以从参数transitionContext中获取到切换时的上下文信息,比方说从哪个VC切换到哪个VC等。
  2. 在需切换的VC中实现UIViewControllerTransitioningDelegte,并实现animationController方法,返回一个步骤1中定义的动画变量。
  3. 调用展现VC切换方法,presentViewController / push等。

(1)、单独两个ViewController之间的转场(相当于以前的modal),需要第一个VC去实现 UIViewControllerTransitioningDelegate

VC -->VC (纯VC-->纯的VC、纯VC-->UINavigationVC、UINavigationVC-->纯VC、UINavigationVC-->UINavigationVC)

即 VC.transitioningDelegate    或者 UINavigationVC.transitioningDelegate

(2)、不是单独两个ViewController之间的转场,需要用一个UINavigationController去控制转场的 我们需要告知 UINavigationController 去使用 UIViewControllerAnimatedTransitioning.

1.应该让当前这个ViewController去作为UINavigationControllerDelegate的代理对

2.最好是写一个基类继承UINavigationController 在里面设置UINavigationControllerDelegate代理,对于不同的由UINavigationController去控制的转场动画做统一处理

self.delegate = self ;

- (id <UIViewControllerAnimatedTransitioning>)navigationController:(UINavigationController *)navigationController
animationControllerForOperation:(UINavigationControllerOperation)operation
fromViewController:(UIViewController *)fromVC
toViewController:(UIViewController *)toVC{ if ([toVC isKindOfClass:[SecondViewController class]]) {
MagicMoveTransition *transition = [[MagicMoveTransition alloc]init];
return transition;
}else{
return nil;
}
}

交互式切换:

  1. 首先定义一个动画类实现接口 UIViewControllerInteractiveTransitioning,iOS7提供了一个默认的基于百分比的动画实现UIPercentDrivenInteractiveTransition,不想太麻烦可以直接扩展这个类。该类需要绑定需要实现手势控制的VC,同时把手势操作添加到该VC上,然后在处理手势动作的时候,调用接口中的方法去更新当前的动画进度。
  2. 定以切换时的动画效果类。和动画式切换的方式一致。
  3. 在需切换的VC中实现UIViewControllerTransitioningDelegate,实现interactiveController方法,返回步骤1定义的类,实现animationController方法返回步骤2定义的动画效果。
  4. 一般用于响应手势做出的转场动画。

例如:在用户手指从屏幕左边边缘划入时产生互动

我们在第二个 viewController 的 viewDidLoad 方法中,创建这个手势识别器

- (void)viewDidLoad {
[super viewDidLoad];
UIScreenEdgePanGestureRecognizer *edgePanGestureRecognizer = [[UIScreenEdgePanGestureRecognizer alloc]initWithTarget:self action:@selector(edgePanGesture:)];
//设置从什么边界滑入
edgePanGestureRecognizer.edges = UIRectEdgeLeft;
[self.view addGestureRecognizer:edgePanGestureRecognizer];
}

现在我们可以识别该手势了,然后我们用它来设置并更新一个 iOS 7 新加入的类的对象。 UIPercentDrivenInteractiveTransition。这个类的对象会根据我们的手势,来决定我们的自定义过渡的完成度。我们把这些都放到手势识别器的 action 方法中去,具体就是:

-(void)edgePanGesture:(UIScreenEdgePanGestureRecognizer *)recognizer{
//计算手指滑的物理距离(滑了多远,与起始位置无关)
CGFloat progress = [recognizer translationInView:self.view].x / self.view.bounds.size.width;
progress = MIN(1.0, MAX(0.0, progress));//把这个百分比限制在0~1之间 //当手势刚刚开始,我们创建一个 UIPercentDrivenInteractiveTransition 对象
if (recognizer.state == UIGestureRecognizerStateBegan) {
self.percentDrivenTransition = [[UIPercentDrivenInteractiveTransition alloc]init];
[self.navigationController popViewControllerAnimated:YES];
}else if (recognizer.state == UIGestureRecognizerStateChanged){
//当手慢慢划入时,我们把总体手势划入的进度告诉 UIPercentDrivenInteractiveTransition 对象。
[self.percentDrivenTransition updateInteractiveTransition:progress];
}else if (recognizer.state == UIGestureRecognizerStateCancelled || recognizer.state == UIGestureRecognizerStateEnded){
//当手势结束,我们根据用户的手势进度来判断过渡是应该完成还是取消并相应的调用 finishInteractiveTransition 或者 cancelInteractiveTransition 方法.
if (progress > 0.5) {
[self.percentDrivenTransition finishInteractiveTransition];
}else{
[self.percentDrivenTransition cancelInteractiveTransition];
}
} }

最后一步,别忘了告诉navigationController 去用它。 在SecondViewController.m 里,实现UINavigationControllerDelegate 中的另一个返回UIViewControllerInteractiveTransitioning的方法:

- (id <UIViewControllerInteractiveTransitioning>)navigationController:(UINavigationController *)navigationController
interactionControllerForAnimationController:(id <UIViewControllerAnimatedTransitioning>) animationController{
if ([animationController isKindOfClass:[MagicMoveInverseTransition class]]) {
return self.percentDrivenTransition;
}else{
return nil;
}
}

iOS8  UIPresentationController

modal 的方式

UIPresentationController,它与 iOS 7 新添加的几个类与协议一道,帮助我们方便快捷地实现 ViewController 的自定义过渡效果。

代码:https://github.com/PeteC/PresentationControllers

UIPresentationController 的子类是负责「被呈现」及「负责呈现」的 controller 的大小 modal出来的控制器其实是在单独的一个window中里面有个容器放着被呈现的vc,可以改变view 的frame (其controller 大小也会改变)如下

- (void)containerViewWillLayoutSubviews{
[super containerViewWillLayoutSubviews];
// 1.设置弹出View的尺寸
[self presentedView].frame = self.presentedFrame;
// 2.添加蒙版
[self setupCoverView]; }

当然它还可以负责的仅仅是那个带渐变效果的红色的半透明背景 View 的动画(其实是我们自己加进去一个view 然后根据监听弹出的的过程对改view做动画)

* presentationTransitionWillBegin //是在呈现过渡即将开始的时候被调用的
* presentationTransitionDidEnd: //是在呈现过渡结束时被调用的
* dismissalTransitionWillBegin
* dismissalTransitionDidEnd:
* frameOfPresentedViewInContainerView// 重写返回PresentedView的frame

http://www.cocoachina.com/industry/20140707/9053.html

http://www.kittenyang.com/uipresentation/

最新文章

  1. Android GPS应用开发
  2. MyEclipse Hibernate 学习总结
  3. 在Array原型链上扩展remove,contain等方法所遇到的坑
  4. C#新语法特性前瞻
  5. BZOJ 3123 森林(函数式线段树)
  6. Java HashMap 核心源码解读
  7. Packetbeat协议扩展开发教程(2)
  8. ARM中的PC和AXD的PC
  9. ASP.NET多线程下使用HttpContext.Current为null解决方案
  10. Cyclic Nacklace - HDU 3746(next求循环节)
  11. HDU H204 阿牛的EOF牛肉串
  12. 解决红米等手机(移动端)无法触发touchend事件
  13. a标签阻止跳转的方法
  14. 引用iscroll的一个封装方法
  15. ios 检测屏幕方向
  16. linux的dd命令
  17. 使用Java方式连接HDFS
  18. Flutter去除右上角Debug标签
  19. Java核心技术及面试指南 IO部分的面试题归纳以及答案
  20. .net core compatibility windows &amp; windows compatible Linux

热门文章

  1. Android O 可以上网 提示无法访问网络
  2. C语言简明数据类型指南
  3. SpringBoot系列五:SpringBoot错误处理(数据验证、处理错误页、全局异常)
  4. Java如何显示所有正在运行的线程?
  5. RNA_seq GATK 最佳实践
  6. Scala学习笔记——安装
  7. iOS7以上: 实现如“日历”的 NavigationBar
  8. Objective-C 语法之 Debug 表达式
  9. Array.prototype.removeBeginWithVal(删除数组内以某值开头的字符串对象)
  10. C# 异步锁【转】