Swift: 是用Custom Segue还是用Transition动画
用一个很简单的场景做为例子:在storyboard上,你有用UINavigationController
串起来两个UIViewController
。这两个controller之间要互相跳转,A->B, B->A。跳转的时候默认的那个push来push去的效果你觉得很傻X,所以想换一个效果。比如,不那么二的fade in/out效果。
很多的例子会说写一个cusom的UIStoryboardSegue
,然后在这个里面写一个UIView.animationWithDuration
来实现这个效果。千万别这么干!从iOS7开始就有一个更加方便简洁的方法可以实现这个效果。
下面就开始介绍这个很牛X的方法。首先创建一个single view的项目。名称可以叫做transitionDemo
。各个controller之间的关系是这样的:

一个UINavigationController
作为启动controller,串起来一个UITableViewController
(root controller)和一个UIViewController
。在Prototype Cells上ctrl+drag到view controller上,并选择show。
下面分别为table view controller创建类TDTableViewController
为view controller创建类TDViewController
之后分别在storyboard里关联起来。把从table view controller到view controller的segue的identitifer设置为TDViewController
。

接下来给TDTableViewController
添加数据源:
class TDTableViewController: UITableViewController { var tableViewDataSource: [String]? override func viewDidLoad() {
super.viewDidLoad() createDataSource()
} func createDataSource() {
if let _ = self.tableViewDataSource {
return
} self.tableViewDataSource = [String]()
for i in 0..<100 {
self.tableViewDataSource!.append("item :- [\(i)]")
}
}
//............
}
打开storyboard,在TDViewController
里添加一个label,给这个label添加约束,随便是什么约束都可以只要是正确的。然后在controller里添加这个label的outlet并关联。
在TDViewController
代码中添加数据属性,并在viewDidLoad
方法里给这label的text赋值:
class TDViewController: UIViewController { @IBOutlet weak var dataLabel: UILabel! var singleData: String! override func viewDidLoad() {
super.viewDidLoad() self.dataLabel.text = self.singleData
}
}
使用默认的segue,这里现在是show模式,跳转。并从table view controller出传递数据给view controller:
// 使用segue跳转
override func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
self.dataItem = self.tableViewDataSource![indexPath.row]
self.performSegueWithIdentifier("TDViewController", sender: nil)
} // 传递数据
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
if segue.identifier != "TDViewController" {
return
} let destinationController = segue.destinationViewController as! TDViewController
destinationController.singleData = self.dataItem!
}
run一把来看看:

Segue和Transition
custom segue
直接用代码把两种方式都实现出来,分别代替上面使用的默认的实现方式。
首先弄一个custom segue。要开发一个custom segue,首先需要创建一个类并继承自UIStoryboardSegue
,我们为这个类命名为DetailStoryboardSegue
。在这个类中关键就是实现方法perform()
。
import UIKit class DetailStoryboardSegue: UIStoryboardSegue {
override func perform() {
let sourceView = self.sourceViewController.view // 1
let destView = self.destinationViewController.view let window = (UIApplication.sharedApplication().delegate as! AppDelegate).window
window?.insertSubview(destView, aboveSubview: sourceView) // 2 destView.alpha = 0.0 UIView.animateWithDuration(0.3, animations: { // 3
destView.alpha = 1.0
})
}
}
self.sourceViewController
和self.destinationViewController
都是UIStoryboardSegue
类本身就有的属性。从A controller跳转到B controller,那么source就是A,destination就是B。我们的fade in/out效果就是通过source和destination controller的view的切换和alpha实现的。- 在window上做source和destination view的切换。把destination view覆盖到source view上。
- destination view的alpha在上一步设置为了0,也就是完全透明的。在动画中把destination view的alpha设置回完全不透明,把view呈现在用户面前达到fade in的效果。
实现完成后,在storyboard中把segue的Kind 设置为custom,然后给Class设置为类DetailStoryboardSegue
。

其实很简单,运行起来看看。

