左右侧滑菜单swift
2016-06-03 本文已影响1377人
乌黑的太阳
可以只传入左菜单参数,也可以只传入右菜单参数,也可以同时传入左右菜单,都支持。(先有oc版,再写的swift版)
HZSSliderController(centerViewController: UIViewController, leftViewController: UIViewController?, rightViewController: UIViewController?)
默认效果
sideMenu.gifsideMovable = true
sideMenu1.gifscaleEnable = true
sideMenu2.gifsideMovable = true && scaleEnable = true
sideMenu3.gifimport 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
}
}