首页投稿(暂停使用,暂停投稿)iOS进阶指南Swifty Coding

左右侧滑菜单swift

2016-06-03  本文已影响1377人  乌黑的太阳
可以只传入左菜单参数,也可以只传入右菜单参数,也可以同时传入左右菜单,都支持。(先有oc版,再写的swift版)
HZSSliderController(centerViewController: UIViewController, leftViewController: UIViewController?, rightViewController: UIViewController?)

默认效果

sideMenu.gif

sideMovable = true

sideMenu1.gif

scaleEnable = true

sideMenu2.gif

sideMovable = true && scaleEnable = true

sideMenu3.gif
import UIKit

class HZSSliderController: UIViewController, UIGestureRecognizerDelegate {
    
    enum HZSSliderState {
        case Cener, Left, Right
    }
    
    //Public property
    private(set) var leftVC: UIViewController?
    private(set) var centerVC: UIViewController
    private(set) var rightVC: UIViewController?
    private(set) var state: HZSSliderState = .Cener
    var animationDuration: NSTimeInterval = 0.25
    var scaleEnable: Bool = false
    var scale: CGFloat = 0.85
    var sideMovable: Bool = false
    var recoverCenterClosure: (() -> Void)?
    var backgroundIMG: UIImage? {
        didSet {
            backgroundImgView.image = backgroundIMG
        }
    }
    //Private property
    private let backgroundImgView: UIImageView = UIImageView()
    private var touchAtLeft: Bool = false
    private var leftCenter: CGPoint = CGPointZero
    private var centerCenter: CGPoint = CGPointZero
    private var rightCenter: CGPoint = CGPointZero
    private var distanceFromLeft: CGFloat = 0
    private var centerButton: UIButton?
    private var enable_edge: CGFloat = 75
    private var screen_width: CGFloat {
        return UIScreen.mainScreen().bounds.size.width
    }
    private var mini_triggerDistance: CGFloat {
        return screen_width*0.2
    }
    private var max_moveDistance: CGFloat {
        return scaleEnable ? (screen_width - 90) : (screen_width - 70)
    }
    private var menu_begin: CGFloat {
        return sideMovable ? 60 : 0
    }
    
    //Public func
    init(centerViewController: UIViewController, leftViewController: UIViewController?, rightViewController: UIViewController?) {
        self.centerVC = centerViewController
        self.leftVC = leftViewController
        self.rightVC = rightViewController
        super.init(nibName: nil, bundle: nil)
    }
    
    func showLeftViewController(animated animated: Bool) -> Void {
        guard let left = leftVC else { return }
        
        view.window?.endEditing(true)
        left.view.hidden = false
        rightVC?.view.hidden = true
        let center = view.center
        UIView.animateWithDuration(animated ? animationDuration : 0, animations: { 
            left.view.center = center
            self.centerVC.view.center = CGPoint(x: center.x + self.max_moveDistance, y: center.y)
            if self.scaleEnable {
                self.centerVC.view.transform = CGAffineTransformMakeScale(self.scale, self.scale)
            }
            }) { (finished) in
                self.state = .Left
                self.rightVC?.view.center = CGPoint(x: center.x + self.menu_begin, y: center.y)
                self.addCenterButton()
                self.distanceFromLeft = self.max_moveDistance
        }
    }
    
    func showRightViewController(animated animated: Bool) -> Void {
        guard let right = rightVC else { return }
        
        view.window?.endEditing(true)
        leftVC?.view.hidden = true
        right.view.hidden = false
        let center = view.center
        UIView.animateWithDuration(animated ? animationDuration : 0, animations: { 
            right.view.center = center
            self.centerVC.view.center = CGPoint(x: center.x - self.max_moveDistance, y: center.y)
            if self.scaleEnable {
                self.centerVC.view.transform = CGAffineTransformMakeScale(self.scale, self.scale)
            }
            }) { (finished) in
                self.state = .Right
                self.leftVC?.view.center = CGPoint(x: center.x - self.menu_begin, y: center.y)
                self.addCenterButton()
                self.distanceFromLeft = -self.max_moveDistance
        }
    }
    
