作者:Simon NG,时间:2016/7/29
翻译:BNCoding, 如有错误欢迎指出。原文链接

导航是用户交互的一个重要组成部分,有很多种方式提供一个菜单栏让用户来自由切换想访问的功能。在之前的教程中我们介绍了其中的一种就是侧滑栏。下拉菜单则是另一种常用的菜单设计。当用户点击菜单按键的是时候主屏幕中下拉显示出菜单选项。如果你不知道下拉菜单是如何实现的话,不需要忧虑。继续阅读文章马上你就能看见一个演示动画。

在展示下拉菜单的实现之前,这篇文章已经假设你对自定义视图切换有一定的了解。如果你对这个视图切换有关的内容不太熟悉的话,那么你可以先去看下Joyce写的这篇文章

好了现在进入正题。

下拉菜单功能的开始演示

在这篇教程中我们会用Swift语言来实现下拉菜单,下面就是最终效果的一个快速展示:

工程模版

和以往一样,我不希望你从头开始,你可以先去下载起始工程。该起始工程里面包含了storyboard和一些view controller的类。你可以找到两个tableview,其中一个用于主屏幕(嵌在导航控制器中),另一个用于导航菜单。如果你运行程序的话,主页会展示一些虚拟的数据。

再继续下一步之前,我们先花点时间去浏览一些工程熟悉一下代码。

模态展示菜单视图

首先,我们打开Main.storyboard文件,找到里面的两个tableview,因为两者还没有进行segue链接。为了让用户点击menu按键的时候能够展示出菜单,我们按住control键点击menu按键拖动到菜单的tableview。松开按键,在action segue里面选择”present modally“。

如果你现在运行app的话,菜单界面会以模态的形式展现出来。为了退出下拉菜单视图,我们添加一个unwind segue

打开NewsTableViewController.swift文件,然后添加一个unwind action方法:

@IBAction func unwindToHome(segue: UIStoryboardSegue) {
    let sourceController = segue.sourceViewController as! MenuTableViewController
    self.title = sourceController.currentItem
}

接下来,我们回到storyboard,按住control键链接Menutableview中的prototype cellexit图标,在selection segue选项下面选择unwindToHome

如果用户现在点击任意一个菜单的话,那么当前视图会消失而主视图将会呈现出来。通过unwindToHome函数,主视图控制器(即NewsTableViewController)会根据用户选择的菜单相应的改变其标题。为了简单其间我们除了标题我们不会修改主视图中的内容。

除此之外,我们还将设置当前的选中项为白色。在实现这些希望的结果之前我们还要实现一系列的函数方法。

将下面的函数插入到MenuTableViewController类里面:

override func prepareForSegue(segue: UIStoryboardSegue,sender: AnyObject?) {
let menuTableViewController = segue.sourceViewController as! MenuTableViewController
if let selectedRow = menuTableViewController.tableView.indexPathForSelectedRow()?.row {
currentItem = menuItems[selectedRow]
}
}

在新版本的Swift中上面的代码编译无法通过,后面我会将附上自己修改后的完整代码

这个函数里面我们只是正确设置了当前选择的菜单。

NewsTableViewController.swift文件里面插入下面这个函数,该函数会将当前的标题传递给menu controller。

override func prepareForSegue(segue: UIStoryboardSegue,sender: AnyObject?) {
let menuTableViewController = segue.destinationViewController as! MenuTableViewController
menuTableViewController.currentItem = self.title!
}

现在编译并运行程序的话,当你点击菜单按键的时候菜单选择视图会模态的出现,当你选择其中的一个菜单项的时候程序会回到主视图并且相应的修改主视图标题。

创建带动画过渡的下了菜单

当前的菜单视图示使用系统标准的动画进行转场的,现在我们需要创建一个自定义的转场动画。正如我在之前的文章中介绍的那样,自定义视图控制器的转场动画的核心是动画对象,该对象同时遵守UIViewControllerAnimatedTransitioningUIViewControllerTransitioningDelegate协议。我们将会在类中使用这两者来实现动画转场,但是在此之前我们我们先来看看下拉菜单是怎么工作的。当用户点击菜单按键的时候,主视图会慢慢的往下面移动直到它到达指定的位置,也就是视图底部在往下180个单位。

创建下拉菜单动画

为了实现下拉菜单的动画效果,我们会创建一个名为MenuTransitionManager动画管理器。在工程导航中右击创建一个新文件。文件中的创建一个NSObject的子类MenuTransitionManager

类的代码如下:

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
}

}

该类同时遵循了UIViewControllerAnimatedTransitioningUIViewControllerTransitioningDelegate协议。因为以前的文章中已经介绍了,这里我就不会讲解其中的细节了。我们仔细查看其中的animation block(例如animateTransition方法)。

参考之前显示过程,在整个转场动画其间main viewfromViewmenu viewtoView

为了实现我们要的效果,我们配置了两个转场动画。第一个是向下移动main view,另一个则是上移menu view这样当该视图回到原先的位置的时候可以再次响应事件并进行动画转场。稍后运行程序的时候就明白我的意思了。

