效果展示:
新建工程和对应文件
首先建立iOS工程,工程名随意,选择Single View Application即可。
新建三个swift文件:
- 用于显示主页面的
mainViewController.swift
,继承UIViewController
。 - 用于显示左菜单的
leftTableViewController.swift
,继承UITableViewController
。 - 用于显示右菜单的
rightTableViewController.swift
,继承UITableViewController
。
那么现在我们左边的文件列表中有4个ViewController了:
ViewController.swift
,mainViewController.swift
,leftTableViewController.swift
,rightTableViewController.swift
。
第一步完成~
打造抽屉效果
首先在ViewController
类中建立其他三个要显示VC的对象:
var mainViewController:UINavigationController?
var leftViewController:LeftTableViewController?
var rightViewController:RightTableViewController?
在viewDidload
方法中加入:
//视图加载
self.leftViewController = LeftTableViewController()
self.view.addSubview((leftViewController?.view)!)
self.rightViewController = RightTableViewController()
self.view.addSubview((rightViewController?.view)!)
self.mainViewController = UINavigationController(rootViewController: MainViewController())
self.view.addSubview((mainViewController?.view)!)
为了方便和显示,mainViewController
我选择继承于NavigationController
。
至于为什么要先将左右VC加载到根视图后加载mainVC,后面我会说道。
然后在刚刚加入的代码下继续加入:
//隐藏左右视图
self.leftViewController?.view.hidden = true
self.rightViewController?.view.hidden = true
首先隐藏左右的视图。因为主视图始终显示在最上面,而左右的菜单显示在下面,难免出现叠加遮挡额度结果。为了不使两个菜单视图互相遮挡,我们选择显示哪个菜单的时候将哪个视图显示出来的方法。
为方便显示,给三个视图分别添加一个背景色。
这里我设置的:
mainViewController
的viewDIdLoad
中:
self.view.backgroundColor = UIColor.whiteColor()
leftViewController
的viewDIdLoad
中:
self.view.backgroundColor = UIColor.redColor()
rightViewController
的viewDIdLoad
中:
self.view.backgroundColor = UIColor.blackColor()
然后我们回到ViewController
类。
在刚刚//隐藏左右视图
的代码下添加一个手势:
//添加滑动手势
let pan = UIPanGestureRecognizer(target: self, action: #selector(ViewController.panAction(_:)))
self.mainViewController?.view.addGestureRecognizer(pan)
并在ViewController
类中新建一个panAction
方法:
func panAction(sender: UIPanGestureRecognizer){}
下面我们让屏幕获得手指的位置:
//获取手指位置
let point = sender.translationInView(sender.view)
这里我们的sender.view
其实就是我们的MainView
。
然后判断是左滑还是右滑。正常情况下,sender.view?.frame.origin.x
=0。
如果sender.view?.frame.origin.x <= 0
,那么我们就是向左滑,反之向右:
if sender.view?.frame.origin.x <= 0{
//向左滑
}else{
//向右滑
}
为了显示效果比较好,我们在ViewController
类中增加一个变量:
var speed_f:CGFloat?//滑动速率
并且在viewDidLoad
方法中给它赋值:
self.speed_f = 0.5//滑动速率
向左滑的时候,显示右边的菜单,左边的菜单不显示,并且mainView向左移动;向右滑的时候,显示左边的菜单,右边的菜单不显示,兵器mainView向右移动。
在//向左滑
下面添加:
sender.view?.center = CGPointMake((sender.view?.center.x)! + point.x * speed_f!, (sender.view?.center.y)!)//计算新的view的center位置
sender.setTranslation(CGPointMake(0, 0), inView: self.view)//矫正手指位置
self.leftViewController?.view.hidden = true
self.rightViewController?.view.hidden = false
在//向右滑
下面添加:
sender.view?.center = CGPointMake((sender.view?.center.x)! + point.x * speed_f!, (sender.view?.center.y)!)
sender.setTranslation(CGPointMake(0, 0), inView: self.view)//矫正手指位置
self.leftViewController?.view.hidden = false
self.rightViewController?.view.hidden = true
运行一下试试吧。两个抽屉都已经构建好了。
试试滑动一下,发现一个问题:这抽屉没有极限的,可以无限滑动。
下面我们来解决这个问题。
抽屉的滑动极限和回弹效果
我们的抽屉肯定是不能一直滑的,那么我们就需要给抽屉一个界限。
首先在ViewController
类中增加一个常量来表示界限值:
let mainVC_offset:CGFloat = 120//屏幕偏移极限
- 我这里设定的偏移是120。大家也可以自己更改一下这个数值看一下有什么效果~
然后我们在滑动方法中,判断一下手指离开屏幕的时候几个View的操作。
当sender.state == .Ended
,即手指离开屏幕的时候,我们判断离开的这个位置相对屏幕中的偏移量,如果偏移小就返回原来的位置,大于一定的界限就移动到下一个位置。
当然,我们需要在ViewController
类里增加一个变量:
var condition_f:CGFloat?//三视图显示条件
用于显示这个条件。并且在viewDidLoad
方法中给它赋值:
condition_f = 0//三视图显示条件
从屏幕中间线到我们设定的滑动极限位置,这个宽度就是MainView的移动距离。当低于这个距离的一半的时候我们认为滑动量少,返回原位置;大于这个值我们就认为滑动量大,可以移动到下一个位置。
在滑动方法
panAction
继续加入如下代码:
//手指离开屏幕
if sender.state == .Ended{
if self.condition_f > UIScreen.mainScreen().bounds.size.width * 0.5 * speed_f!{//右滑超过界限
self.showLeftView()
}else if self.condition_f < UIScreen.mainScreen().bounds.size.width * -0.5 * speed_f!{//左滑超过界限
self.showRightView()
}else{
self.showMainView()
}
}
并且在ViewController
类中增加这三个对应的方法:
//显示主View
func showMainView(){}
//显示左边菜单
func showLeftView(){}
//显示右边菜单
func showRightView(){}
在这三个方法里我们无非要做计算屏幕的偏移量,并且加上对应的动画效果使显示更加完善。
完善这三个方法:
func showMainView(){
//动画显示
UIView.beginAnimations(nil, context: nil)
//屏幕偏移计算
self.mainViewController?.view.center = CGPointMake(UIScreen.mainScreen().bounds.size.width / 2, UIScreen.mainScreen().bounds.size.height / 2)
//提交动画
UIView.commitAnimations()
}
func showLeftView(){
UIView.beginAnimations(nil, context: nil)
self.mainViewController?.view.center = CGPointMake(UIScreen.mainScreen().bounds.size.width * 1.5 - mainVC_offset, UIScreen.mainScreen().bounds.size.height / 2)
UIView.commitAnimations()
}
func showRightView(){
UIView.beginAnimations(nil, context: nil)
self.mainViewController?.view.center = CGPointMake(mainVC_offset - UIScreen.mainScreen().bounds.size.width / 2, UIScreen.mainScreen().bounds.size.height / 2)
UIView.commitAnimations()
}