    func showCenterViewController(animated animated: Bool) -> Void {
        view.window?.endEditing(true)
        let center = view.center
        UIView.animateWithDuration(animated ? animationDuration : 0, animations: { 
            self.leftVC?.view.center = CGPoint(x: center.x - self.menu_begin, y: center.y)
            self.rightVC?.view.center = CGPoint(x: center.x + self.menu_begin, y: center.y)
            self.centerVC.view.center = center
            self.centerVC.view.transform = CGAffineTransformIdentity
            }) { (finished) in
                self.state = .Cener
                self.centerButton?.removeFromSuperview()
                self.centerButton = nil
                self.distanceFromLeft = 0
        }
    }
    
    func setCenterViewControllerWith(viewController: UIViewController, animated: Bool) -> Void {
        if centerVC == viewController { return }
        
        viewController.view.center = centerVC.view.center
        viewController.view.transform = centerVC.view.transform
        viewController.view.alpha = 0;
        addViewController(viewController)
        hideViewController(centerVC)
        centerVC = viewController
        UIView.animateWithDuration(animated ? animationDuration : 0, animations: { 
            viewController.view.alpha = 1.0
            }, completion: nil)
    }
    
    required init?(coder aDecoder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }
    
    override func viewDidLoad() {
        super.viewDidLoad()
        //backgroundIMG
        backgroundImgView.frame = view.bounds
        backgroundImgView.contentMode = .ScaleAspectFill
        backgroundImgView.autoresizingMask = [.FlexibleWidth, .FlexibleHeight]
        view.addSubview(backgroundImgView)
        
        //childView
        if let left = leftVC {
            self.addViewController(left)
            left.view.center = CGPoint(x: self.view.center.x - menu_begin, y: self.view.center.y)
        }
        if let right = rightVC {
            self.addViewController(right)
            right.view.center = CGPoint(x: self.view.center.x + menu_begin, y: self.view.center.y)
        }
        self.addViewController(centerVC)
        
        //panGesture
        let panGesture = UIPanGestureRecognizer(target: self, action: #selector(HZSSliderController.panHandler(_:)))
        panGesture.delegate = self
        view.addGestureRecognizer(panGesture)
    }
    
    func panHandler(gesture: UIPanGestureRecognizer) {
        guard leftVC != nil || rightVC != nil else { return }
        
        let xTranslation = gesture.translationInView(view).x
        distanceFromLeft += xTranslation
        gesture.setTranslation(CGPointZero, inView: view)
        
        switch gesture.state {
        case .Began:
            let startXPoint = gesture.locationInView(view).x
            if startXPoint <= enable_edge {
                touchAtLeft = true
            } else {
                touchAtLeft = false
            }
            view.window?.endEditing(true)
        case .Changed:
            if let left = leftVC {
                leftCenter = left.view.center
            }
            if let right = rightVC {
                rightCenter = right.view.center
            }
            centerCenter = centerVC.view.center
            
            switch state {
            case .Cener:
                if touchAtLeft && leftVC != nil {
                    movingAroundLeft()
                } else if touchAtLeft == false && rightVC != nil {
                    movingAroundRight()
                }
            case .Left:
                movingAroundLeft()
            case .Right:
                movingAroundRight()
            }
            if let left = leftVC {
                left.view.center = leftCenter
            }
            if let right = rightVC {
                right.view.center = rightCenter
            }
            centerVC.view.center = centerCenter
            
            //中间视图的缩放
            if scaleEnable && ((rightVC != nil && touchAtLeft == false) || (leftVC != nil && touchAtLeft == true)) {
                let localScale = (1 - abs(distanceFromLeft)/max_moveDistance) * (1 - scale) + scale
                centerVC.view.transform = CGAffineTransformMakeScale(localScale, localScale)
            }
        case .Ended:
            let velocity = gesture.velocityInView(view)
            switch state {
            case .Cener:
                if distanceFromLeft > mini_triggerDistance && velocity.x > 0{
                    showLeftViewController(animated: true)
                } else if distanceFromLeft < -mini_triggerDistance && velocity.x < 0 {
                    showRightViewController(animated: true)
                } else {
                    showCenterViewController(animated: true)
                }
            case .Left:
                if distanceFromLeft < max_moveDistance - mini_triggerDistance && velocity.x < 0 {
                    showCenterViewController(animated: true)
                } else {
                    showLeftViewController(animated: true)
                }
            case .Right:
                if distanceFromLeft > -max_moveDistance + mini_triggerDistance && velocity.x > 0 {
                    showCenterViewController(animated: true)
                } else {
                    showRightViewController(animated: true)
                }
            }
        default:
            return
        }
    }
    
    //MARK: Private method
    private func movingAroundLeft() {
        guard let left = leftVC else { return }
        
        left.view.hidden = false
        rightVC?.view.hidden = true
        if distanceFromLeft >= max_moveDistance {
            leftCenter = view.center
            centerCenter.x = view.center.x + max_moveDistance
            distanceFromLeft = max_moveDistance
        } else if distanceFromLeft <= 0 {
            leftCenter.x = -menu_begin
            centerCenter = view.center
            distanceFromLeft = 0
        } else {
            leftCenter.x = view.center.x - menu_begin + abs(distanceFromLeft/max_moveDistance) * menu_begin
            centerCenter.x = view.center.x + distanceFromLeft
        }
    }
    
    private func movingAroundRight() {
        guard let right = rightVC else { return }
        
        right.view.hidden = false
        leftVC?.view.hidden = true
        if distanceFromLeft <= -max_moveDistance {
            rightCenter.x = view.center.x
            centerCenter.x = view.center.x - max_moveDistance
            distanceFromLeft = -max_moveDistance
        } else if distanceFromLeft >= 0 {
            rightCenter.x = view.center.x + menu_begin
            centerCenter = view.center
            distanceFromLeft = 0
        } else {
            rightCenter.x = view.center.x + menu_begin + abs(distanceFromLeft/max_moveDistance) * -menu_begin
            centerCenter.x = view.center.x + distanceFromLeft
        }
    }
    
    private func addCenterButton() {
        if centerButton == nil {
            centerButton = UIButton(type: .System)
            centerButton?.backgroundColor = UIColor.clearColor()
            centerButton?.addTarget(self, action: #selector(HZSSliderController.centerButtonAction), forControlEvents: .TouchUpInside)
            view.addSubview(centerButton!)
        }
        centerButton?.frame = centerVC.view.frame
    }
func centerButtonAction() {
        showCenterViewController(animated: true)
        if let closure = recoverCenterClosure {
            closure()
        }
    }
    
    //MARK: viewController operate
    private func addViewController(viewController: UIViewController) {
        viewController.view.autoresizingMask = [.FlexibleWidth, .FlexibleHeight]
        self.addChildViewController(viewController)
        self.view.addSubview(viewController.view)
        viewController.didMoveToParentViewController(self)
    }
    
    private func hideViewController(viewController: UIViewController) {
        viewController.willMoveToParentViewController(nil)
        viewController.view.removeFromSuperview()
        viewController.removeFromParentViewController()
    }
    
    //MARK: UIGestureRecognizerDelegate
    func gestureRecognizer(gestureRecognizer: UIGestureRecognizer, shouldReceiveTouch touch: UITouch) -> Bool {
        if centerVC is UINavigationController {
            let nav = centerVC as! UINavigationController
            if nav.viewControllers.count > 1 { return false }
        }
        
        if gestureRecognizer is UIPanGestureRecognizer {
            let point = touch.locationInView(gestureRecognizer.view)
            if state == .Left {
                if point.x >= screen_width - enable_edge {
                    return true
                } else {
                    return false
                }
            } else if state == .Right {
                if point.x <= enable_edge {
                    return true
                } else {
                    return false
                }
            } else {
                if point.x >= enable_edge && point.x <= screen_width - enable_edge {
                    return false
                } else {
                    return true
                }
            }
        }
        return true
    }
}

extension UIViewController {
    var hzs_sliderController: HZSSliderController? {
        var iter = self.parentViewController
        while iter != nil {
            if iter is HZSSliderController {
                return iter as? HZSSliderController
            } else if iter?.parentViewController != nil && iter?.parentViewController != iter {
                iter = iter?.parentViewController
            } else {
                iter = nil
            }
        }
        return nil
    }
    
    func hzs_sliderControllerShowLeftViewController(animated animated: Bool) {
        self.hzs_sliderController?.showLeftViewController(animated: animated)
    }
    
    func hzs_sliderControllerShowRightViewController(animated animated: Bool) {
        self.hzs_sliderController?.showRightViewController(animated: animated)
    }
    
    func hzs_sliderControllerShowCenterViewController(animated animated: Bool) {
        self.hzs_sliderController?.showCenterViewController(animated: animated)
    }
    
    func hzs_sliderControllerSetCenterRecoverColsure(closure: () -> Void) {
        self.hzs_sliderController?.recoverCenterClosure = closure
    }
}
上一篇下一篇

猜你喜欢

热点阅读