从iOS7开始,你可以通过UIView-Snapshotting API快速、简单的创建一个轻量级的视图快照。

snapshot = fromView.snapshotViewAfterScreenUpdates(true)

通过调用snapshotViewAfterScreenUpdates函数,你就获得的main view的快照了。有了快照之后,我们就可以在动画转场的容器里添加该快照了。该快照在menu view之后添加以保证该快照在容器的最顶部。

菜单视图的出场动画的实现其实很简单。我们仅仅在主视图的snapshot上面使用moveDown转场将菜单栏视图设置为默认位置。

self.snapshot?.transform = moveDown
toView.transform = CGAffineTransformIdentity

当菜单栏消失的时候采取的动作是相反的。主视图向上滑动并且恢复到默认的位置。另外我们会将快照移出这样真正的主视图就会展现出来。

现在我们打开NewsTableViewController.swift文件并声明一个MenuTransitionManager对象:

var menuTransitionManager = MenuTransitionManager()

prepareForSegue方法里面添加一行代码设置好该动画委托对象。

现在编译运行代码,点击菜单按键你就能看见一个下拉的菜单栏视图了。

检查用户的手势

到现在为止我们只能通过选择某一个菜单选项来使菜单栏视图消失。从用户的角度来考虑的话,其实点击主视图的快照该菜单栏视图也应该消失。但是主视图的快照是没有进行响应的。

事实上snapshot也是一个UIView对象,所以我们可以创建一个UITapGestureRecognizer对象并且将其添加到snapshot上。

当我们对UITapGestureRecognizer对象进行初始化的时候,我们需要传递目标对象和需要被调用的函数名。很明显你可以硬编码一个特定的对象来让菜单栏视图消失,但是为了我们的设计更加的灵活我们声明一个协议对象,并且让委托对象实现该协议中的方法。

MenuTransitionManager.swift里面,我们如下声明该协议:

@objc protocol MenuTransitionManagerDelegate {
func dismiss()
}

在这里我们定义了一个MenuTransitionManagerDelegate协议,该协议里面还有一个必须要实现的方法。委托对象必须实现dismiss()方法来完成逻辑上的视图消失操作。

MenuTransitionManager类里面,声明一个委托变量:

var delegate:MenuTransitionManagerDelegate?

然后需要处理该点击事件的对象将会被设置为委托对象。

最后,我们需要创建一个UITapGestureRecognizer对象并且添加多snapshot中。一个好的解决方法就是在snapshot变量中使用didset方法。我们将snapshot定义声明进行修改:

var snapshot:UIView? {
didSet {
if let _delegate = delegate {
let tapGestureRecognizer = UITapGestureRecognizer(target: _delegate,action: "dismiss")
snapshot?.addGestureRecognizer(tapGestureRecognizer)
}
}
}

属性观察器(Property observer)是Swift中一个非常强大的特性。在设置属性的值的时候观察器(willSet/didSet)都将会被调用。该特性让我们在变量赋值的前后都可以很方便的立刻采取一些特定的操作。willSet方法会在属性值赋值设置之前立刻被调用,而didSet方法会在属性值赋值设置完成后立刻被调用。

在上面的代码中,我们在属性观察器方法中创建了一个UITapGestureRecognizer对象并且将它添加给了snapshot。所以,每次我们对snapshot变量进行赋值之后都会立马配置一个UITapGestureRecognizer对象。

大部分的工作都差不多完成了。现在我们回到NewsTableViewController.swift中设置该类遵循MenuTransitionManagerDelegate协议并且实现里面的方法。

首先,我们如下修改相关的声明:

class NewsTableViewController: UITableViewController,MenuTransitionManagerDelegate

接下来我们实现其中的方法:

func dismiss() {
dismissViewControllerAnimated(true,completion: nil)
}

在上面的代码中,我们使用dismissViewControllerAnimated方法来将退出当前的视图。

最后,我们在NewsTableViewController类的prepareForSegue方法中添加一行代码来设置委托对象:

self.menuTransitionManager.delegate = self

任务完成,现在你编译运行程序并点击主视图的snapshot的话,菜单栏视图将会消失。

通过自定义的视图转换动画,你可以大大的提高用户的体验让你的应用脱颖而出。下拉菜单栏紧急是一个示例而已,在你自己的下一个应用中你可以做出自己的动画实现。

为了读者进行参照,你可以下载完整的代码

因为教程的编写的时间较早以及Swift版本的更迭,文章的部分代码已经不在适用或者部分代码有更好的方法来实现。附上我的代码。

