说明:在Xcode7 beta5 中制作完成
-
创建一个Single View Application,填写相应信息,选择一个目录存储工程。
-
打开Main.storyboard,取消勾选Use Size Class,完成后设计视图的大小将会呈现iphone大小
-
在storyboard中选中View Controller,单击菜单栏上的Editor菜单,依次选择Embed In和Navigation Controller。
完成后如下所示
-
选中Navigation Bar,改变它的Bar Tint(可以省略不做)
完成后的效果图
-
导入要使用到的资源文件
单击Assets.xcassets文件夹,把要使用到的菜单图标拖放到图片资源框中。
完成后
-
拖放一个Bar Button Item到Navigation Bar上, 设置它的image属性。
完成后的效果图 -
从控件库中拖一个TableView到View Controller中,选中TableView,把它的Prototype Cells的数量设置为1,接着改变TableView的位置和大小。
-
展开TableView选中TableViewCell,设置它的identifier以及它的高度
-
再次选中TableView,给它增加约束。单击右下角的第3个按钮,给TableView增加如下约束(上边距和左边距为0)。这里把高度设置为544和宽度设置为80的原因是,每个菜单的大小为(80 x 80),导航栏的高度为64,一共有6个菜单,所以高度为544,宽度为80.
-
从控件库中拖一个ImageView到TableViewCell中,改变它的位置大小。
给ImageView添加约束并给它设置一个tag
-
打开辅助视图,会呈现storyboard和代码编辑区
-
选中TableView按住ctrl键,鼠标左键拖拽一个outlet到ViewController代码文件中。
接下来添加代码,一步一步实现侧滑菜单的功能
在viewDidLoad()方法上添加一个数组,用来存储菜单图标的名字。
let menuIcons = ["dribble-flat", "evernote-flat", "facebook-flat", "google-plus-flat", "pandora-flat", "phone-flat"]
让ViewController遵循UITableView的两个协议
class ViewController: UIViewController, UITableViewDataSource, UITableViewDelegate
此时编译器会报错,因为还没有实现必须的代理方法。现在实现必须的代理方法。
//设置TableViewCell的高度
func tableView(tableView: UITableView, heightForRowAtIndexPath indexPath: NSIndexPath) -> CGFloat {
return 80
}
// 设置TableView的行数
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return menuIcons.count
}
// 配置每个TableViewCell
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
// 1. 获取到可重用的cell
let cell = tableView.dequeueReusableCellWithIdentifier("menuCell") as UITableViewCell!
// 2. 拿到imageView
let menuImageView = cell.viewWithTag(715) as! UIImageView
// 3. 设置imageView的图片
menuImageView.image = UIImage(named: menuIcons[indexPath.row])
return cell
}
到此时为止,代码文件看起来应该类似这样。
import UIKit
//3. 遵循TableView的两个协议
class ViewController: UIViewController, UITableViewDataSource, UITableViewDelegate {
// 1. 拖拽生成tableview的outlet
@IBOutlet weak var menuTableView: UITableView!
// 2.菜单图标名数组
let menuIcons = ["dribble-flat", "evernote-flat", "facebook-flat", "google-plus-flat", "pandora-flat", "phone-flat"]
override func viewDidLoad() {
super.viewDidLoad()
}
// 4. 实现代理方法
// 设置TableViewCell的高度
func tableView(tableView: UITableView, heightForRowAtIndexPath indexPath: NSIndexPath) -> CGFloat {
return 80
}
// 设置TableView的行数
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return menuIcons.count
}
// 配置每个TableViewCell
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
// 1. 获取到可重用的cell
let cell = tableView.dequeueReusableCellWithIdentifier("menuCell") as UITableViewCell!
// 2. 拿到imageView
let menuImageView = cell.viewWithTag(715) as! UIImageView
// 3. 设置imageView的图片
menuImageView.image = UIImage(named: menuIcons[indexPath.row])
return cell
}
}
运行一下,看有什么效果
哇!只有一个空的列表。为什么会这样呢??因为还没有指定TableView的代理人是谁,那么TableView的代理就没有人在执行。现在给TableView指定代理人,在viewDidLoad()方法中添加两行代码。
menuTableView.dataSource = self
menuTableView.delegate = self
这两行代码的作用是,把menuTableView的代理人指定为当前的ViewController,那么当前的ViewController就会执行TableView的代理方法,为menuTableView提供数据以及对menuTableView的行为负责。
OK,再次运行,看下效果
还不错,菜单图标已经显示出来了!!
接下来,先用触发按钮来控制菜单的出现与隐藏...
首先在viewDidLoad()方法的下方添加以下代码,把菜单隐藏掉,这样程序启动完成后,就不会把菜单显示出来
override func viewDidAppear(animated: Bool) {
super.viewDidAppear(animated)
// 获取到所有显示的cell
let cells = menuTableView.visibleCells
// 把cell移动至可视区域外
for cell in cells {
cell.frame.origin = CGPoint(x: -80, y: cell.frame.origin.y)
}
}
在viewDidLoad()方法的上方添加一个菜单的状态标记,用来记录菜单的显示状态
//一开始菜单的状态为隐藏
var isShow = false
在最后一个花括号的上方,添加一个辅助函数,用来更改菜单的位置和状态,达到显示和隐藏的效果
func menuStateChange() {
let cells = menuTableView.visibleCells
//如果当前菜单的状态为隐藏,则让每个菜单显示出来
if isShow == false {
//改变每个cell的原点位置
for cell in cells {
cell.frame.origin = CGPoint(x: 0, y: cell.frame.origin.y)
}
}
else {
for cell in cells {
cell.frame.origin = CGPoint(x: -80, y: cell.frame.origin.y)
}
}
//改变菜单的显示状态
isShow = !isShow
}
接着在menuStateChange()的下方添加一个Action,这个Action将由导航栏上的按钮触发
// 触发或关闭菜单
@IBAction func trigger(sender: AnyObject) {
menuStateChange()
}
回到Storyboard中,让按钮关联这个Action. 选中Bar Button Item,按住ctrl键,鼠标左键拖拽至View Controller,在弹出菜单中选择trigger:
现在运行一下程序,可以发现用按钮控制菜单显示状态的目标完成啦。。。
接下来用手指的滑动来控制菜单的显示状态
First. 在代码文件中添加用手机滑动屏幕时会执行的Action
// 实现滑动手势,判断滑动方向是否与当前菜单状态吻合
@IBAction func swipe(gesture: UISwipeGestureRecognizer) {
// 往左滑关掉菜单
if gesture.direction == UISwipeGestureRecognizerDirection.Left && isShow == true {
menuStateChange()
}
else if gesture.direction == UISwipeGestureRecognizerDirection.Right && isShow == false {
menuStateChange()
}
}
ok, 回到storyboard,增加两个滑动手势识别器.从控件库中拖放一个Swipe Gesture Recognizer到View Controller中,让View Controller的view能够识别到滑动手势.
选中Swipe Gesture Recognizer,按住ctrl键,鼠标左键拖拽至View Controller,在弹出菜单中选择swipe:,让手势识别器关联到要执行的Action
运用相同的方法,再拖一个Swipe Gesture Recognizer到View Controller中,此时有一个地方要修改,因为滑动手势识别器的识别方向默认为向右滑. 选中刚添加的手势,修改它的识别方向. 同时将它与swipe Action关联。
运行程序,看下效果. 左右滑动可以控制菜单的显示状态,按钮也工作正常,两者没有冲突。
为了让菜单的隐藏与出现具有动态效果,现在给每一个菜单加一个动画.
修改menuStateChange()函数,添加动画效果.
func menuStateChange() {
let cells = menuTableView.visibleCells
//一个单位的延迟时间
let diff = 0.05
if isShow == false {
for cell in cells {
cell.frame.origin = CGPoint(x: -80, y: cell.frame.origin.y)
}
// 给每个cell增加动画
for i in 0.. Void in
cell.frame.origin = CGPoint(x: 0, y: cell.frame.origin.y)
},
completion: nil)
}
}
else {
for i in (0.. Void in
cell.frame.origin = CGPoint(x: -80, y: cell.frame.origin.y)
},
completion: nil)
}
}
isShow = !isShow
}
解释一下实现动画效果的代码
UIView.animateWithDuration(0.3, delay: Double(i+1) * diff,
options: UIViewAnimationOptions.CurveEaseIn,
animations: { () -> Void in
cell.frame.origin = CGPoint(x: 0, y: cell.frame.origin.y)
},
completion: nil)
第一个参数是每个Cell执行动画的时间,为0.3秒
第二个参数是动画的延迟时间,因为希望菜单一个接一个的出现,所以每个菜单都会比上一个菜单有一个单位时间的延迟
第三个参数是动画按指定速率变化曲线执行,这里的速率变化曲线为CurveEaseIn
第四个参数是要实现的动画效果,这里改变每个cell的原点位置,控制它的显示状态
第五个参数是动画结束后要执行的事情,这里为nil,表明什么都不做.
ok,侧滑菜单制作完了,运行看下效果吧!!
出现时的效果