你会看到,运行的结果出了一点问题。之前在正确位置显示的label,在这里居然出现在了屏幕的顶端。这是因为前面TDViewController
是用navigation controller的push出来的,屏幕的最顶端有一个navigation bar,所以label的top约束是有效的。而我们的custom segue的切换中并不存在navigation controller的push。而是简单的view的覆盖替换,没有navigation bar。所以labe的top约束失效了,直接被显示在了顶端。
这个错误其实引出了一个问题,但是这里我们暂时不做深入讨论。先看看Transitioning animtion动画是怎么运行的,然后我们讨论这个严肃的问题。
custom transitioning animation
实现自定义的切换动画就需要实现UIViewControllerAnimatedTransitioning
这个protocol了。我们自定义一个类DetailTransitioningAnimator
来实现这个protocol。
这个protocol有两个方法是必须实现的,func transitionDuration(transitionContext: UIViewControllerContextTransitioning?) -> NSTimeInterval
和func animateTransition(transitionContext: UIViewControllerContextTransitioning)
。来看代码:
import UIKit class DetailTransitioningAnimator: NSObject, UIViewControllerAnimatedTransitioning {
let durationTimeInterval: NSTimeInterval
// 1
init(duration: NSTimeInterval){
durationTimeInterval = duration
} func transitionDuration(transitionContext: UIViewControllerContextTransitioning?) -> NSTimeInterval {
return self.durationTimeInterval
}
//2
func animateTransition(transitionContext: UIViewControllerContextTransitioning) {
let containerView = transitionContext.containerView()
let sourceController = transitionContext.viewControllerForKey(UITransitionContextFromViewControllerKey)
let destController = transitionContext.viewControllerForKey(UITransitionContextToViewControllerKey) let sourceView = sourceController!.view
let destView = destController!.view containerView?.addSubview(destView) // 3 destView.alpha = 0.0 UIView.animateWithDuration(0.3, animations: {
destView.alpha = 1.0
}, completion: {completed in
let cancelled = transitionContext.transitionWasCancelled()
transitionContext.completeTransition(!cancelled)
})
} func animationEnded(transitionCompleted: Bool) { }
}
- 这个
init
方法不是必需的,但是为了可以自定义动画的执行时间添加这个构造方法。 - transitioning动画的执行方法。在这个方法里实现我们在之前的custom segue里实现的效果。
- 注意这里,用的是
let containerView = transitionContext.containerView()
得到的container view。而不是之前用到的window。
下面把transitioning动画应用到代码中。在使用的时候需要实现UINavigationControllerDelegate
。创建一个类NavigationControllerDelegate
来实现这个protocol。
import UIKit class NavigationControllerDelegate: NSObject, UINavigationControllerDelegate {
func navigationController(navigationController: UINavigationController, animationControllerForOperation operation: UINavigationControllerOperation, fromViewController fromVC: UIViewController, toViewController toVC: UIViewController) -> UIViewControllerAnimatedTransitioning? {
return DetailTransitioningAnimator(duration: 0.3)
}
}
这里没有太多需要讲的。只要知道是这个方法就可以了。
下面在storyboard中把类NavigationControllerDelegate
应用在UINavigationController
中。
- 把object这个东西拖动到项目中唯一存在的navigation controller上。
- 给刚刚的object设置custom class为类
NavigationControllerDelegate
。只要关注右侧的Class的设置就可以。
- 给navigation controller的代理设置为刚刚拖动上去的delegate。
对上面的custom segue代码去掉,并稍作修改之后,运行起来。

