利用转场动画实现slide down menu

项目模板

你可以从这里下载最初的项目模板下载项目模板。现在的这个项目中包括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

到这里,我们就完成全部的代码了,

全部文件代码

时间: 2024-11-15 21:01:06

利用转场动画实现slide down menu的相关文章

iOS 利用UIPresentationController自定义转场动画

1. 系统默认modal出来的动画效果默认是从屏幕底部爬出来的 - (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event{ secondVC *second = [[secondVC alloc] init];  [self presentViewController:second animated:YES completion:nil]; } 2. 想自定义转场动画,首先设置 展示样式 和 过渡代理 secondVC *s

利用手势控制动画的进度

最近在研究一个项目,利用手势控制动画的进度,发现简单的还可以,如果遇到了复杂的情况就比较麻烦了,ios7新出了一个特性,可以利用NavigationController的自定义转场动画,提供进度来控制. //这个方法控制转场动画的进度 - (id <UIViewControllerInteractiveTransitioning>)navigationController:(UINavigationController *)navigationController               

[转]Android Activity和Fragment的转场动画

Android Activity和Fragment的转场动画 Activity转场动画 Activity的转场动画是通过overridePendingTransition(int enterAnim, int exitAnim)实现的. 这个方法是API Level 5 加入的. 这个方法在startActivity(Intent) or finish()之后被调用,指定接下来的这个转场动画. 方法的第一个参数:enterAnim,是新的Activity的进入动画的resource ID: 第二

Android Activity和Fragment的转场动画

Activity转场动画 Activity的转场动画是通过overridePendingTransition(int enterAnim, int exitAnim)实现的. 这个方法是API Level 5 加入的. 这个方法在startActivity(Intent) or finish()之后被调用,指定接下来的这个转场动画. 方法的第一个参数:enterAnim,是新的Activity的进入动画的resource ID: 第二个参数exitAnim,是旧的Activity(当前的Acti

Android5.0之Activity的转场动画

Activity的转场动画很早就有,但是太过于单调,样式也不好看,于是Google在Android5.0之后,又推出的新的转场动画,效果还是非常炫的,今天我们一起来看一下. 1.旧转场动画回顾 首先我们还是先来看看在5.0之前如果我们想要在启动Activity时使用动画该怎么做呢? [java] view plain copy print? startActivity(new Intent(this, Main3Activity.class)); overridePendingTransitio

Activity Fragment转场动画

Activity转场动画 先介绍个动画的好例子:https://github.com/lgvalle/Material-Animations Activity的转场动画是通过overridePendingTransition(int enterAnim, int exitAnim)实现的. 这个方法是API Level 5 加入的. 这个方法在startActivity(Intent) or finish()之后被调用,指定接下来的这个转场动画. 方法的第一个参数:enterAnim,是新的Ac

自定义presentViewController的转场动画(Swift)

原创Blog,转载请注明出处 我的StackFlow 前言: iOS默认的presentViewController的切换动画是从底部推入,消失是从顶部推出.但是,因为iOS系统默认的是适配所有转场上下文的.而针对特定的转场上下文,我们能做出更好的效果. Tips:所谓的转场上下文,就是转场的开始View和结束View,以及对应的ViewController 目标效果 最终的效果 准备工作 首先写出一个CollectionView,每个Cell是一个图片,由于本文的核心是如何转场,所以Colle

UINavigationController 自定义转场动画(模仿淘宝App跳转)

制作目的 想要自定义系统转场动画速度 放弃不顺畅的 NavigationBar 隐藏消失 干脆直接干掉每个页面的 NavigationBar,在使用 UINavigationController 管理的同时,每个页面的 NavigationBar 都使用自定义的 UIView, 这样既定制程度高又可以在不需要 NavigationBar 的页面无缝对接,包括一些之前 NavigationBar 动画也可以更轻松的利用自定义的 UIView 的适配动画来更灵活的实现 实现功能 可以设置一个自己认为

高逼格Android转场动画

前言 转场动画在交互上非常有优势,本文从转场动画的使用场景和方法起,最后是实现掘金中用户头像的转场动画. 转场动画适用的版本 Activity transition APIs 只有在Android 5.0(API 21)或者更高的版本上能使用.所以在使用之前需要进行版本判断.当版本API 大于21时使用转场动画,否则不使用. // Check if we're running on Android 5.0 or higher if (Build.VERSION.SDK_INT >= Build.