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
          }
      }
    }
    
  • 建立移動動作
    func 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)
    }
    
    下載完整範例 OneDrive

results matching ""

    No results matching ""