使用视图控制器的切换创建下拉菜单栏的更多相关文章

  1. HTML5单选框、复选框、下拉菜单、文本域的实现代码

    这篇文章主要介绍了HTML5单选框、复选框、下拉菜单、文本域的实现代码,本文通过实例代码给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下

  2. Swift下拉菜单动画实现

    本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容,请发送邮件至dio@foxmail.com举报,一经查实,本站将立刻删除。

  3. 使用视图控制器的切换创建下拉菜单栏

    下拉菜单则是另一种常用的菜单设计。当用户点击菜单按键的是时候主屏幕中下拉显示出菜单选项。如果你不知道下拉菜单是如何实现的话,不需要忧虑。在展示下拉菜单的实现之前,这篇文章已经假设你对自定义视图切换有一定的了解。下拉菜单功能的开始演示在这篇教程中我们会用Swift语言来实现下拉菜单,下面就是最终效果的一个快速展示:工程模版和以往一样,我不希望你从头开始,你可以先去下载起始工程。

  4. Swift 类似美团下拉菜单

    本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容,请发送邮件至dio@foxmail.com举报,一经查实,本站将立刻删除。

  5. android – 如何在Evernote应用程序中制作这样的下拉菜单?

    单击操作栏中的中间图标时,会出现一个下拉菜单:我如何制作其中一个?

  6. android – WebView / Phonegap更改选择(下拉菜单)样式

    本机选择如下所示:解决方法没有办法实现这一点.您需要做的是构建一个本机插件,当您点击时才会打开一个自定义对话框.您要摆脱的下拉菜单是用于在网络浏览上选择的默认视图,而与Chrome中内置的第二个相反.帮助您开始://获取所有选项并存储在数组中//本机函数获取选项并显示一个对话框确保将您的主题设置为Holo或Holo.Light,您可以选择,并且只要点击select元素,就可以从javascript层调用本机代码.

  7. vue实现下拉菜单效果

    这篇文章主要为大家详细介绍了vue实现下拉菜单效果,运用了hover显示与隐藏以及定位,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下

  8. JavaScript实现网页下拉菜单效果

    这篇文章主要为大家详细介绍了JavaScript实现网页下拉菜单效果,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下

  9. react实现移动端下拉菜单的示例代码

    这篇文章主要介绍了react实现移动端下拉菜单的示例代码,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧

  10. 更换select下拉菜单背景样式的实现代码

    更换select下拉菜单背景样式的实现代码,需要的朋友可以参考下。

随机推荐

  1. Swift UITextField,UITextView,UISegmentedControl,UISwitch

    下面我们通过一个demo来简单的实现下这些控件的功能.首先,我们拖将这几个控件拖到storyboard,并关联上相应的属性和动作.如图:关联上属性和动作后,看看实现的代码:

  2. swift UISlider,UIStepper

    我们用两个label来显示slider和stepper的值.再用张图片来显示改变stepper值的效果.首先,这三个控件需要全局变量声明如下然后,我们对所有的控件做个简单的布局:最后,当slider的值改变时,我们用一个label来显示值的变化,同样,用另一个label来显示stepper值的变化,并改变图片的大小:实现效果如下:

  3. preferredFontForTextStyle字体设置之更改

    即:

  4. Swift没有异常处理,遇到功能性错误怎么办?

    本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容,请发送邮件至dio@foxmail.com举报,一经查实,本站将立刻删除。

  5. 字典实战和UIKit初探

    ios中数组和字典的应用Applicationschedule类别子项类别名称优先级数据包contactsentertainment接触UIKit学习用Swift调用CocoaTouchimportUIKitletcolors=[]varbackView=UIView(frame:CGRectMake(0.0,0.0,320.0,CGFloat(colors.count*50)))backView

  6. swift语言IOS8开发战记21 Core Data2

    上一话中我们简单地介绍了一些coredata的基本知识,这一话我们通过编程来实现coredata的使用。还记得我们在coredata中定义的那个Model么,上面这段代码会加载这个Model。定义完方法之后,我们对coredata的准备都已经完成了。最后强调一点,coredata并不是数据库,它只是一个框架,协助我们进行数据库操作,它并不关心我们把数据存到哪里。

  7. swift语言IOS8开发战记22 Core Data3

    上一话我们定义了与coredata有关的变量和方法,做足了准备工作,这一话我们来试试能不能成功。首先打开上一话中生成的Info类,在其中引用头文件的地方添加一个@objc,不然后面会报错,我也不知道为什么。

  8. swift实战小程序1天气预报

    在有一定swift基础的情况下,让我们来做一些小程序练练手,今天来试试做一个简单地天气预报。然后在btnpressed方法中依旧增加loadWeather方法.在loadWeather方法中加上信息的显示语句:运行一下看看效果,如图:虽然显示出来了,但是我们的text是可编辑状态的,在storyboard中勾选Editable,再次运行:大功告成,而且现在每次单击按钮,就会重新请求天气情况,大家也来试试吧。

  9. 【iOS学习01】swift ? and !  的学习

    如果不初始化就会报错。

  10. swift语言IOS8开发战记23 Core Data4

    接着我们需要把我们的Rest类变成一个被coredata管理的类,点开Rest类,作如下修改:关键字@NSManaged的作用是与实体中对应的属性通信,BinaryData对应的类型是NSData,CoreData没有布尔属性,只能用0和1来区分。进行如下操作,输入类名:建立好之后因为我们之前写的代码有些地方并不适用于coredata,所以编译器会报错,现在来一一解决。

返回
顶部