Slide Menu 側滑選單
新增2 個UIViewController
manvc.swift
import UIKit class mainvc: UIViewController { override func viewDidLoad() { super.viewDidLoad() // 背景顏色為藍色 view.backgroundColor = .blue } override func didReceiveMemoryWarning() { super.didReceiveMemoryWarning() // Dispose of any resources that can be recreated. } }
menu.vc
import UIKit class menuvc: UIViewController, UITableViewDelegate, UITableViewDataSource { var tableview = UITableView() var names = ["Bill", "John", "Harry", "Alex", "Jenny", "Arno", "Bert", "Chad", "Dave", "Eden"] let WIDTH = UIScreen.main.bounds.size.width let HEIGHT = UIScreen.main.bounds.size.height override func viewDidLoad() { super.viewDidLoad() view.backgroundColor = .darkGray tableview = UITableView(frame: CGRect(x: 0, y: 0, width: WIDTH, height: HEIGHT), style: .plain) tableview.delegate = self tableview.dataSource = self tableview.register(UITableViewCell.self, forCellReuseIdentifier: "cell") tableview.backgroundColor = .clear tableview.separatorStyle = .singleLine tableview.separatorColor = .white tableview.separatorInset = UIEdgeInsetsMake(0, 0, 0, 10) tableview.indicatorStyle = .white tableview.tableFooterView = UIView(frame: .zero) view.addSubview(tableview) } func numberOfSections(in tableView: UITableView) -> Int { return 1 } func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { return names.count } func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { var cell = tableView.dequeueReusableCell(withIdentifier: "cell") if cell == nil { cell = UITableViewCell(style: .default, reuseIdentifier: "cell") } cell?.textLabel?.text = "\(names[indexPath.row])" cell?.textLabel?.textColor = .white cell?.backgroundColor = .clear return cell! } func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) { tableView.deselectRow(at: indexPath, animated: true) } override func didReceiveMemoryWarning() { super.didReceiveMemoryWarning() // Dispose of any resources that can be recreated. } }
ViewController.swift
- 宣告資料
var main: mainvc! var menu: menuvc! let WIDTH = UIScreen.main.bounds.size.width let HEIGHT = UIScreen.main.bounds.size.height // 新增表示menu 狀態 enum menustate { case off case on } // 預設menu 狀態 var state = menustate.off // menu 展開後寬度 let move: CGFloat = UIScreen.main.bounds.size.width - 80
- 在viewDidLoad 設定初始畫面
view.backgroundColor = .lightGray main = mainvc() main?.view.frame = CGRect(x: 0, y: 20, width: WIDTH, height: HEIGHT) view.addSubview(main.view) // 加入觸發滑動動作 let pan = UIPanGestureRecognizer(target: self, action: #selector(slideon)) view.addGestureRecognizer(pan) // 加入觸發點選動作 let tap = UITapGestureRecognizer(target: self, action: #selector(tapon)) main.view.addGestureRecognizer(tap)
- 建立觸發滑動動作
func slideon(_ recognizer: UIPanGestureRecognizer) { switch recognizer.state { // 滑動開始 case .began: // menu 狀態off if state == .off { // 建立menu addmenu() // 建立陰影 addshadow(true) } // 滑動改變 case .changed: // 記錄滑動數值 var x = CGFloat() // menu 狀態on if state == .on { // 右向左滑, 位置為move 時禁止右滑 x = recognizer.translation(in: view).x < 0 ? move + recognizer.translation(in: view).x : move } else { // 左向右滑, 位置為move 時禁止右滑 x = (main?.view.frame.origin.x)! < move ? recognizer.view!.frame.origin.x + recognizer.translation(in: view).x : move } // main 位置為0 時禁止左滑 main?.view.frame.origin.x = x < 0 ? 0 : x // main 位置為0 時menu 可見度為0 menu?.view.alpha = x < 0 ? 0 : 1.5 * x / move // 滑動停止(放手) case .ended: let half = (main?.view.center.x)! > WIDTH // half 大於WIDTH, 滑動狀態回傳true slidestatus(half) // half 大於WIDTH, 建立陰影 addshadow(half) default: break } }
- 加入觸發點選動作
func tapon(_ recognizer: UITapGestureRecognizer) { // menu 狀態on if state == .on { // 滑動狀態回傳false slidestatus(false) } }
- 加入建立menu 動作
func addmenu() { if menu == nil { menu = menuvc() menu?.view.frame = CGRect(x: 0, y: 20, width: move, height: HEIGHT - 20) // 放置於main 下方 view.insertSubview((menu?.view)!, at: 0) } }
- 加入建立陰影動作
func addshadow(_ on: Bool) { if on { main.view.layer.shadowOpacity = 1 main.view.layer.shadowOffset = CGSize(width: -2, height: 1) } else { main.view.layer.shadowOpacity = 0 } }
- 建立滑動狀態動作
func slidestatus(_ on: Bool) { // 滑動狀態為true if on { // menu 狀態on state = .on // main 移動至move(distance 回傳move) mainslide(move) } else { // main 移動至0(distance 回傳0) mainslide(0) { finished in // menu 狀態off self.state = .off // 移除menu self.menu?.view.removeFromSuperview() // 釋放內存 self.menu = nil } } }
- 建立移動動作
下載完整範例 OneDrivefunc mainslide(_ distance: CGFloat, completion: ((Bool) -> Void)! = nil) { UIView.animate(withDuration: 0.3, delay: 0, usingSpringWithDamping: 1.0, initialSpringVelocity: 0, options: UIViewAnimationOptions(), animations: { self.main?.view.frame.origin.x = distance }, completion: completion) }