ios制作简单侧滑菜单

说明:在Xcode7 beta5 中制作完成

  1. 创建一个Single View Application,填写相应信息,选择一个目录存储工程。


  2. 打开Main.storyboard,取消勾选Use Size Class,完成后设计视图的大小将会呈现iphone大小


  3. 在storyboard中选中View Controller,单击菜单栏上的Editor菜单,依次选择Embed In和Navigation Controller。



    完成后如下所示


  4. 选中Navigation Bar,改变它的Bar Tint(可以省略不做)



    完成后的效果图


  5. 导入要使用到的资源文件
    单击Assets.xcassets文件夹,把要使用到的菜单图标拖放到图片资源框中。



    完成后


  6. 拖放一个Bar Button Item到Navigation Bar上, 设置它的image属性。



    完成后的效果图
  7. 从控件库中拖一个TableView到View Controller中,选中TableView,把它的Prototype Cells的数量设置为1,接着改变TableView的位置和大小。


  8. 展开TableView选中TableViewCell,设置它的identifier以及它的高度


  9. 再次选中TableView,给它增加约束。单击右下角的第3个按钮,给TableView增加如下约束(上边距和左边距为0)。这里把高度设置为544和宽度设置为80的原因是,每个菜单的大小为(80 x 80),导航栏的高度为64,一共有6个菜单,所以高度为544,宽度为80.


  10. 从控件库中拖一个ImageView到TableViewCell中,改变它的位置大小。



    给ImageView添加约束并给它设置一个tag


  11. 打开辅助视图,会呈现storyboard和代码编辑区


  12. 选中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..<cells.count {
                
                let cell = cells[i]
                
               //动画效果
                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)
            }
            
        }
        else {

            for i in (0..<cells.count).reverse() {
                let cell = cells[i]
                UIView.animateWithDuration(0.3, delay: Double(6 - i) * diff,
                    options: UIViewAnimationOptions.CurveEaseIn,
                    animations: { () -> 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,侧滑菜单制作完了,运行看下效果吧!!

出现时的效果


最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,324评论 5 476
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,303评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,192评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,555评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,569评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,566评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,927评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,583评论 0 257
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,827评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,590评论 2 320
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,669评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,365评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,941评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,928评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,159评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,880评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,399评论 2 342

推荐阅读更多精彩内容

  • 1.badgeVaule气泡提示 2.git终端命令方法> pwd查看全部 >cd>ls >之后桌面找到文件夹内容...
    i得深刻方得S阅读 4,628评论 1 9
  • 发现 关注 消息 iOS 第三方库、插件、知名博客总结 作者大灰狼的小绵羊哥哥关注 2017.06.26 09:4...
    肇东周阅读 12,016评论 4 62
  • WebSocket-Swift Starscream的使用 WebSocket 是 HTML5 一种新的协议。它实...
    香橙柚子阅读 23,686评论 8 183
  • 香山红叶,只装扮你的浪漫。 也许有一天我们必须陌生, 那么请你在我的肩上, 留下所有的不幸。 像云彩一样, 静静的...
    流浪先森cc阅读 226评论 0 1
  • 早餐粉,中餐馒头,晚餐油条加油饼。疯了。明天一定长两斤。吃油饼的时候,想着吃了再吐出来,去催吐的时候,可能是因为肚...
    狂奔的阿肥阅读 317评论 0 0