参考文章
实现原理
本文几乎以最简化的方式来实现一种侧边栏效果,方便理解其原理,所以,只有tap手势过渡效果,并未实现pan的侧滑效果.
实现这种效果,要用容器控制器的概念.通过容器控制器中不同容器视图的切换,来实现.
实现的难点在于容器视图切换中,动画效果平缓自然.
容器视图切换的核心代码:
func setUpViewController(targetView: UIView, targetViewController: UIViewController?) {
if let viewController = targetViewController {
addChildViewController(viewController)
viewController.view.frame = targetView.bounds
targetView.addSubview(viewController.view)
viewController.didMoveToParentViewController(self)
}
}
func removeViewController(viewController: UIViewController?) {
if let _viewController = viewController {
_viewController.willMoveToParentViewController(nil)
_viewController.view.removeFromSuperview()
_viewController.removeFromParentViewController()
}
}
过渡动画的核心代码:
override func openLeft() {
leftVC?.beginAppearanceTransition(isLeftHidden(), animated: true)
openLeftWithVelocity(0)
}
func openLeftWithVelocity(velocity: CGFloat) {
let xOrigin: CGFloat = leftContainerView.frame.origin.x
let finalXOrigin: CGFloat = 0
var frame: CGRect = leftContainerView.frame
frame.origin.x = finalXOrigin
var duration: NSTimeInterval = Double(SlideMenuOptions.animationDuration)
if velocity != 0 {
duration = Double(fabs(xOrigin - finalXOrigin)/velocity)
duration = Double(fmax(0.1, fmin(1, duration)))
}
UIView.animateWithDuration(duration, delay: 0, options: UIViewAnimationOptions.CurveEaseIn, animations: { [weak self]() -> Void in
if let strongSelf = self {
strongSelf.leftContainerView.frame = frame
strongSelf.mainContainerView.transform = CGAffineTransformMakeScale(SlideMenuOptions.contentViewScale, SlideMenuOptions.contentViewScale)
}
}) { [weak self](Bool) -> Void in
if let strongSelf = self {
strongSelf.leftVC?.endAppearanceTransition()
}
}
}
override func closeLeft() {
leftVC?.beginAppearanceTransition(isLeftHidden(), animated: true)
closeLeftWithVelocity(0)
}
func closeLeftWithVelocity(velocity: CGFloat) {
let xOrigin: CGFloat = leftContainerView.frame.origin.x
let finalXOrigin: CGFloat = leftMinOrigin()
var frame: CGRect = leftContainerView.frame
frame.origin.x = finalXOrigin
var duration: NSTimeInterval = Double(SlideMenuOptions.animationDuration)
if velocity != 0 {
duration = Double(fabs(xOrigin - finalXOrigin)/velocity)
duration = Double(fmax(0.1, fmin(1, duration)))
}
UIView.animateWithDuration(duration, delay: 0, options: UIViewAnimationOptions.CurveEaseIn, animations: { [weak self]() -> Void in
if let strongSelf = self {
strongSelf.leftContainerView.frame = frame
strongSelf.mainContainerView.transform = CGAffineTransformMakeScale(1, 1)
}
}) { [weak self](Bool) -> Void in
if let strongSelf = self {
strongSelf.leftVC?.endAppearanceTransition()
}
}
}
func isPointContainedWithinLeftRect(point: CGPoint) -> Bool {
return CGRectContainsPoint(leftContainerView.frame, point)
}