Swift之导航条侧滑效果的实现

首先,我们在Main.storyboard中创建UINavgationController:
Swift之导航条侧滑效果的实现
文章图片
在Main.storyboard中创建导航控制器.png
创建MainViewController并与之关联,因为主要是实现侧滑效果,所以就不在MainViewController中搭界面了。
接下来我们在Main.storyboard中再拖一个UIViewController,并创建一个MenuViewController与之关联。然后在界面上搭建你自己喜欢的界面,我是这样搭建的:

Swift之导航条侧滑效果的实现
文章图片
MenuViewController.png
下面我们来上代码咯:
在ViewController中:

class ViewController: UIViewController {// 主页导航控制器 var mainNavigationController:UINavigationController!// 主页面控制器 var mainViewController:MainViewController!// 菜单页控制器 var menuViewController:MenuViewController?// 菜单页当前状态 var currentState = MenuState.Collapsed { didSet { //菜单展开的时候,给主页面边缘添加阴影 let shouldShowShadow = currentState != .Collapsed showShadowForMainViewController(shouldShowShadow: shouldShowShadow) } }// 菜单打开后主页在屏幕右侧露出部分的宽度 let menuViewExpandedOffset: CGFloat = 60// 侧滑菜单黑色半透明遮罩层 var blackCover: UIView?// 最小缩放比例 let minProportion: CGFloat = 0.77//MARK: - life cycle override func viewDidLoad() { super.viewDidLoad()//状态栏文字改成白色 UIApplication.shared.statusBarStyle = .lightContent; // 给根容器设置背景 let imageView = UIImageView(image: UIImage(named: "back")) imageView.frame = UIScreen.main.bounds self.view.addSubview(imageView)//初始化主视图 mainNavigationController = UIStoryboard(name: "Main", bundle: nil).instantiateViewController(withIdentifier: "mainNavigaiton") as! UINavigationController view.addSubview(mainNavigationController.view)//指定Navigation Bar左侧按钮的事件 mainViewController = mainNavigationController.viewControllers.first as! MainViewController mainViewController.navigationItem.leftBarButtonItem?.action = #selector(ViewController.showMenu)//添加拖动手势 let panGestureRecognizer = UIPanGestureRecognizer.init(target:self, action:#selector(handlePanGesture(recognizer:))) mainNavigationController.view.addGestureRecognizer(panGestureRecognizer)//单击收起菜单手势 let tapGestureRecognizer = UITapGestureRecognizer.init(target: self, action: #selector(ViewController.handlePanGesture as (ViewController) -> () -> ())) mainNavigationController.view.addGestureRecognizer(tapGestureRecognizer) } //MARK: - event response //导航栏左侧按钮事件响应 func showMenu() { //如果菜单是展开的则会收起,否则就展开 if currentState == .Expanded { animateMainView(shouldExpand: false) }else { addMenuViewController() animateMainView(shouldExpand: true) } }//拖动手势响应 func handlePanGesture(recognizer: UIPanGestureRecognizer) {switch(recognizer.state) { // 刚刚开始滑动 case .began: // 判断拖动方向 let dragFromLeftToRight = (recognizer.velocity(in: view).x > 0) // 如果刚刚开始滑动的时候还处于主页面,从左向右滑动加入侧面菜单 if (currentState == .Collapsed && dragFromLeftToRight) { currentState = .Expanding addMenuViewController() }// 如果是正在滑动,则偏移主视图的坐标实现跟随手指位置移动 case .changed: let screenWidth = view.bounds.size.width var centerX = recognizer.view!.center.x + recognizer.translation(in: view).x //页面滑到最左侧的话就不许要继续往左移动 if centerX < screenWidth/2 { centerX = screenWidth/2 }// 计算缩放比例 var proportion:CGFloat = (centerX - screenWidth/2) / (view.bounds.size.width - menuViewExpandedOffset) proportion = 1 - (1 - minProportion) * proportion// 执行视差特效 blackCover?.alpha = (proportion - minProportion) / (1 - minProportion)//主页面滑到最左侧的话就不许要继续往左移动 recognizer.view!.center.x = centerX recognizer.setTranslation(CGPoint.zero, in: view) //缩放主页面 recognizer.view?.transform = CGAffineTransform.identity.scaledBy(x: proportion, y: proportion)// 如果滑动结束 case .ended: //根据页面滑动是否过半,判断后面是自动展开还是收缩 let hasMovedhanHalfway = recognizer.view!.center.x > view.bounds.size.width animateMainView(shouldExpand: hasMovedhanHalfway) default: break } }//单击手势响应 func handlePanGesture() { //如果菜单是展开的点击主页部分则会收起 if currentState == .Expanded { animateMainView(shouldExpand: false) } } //MARK: - private methods // 添加菜单页 func addMenuViewController() { if (menuViewController == nil) { menuViewController = UIStoryboard(name: "Main", bundle: nil).instantiateViewController(withIdentifier: "menuView") as? MenuViewController// 插入当前视图并置顶 view.insertSubview(menuViewController!.view, belowSubview: mainNavigationController.view)// 建立父子关系 addChildViewController(menuViewController!) menuViewController!.didMove(toParentViewController: self)// 在侧滑菜单之上增加黑色遮罩层,目的是实现视差特效 blackCover = UIView(frame: CGRect(x: 0, y: 0, width: self.view.frame.size.width, height: self.view.frame.size.height)) blackCover!.backgroundColor = UIColor.black self.view.insertSubview(blackCover!, belowSubview: mainNavigationController.view) } }//主页自动展开、收起动画 func animateMainView(shouldExpand: Bool) { // 如果是用来展开 if (shouldExpand) { // 更新当前状态 currentState = .Expanded // 动画 let mainPosition = view.bounds.size.width * (1+minProportion/2) - menuViewExpandedOffset doTheAnimate(mainPosition: mainPosition, mainProportion: minProportion, blackCoverAlpha: 0) } else {// 如果是用于隐藏 // 动画 doTheAnimate(mainPosition: view.bounds.size.width/2, mainProportion: 1, blackCoverAlpha: 1) { finished in // 动画结束之后更新状态 self.currentState = .Collapsed // 移除左侧视图 self.menuViewController?.view.removeFromSuperview() // 释放内存 self.menuViewController = nil; // 移除黑色遮罩层 self.blackCover?.removeFromSuperview() // 释放内存 self.blackCover = nil; } } }//主页移动动画、黑色遮罩层动画 func doTheAnimate(mainPosition: CGFloat, mainProportion: CGFloat, blackCoverAlpha: CGFloat, completion: ((Bool) -> Void)! = nil) { //usingSpringWithDamping:1.0表示没有弹簧震动动画 UIView.animate(withDuration: 0.5, delay: 0, usingSpringWithDamping: 1.0, initialSpringVelocity: 0, options: .curveEaseInOut, animations: { self.mainNavigationController.view.center.x = mainPosition self.blackCover?.alpha = blackCoverAlpha // 缩放主页面 self.mainNavigationController.view.transform = CGAffineTransform.identity.scaledBy(x: mainProportion, y: mainProportion)}, completion: completion) }//给主页面边缘添加、取消阴影 func showShadowForMainViewController(shouldShowShadow: Bool) { if (shouldShowShadow) { //需要遮挡不投明度为0.8 mainNavigationController.view.layer.shadowOpacity = 0.8 } else { mainNavigationController.view.layer.shadowOpacity = 0.0 } } } // 菜单状态枚举 enum MenuState { case Collapsed// 未显示(收起) case Expanding// 展开中 case Expanded// 展开 }

在MenuViewController中:
class MenuViewController: UIViewController , UITableViewDelegate, UITableViewDataSource{let titlesDictionary = ["开通会员", "QQ钱包", "网上营业厅", "个性装扮", "我的收藏", "我的相册"]@IBOutlet weak var settingTableView: UITableView! //MARK: - life cycle override func viewDidLoad() { super.viewDidLoad()settingTableView.delegate = self settingTableView.dataSource = self settingTableView.tableFooterView = UIView()} //MARK: - TableViewDelegate // 处理点击事件 func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) { print(titlesDictionary[indexPath.row]) tableView.deselectRow(at: indexPath, animated: false) }func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { return titlesDictionary.count }func numberOfSectionsInTableView(tableView: UITableView) -> Int { return 1 }func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { let cell = tableView.dequeueReusableCell(withIdentifier: "menuViewCell", for: indexPath)cell.backgroundColor = UIColor.clear cell.textLabel!.text = titlesDictionary[indexPath.row]return cell } }

【Swift之导航条侧滑效果的实现】最终点击menu,实现如下效果:
Swift之导航条侧滑效果的实现
文章图片
最终实现效果.png
好啦,侧滑效果实现啦~~~

    推荐阅读