木有问题,上面出现的错误也没有了。
这个问题不重要,但是还是要讨论一下:为什么custom segue会出现问题,而transitoning动画就没有问题呢?这里是因为实际上transitioning动画是在navigation controller的基础上改变的。Transitioning动画只是修改了navigation controller的push动画,改成了fade in的效果,而navigation controller的其他机制没有改动。custom segue则完全是两个view之间的动画。那么,这里就留下一个问题由读者去修改上面的custom segue代码来让这个navigation bar 出现出来。
但是什么情况下用custom segue,什么情况下用transition动画呢?Transitioning动画更加的灵活,不像custom segue是在storyboard里定死的。你可以根据不同的情况设定你自己想要的动画。
custom segue就是用来调用一些如:presentViewController
和dismissViewController
之类的方法的。这些方法调用的时候两个view controller之间的转化动画则使用上面的方法来做。他们的职责是不同的。
最后补充一点。也是一个发挥custom segue的作用的地方。在多个storyboard的情况下可以使用custom segue。步骤:(假设你已经创建了另外一个storyboard,叫做Another.storyboard)
- 拖一个storyboard reference到你现在的storyboard中。
- 点选这个storyboard reference,并在右侧工具栏的Storyboard下填写另外一个storyboard的名字,这里是Another.storyboard。
- ctrl+drag,从一个view controller中的按钮等view连接到刚刚添加的storyboard reference上。(确保你的另外一个storyboard的view controller已经设置为默认启动)
- 如果你要启动的是另外一个storyboard的某一个特定的view controller,那么就可以写一个custom segue了。在这个custom segue中初始化出另外一个storyboard,从中获取到你要启动的view controller,然后在custom segue的perform方法中完成controller跳转的最后一步。
all code here
to be continued。。。
Swift: 是用Custom Segue还是用Transition动画的更多相关文章
- 移动端 transition动画函数的封装(仿Zepto)以及 requestAnimationFrame动画函数封装(仿jQuery)
移动端 css3 transition 动画 ,requestAnimationFrame 动画 对于性能的要求,h5优先考虑: 移动端 单页有时候 制作只用到简单的css3动画即可,我们封装一下, ...
- CSS3的transition动画功能
<!DOCTYPE html><html lang="en"><head> <meta charset="UTF-8" ...
- css3 Transition动画执行时有可能会出现闪烁的bug
css3 Transition动画执行时有可能会出现闪烁的bug,一般出现在开始的时候. 解决方法: 1.-webkit-backface-visibility: hidden; 2.-webkit- ...
- 解决transition动画与display冲突的几种方法
如demo(如果没有显示,请查看源地址http://jsfiddle.net/ihardcoder/HNduT/2/)所示,基本的效果是在点击“Translate”按钮后,蓝色区域透明度变为0,然后隐 ...
- appendChild与Transition动画
在createElement之后,直接把这个div append到body中,是不会触发css3 transition动画的 必须要让浏览器计算div的css属性后,然后再设置div的style,才会 ...
- iOS涂色涂鸦效果、Swift仿喜马拉雅FM、抽屉转场动画、拖拽头像、标签选择器等源码
iOS精选源码 LeeTagView 标签选择控件 为您的用户显示界面添加美观的加载视图 Swift4: 可拖动头像,增加物理属性 Swift版抽屉效果,自定义转场动画管理器 Swift 仿写喜马拉雅 ...
- Swift:超炫的View Controller切换动画
匿名社交应用Secret的开发者开发了一款叫做Ping的应用,用户可以他们感兴趣的话题的推送. Ping有一个很炫的东西,就是主界面和之间切换的动画做的非常的好.每次看到一个非常炫的动画,都不由得会想 ...
- css3 transition动画
CSS3: 一.transition: <property> <duration> <animation type> <delay> eg: .div{ ...
- safari渲染Transition动画不流畅问题
用css3的transition过渡来做页面动画的时候,发现在chrome和ff流畅,在safari 不流畅: 度娘找到了淘宝UED的一个类似解决方案,动画就流畅了. 测试环境: win7 32bit ...
随机推荐
- 无法连接到localhost.其他信息:用户“sa”登录失败。(MicroSoft Sql Server,错误:18456)
18456错误: 在安装的时候如果选择的身份验证模式为:Window身份验证模式,就会出现18456的错误. 解决方案: 使用windows身份验证登录之后,在下面红框上单击右键,点击属性: 点击属性 ...
- springboot项目maven报错 LoggerFactory is not a Logback LoggerContext but Logback is on the classpath. Either remove Logback
完整信息如下 SLF4J: Class path contains multiple SLF4J bindings.SLF4J: Found binding in [jar:file:/D:/deve ...
- Android requires compiler compliance level 5.0 or 6.0. Found '1.4' instead.解决方法
今天在eclipse里报这个错误: Android requires compiler compliance level 5.0 or 6.0. Found '1.4' instead. Please ...
- 如何调用别人提供的API?
1:一般使用聚合数据提供的API: 百度聚合数据,进入: 2:一般是有用户名的直接登录,没有用户名的先进行注册.在搜索框中输入你想查找的API方面的关键字:例如:有关健康的 点开任意一个,你将会看到: ...
- python loggin
一 日志级别 CRITICAL = 50 #FATAL = CRITICAL ERROR = 40 WARNING = 30 #WARN = WARNING INFO = 20 DEBUG = 10 ...
- Charles抓取https包
Android: 1.若滑动解锁,请先设置屏幕锁: 2.然后浏览器输入Charlesproxy.com/getssl,安装证书,出现安装证书提示,随便打个名称 比如Android,选择WLAN(这里A ...
- laravel框架一次请求的生命周期
第一件事所有的请求都会被web服务器(Apache/Nginx)导向public/index.php文件.index.php文件载入Composer生成的自动加载设置,然后从bootstrap/app ...
- 如何将service绑入到spring 并且在action中使用
第一步:定制 service接口,为什么用接口我也不清楚 package com.inspur.services; import com.hsp.domain.User; public interfa ...
- bootstrap 中 css 与 javascript 的使用
1.css 1.1.选择器 1.2.子选择器: css 里的子元素用符号'>'表示.如下示例是表示拥有table样式的表盒,其thead元素内的tr元素如果有th的话,则应用该样式. .tabl ...
- 车站(NOIP1998)
题目链接:车站 这一题,首先你要会推导,推到出式子后,就会像我一样简单AC. 给一张图: 这里,t是第二个车站上车人数. 有什么规律? 其实很好找.有如下规律: 第x车站的人数增量为第x-2车站的上车 ...