项目模板
你可以从这里下载最初的项目模板下载项目模板。现在的这个项目中包括storyboard和视图控制器类,一个是main screen,另一个是导航菜单。当你下载并运行程序的时候,你会看见一个有模型数据的主界面。
在开始之前,请花一些时间来熟悉一下这个工程。
现在开始实现
当你打开Main.stroyboard文件的时候,你会看到两个tableView Controllers,当然,现在还没有看到任何利用segue实现的链接。为了实现我们想要的效果,参照下图实现动作,选择"present modally"这个动作segue 如果,现在运行这个工程,这个菜单将会modal出来,为了能够dismiss这个菜单,我们需要添加一个unwind segue.
打开NewsTableViewController.swift文件,然后插入unwind动作方法
@IBAction func unwindToHome(segue: UIStoryboardSegue) {
let sourceController = segue.sourceViewController as! MenuTableViewController
self.title = sourceController.currentItem
}
下一步,到storyboard中,找到Menu table view controller 中的prototype cell然后联线到控制器右上角的exit。然后在segue选项中选择unwidToHome:选项,如下图 直到现在,当用户点击Menu item,这个菜单控制器就会dismiss出main screen。通过unwindToHome:这个方法,用户可以在选择menu item和改变标题的时候,回到主菜单。但是,为了保持简单,我们不想通过改变navigation bar的标题来世现弹出main screen 的内容。
另外,我们来一起实现,在选择item的时候实现高亮,那么我们就要实现下面的方法。 在MenuTableViewController类中插入下面的方法
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
let menuTableViewController = segue.sourceViewController as! MenuTableViewController
if let selectedRow = menuTableViewController.tableView.indexPathForSelectedRow()?.row {
currentItem = menuItems[selectedRow]
}
}
到这里,我们只是设置了正在选择的menu item。在NewsTableViewController.swift中添加下面的代码,
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
let menuTableViewController = segue.destinationViewController as! MenuTableViewController
menuTableViewController.currentItem = self.title!
}
现在运行代码,点击menu item,你可以看到弹出菜单控制器,当你选择其中的选项,你可以看到dismiss菜单,并且会出现一个新的标题和新的控制器。如下图:
创建Slide Down menu动画
动画的基本形式可以参考下面图片的样式 e
开始创建动画
在xcode 中新建一个类,名称叫做MenuTransitionManager继承自NSObject.
添加如下代码:
class MenuTransitionManager: NSObject,UIViewControllerAnimatedTransitioning,UIViewControllerTransitioningDelegate {
var duration = 0.5
var isPresenting = false
var snapshot:UIView?
func transitionDuration(transitionContext: UIViewControllerContextTransitioning) -> NSTimeInterval {
return duration
}
func animateTransition(transitionContext: UIViewControllerContextTransitioning) {
// Get reference to our fromView, toView and the container view
let fromView = transitionContext.viewForKey(UITransitionContextFromViewKey)!
let toView = transitionContext.viewForKey(UITransitionContextToViewKey)!
// Set up the transform for sliding
let container = transitionContext.containerView()
let moveDown = CGAffineTransformMakeTranslation(0, container.frame.height - 150)
let moveUp = CGAffineTransformMakeTranslation(0, -50)
// Add both views to the container view
if isPresenting {
toView.transform = moveUp
snapshot = fromView.snapshotViewAfterScreenUpdates(true)
container.addSubview(toView)
container.addSubview(snapshot!)
}
// Perform the animation
UIView.animateWithDuration(duration, delay: 0.0, usingSpringWithDamping: 0.9, initialSpringVelocity: 0.3, options: nil, animations: {
if self.isPresenting {
self.snapshot?.transform = moveDown
toView.transform = CGAffineTransformIdentity
} else {
self.snapshot?.transform = CGAffineTransformIdentity
fromView.transform = moveUp
} },
completion: {
finished in transitionContext.completeTransition(true)
if !self.isPresenting {
self.snapshot?.removeFromSuperview()
}
})
}
```
```
func animationControllerForDismissedController(dismissed: UIViewController) -> UIViewControllerAnimatedTransitioning? {
isPresenting = false
return self
}
```
func animationControllerForPresentedController(presented: UIViewController, presentingController presenting: UIViewController, sourceController source: UIViewController) -> UIViewControllerAnimatedTransitioning? {
isPresenting = true
return self
}
}
看到上面的代码,让我们专注于animation block (i.e. animateTransition 方法)这里主要包括主视图的from view 和to View。 创建这个动画,我们需要实现两个转场,前一个是用来实现向下移动菜单,另一个是实现向上移动菜单。你通过运行程序,以及接下来的介绍后明白我的意思的。 在iOS7以及之后的系统,你都可以使用UIView-Snapshotting API来快速并且简单的创建一个轻量级的View快照。
snapshot = fromView.snapshotViewAfterScreenUpdates(true)
实际的弹出菜单动画其实很简单,使用下面的代码就可以了
self.snapshot?.transform = moveDown
toView.transform = CGAffineTransformIdentity
当我们需要dismiss menu我们就需要做和上面相反的事情。 那么接下来,打开NewsTableViewController.swift 然后为MenuTransitionManager object声明一个变量
var menuTransitionManager = MenuTransitionManager()
在prepareForSegue方法中,添加下面的代码来实现和animation挂钩
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
let menuTableViewController = segue.destinationViewController as! MenuTableViewController
menuTableViewController.currentItem = self.title!
menuTableViewController.transitioningDelegate = self.menuTransitionManager
}
直到这里,你基本完成了这个项目。
点击手势
中间的都是一段废话,我们需要重点,那就是代码 在MenuTransitionmanager.swift中,定义一个协议
@objc protocol MenuTransitionManagerDelegate {
func dismiss ()
}
接下来,就我们需要去创建UITapGestureRecognizer object以及添加snapshot。在snapshot变量中我们声明didSet方法,修改方法如下
var snapshot:UIView? {
didSet {
if let _delegate = delegate {
let tapGestureRecognizer = UITapGestureRecognizer(target:_target, action:"dismiss")
snapshot?.addGestureRecognizer(tapGestureRecognizer)
}
}
}
属性观察是swift众多强悍的使用方法之一。观察(willSet/didSet)一个属性被设置的时间。这为我们提供了一个方便的方式立即之前或转让后,执行某些操作。该willSet方法被称为值存储权利之前,而didSet方法分配后,立即调用。
在上面的代码中,我们使用酒店的观察者来创建一个手势识别并将其设置为快照。所以我们每次分配快照变量中的对象的时候,它会立即用点击手势识别配置。
我们几乎完成。现在回到NewsTableViewController.swift ,来实现MenuTransitionManagerDelegate协议的类。
首先,更改类声明如下:
class NewsTableViewController: UITableViewController, MenuTransitionManagerDelegate
接下来实现:
func dismiss() {
dismissViewControllerAnimated(true, completion: nil)
}
这样,我们完成了一个叫做dismissViewControllerAnimated的方法来dismissView Controller。下面我们需要在prepareForSegue方法中添加NewsTableViewCotnroller类,设置代理
self.menuTransitionManager.delegate = self
到这里,我们就完成全部的代码了,