Плавная анимация ящика с помощью UIPanGestureRecognizer
Я потратил несколько дней, пытаясь получить плавную анимацию для пользовательского бокового ящика, который я сделал с помощью raywenderlich.com, но я не могу получить плавную анимацию, когда жест заканчивается на полпути (пользователь поднимает палец, не переходя на полную длину). жест).
состояние. закругленный код:
case .Ended:
if (leftViewController != nil) {
let velocityInX = recognizer.velocityInView(view).x
let currentX = recognizer.view!.frame.origin.x
if gestureIsDraggingFromLeftToRight {
let finalX = view.frame.width * (1 - targetRatio)
let hasMovedGreaterThanHalfway = recognizer.view!.center.x * 2 > view.bounds.size.width
let distance = finalX - currentX
let rawDuration = distance / velocityInX
let duration = rawDuration < 0.8 ? rawDuration : 0.8
let springVelocity = (currentX / (view.frame.width * (1 - targetRatio)))
animateLeftPanel(shouldExpand: hasMovedGreaterThanHalfway, velocity: springVelocity, duration: Double(duration))
} else {
let finalX: CGFloat = 0
let hasMovedGreaterThanHalfway = recognizer.view!.center.x / 2 > view.bounds.size.width
let distance = finalX - currentX
let rawDuration = fabs(distance / velocityInX)
let duration = rawDuration < 0.8 ? rawDuration : 0.8
let springVelocity = fabs(currentX / (view.frame.width * (1 - targetRatio)))
animateLeftPanel(shouldExpand: hasMovedGreaterThanHalfway, velocity: springVelocity, duration: Double(duration))
}
}
Код анимации:
func animateCenterPanelXPosition(targetPosition targetPosition: CGFloat, velocity: CGFloat, duration: Double, completion: ((Bool) -> Void)! = nil) {
UIView.animateWithDuration(duration, delay: 0, usingSpringWithDamping: 0.7, initialSpringVelocity: velocity, options: .CurveEaseOut, animations: {
self.centerNavigationController.view.frame.origin.x = targetPosition
}, completion: completion)
}
Вот полный код:
import UIKit
class ContainerViewController: UIViewController {
var isLeftDrawerExpanded = false {
didSet {
showShadowForCenterViewController(isLeftDrawerExpanded)
centerViewController.setUiButtonsEnabled(setEnabled: !isLeftDrawerExpanded)
}
}
// Target ratio for center VC when drawer is expanded
let targetRatio: CGFloat = 1/3
var centerNavigationController: UINavigationController!
var centerViewController: HomeScreenViewController!
var leftViewController: LeftDrawerViewController?
var centerPanelExpandedOffset: CGFloat!
override func viewDidLoad() {
super.viewDidLoad()
centerViewController = UIStoryboard.centerViewController()
centerViewController.delegate = self
centerNavigationController = UINavigationController(rootViewController: centerViewController)
view.addSubview(centerNavigationController.view)
addChildViewController(centerNavigationController)
centerNavigationController.didMoveToParentViewController(self)
let panGestureRecogonizer = UIPanGestureRecognizer(target: self, action: #selector(ContainerViewController.handlePanGesture(_:)))
centerNavigationController.view.addGestureRecognizer(panGestureRecogonizer)
centerPanelExpandedOffset = view.frame.width * targetRatio
view.backgroundColor = UIColor.whiteColor()
}
}
extension ContainerViewController: HomeScreenViewControllerDelegate {
func toggleLeftPanel() {
if !isLeftDrawerExpanded {
addLeftPanelViewController()
}
animateLeftPanel(shouldExpand: !isLeftDrawerExpanded, velocity: 0)
}
func closeLeftPanel() {
if isLeftDrawerExpanded {
animateLeftPanel(shouldExpand: false, velocity: 0)
}
}
func addLeftPanelViewController() {
if leftViewController == nil {
leftViewController = UIStoryboard.leftViewController()
leftViewController?.appNavController = centerNavigationController
leftViewController?.containerViewController = self
leftViewController?.view.frame = CGRectMake(0, 0, view.frame.width * (1 - targetRatio), view.frame.height)
view.insertSubview(leftViewController!.view, atIndex: 0)
addChildViewController(leftViewController!)
leftViewController!.didMoveToParentViewController(self)
}
}
func animateLeftPanel(shouldExpand shouldExpand: Bool, velocity: CGFloat, duration: Double = 0.5) {
if shouldExpand {
isLeftDrawerExpanded = true
animateCenterPanelXPosition(targetPosition: view.frame.width * (1 - targetRatio), velocity: velocity, duration: duration)
} else {
animateCenterPanelXPosition(targetPosition: 0, velocity: velocity, duration: duration) { finished in
self.isLeftDrawerExpanded = false
self.leftViewController?.view.removeFromSuperview()
self.leftViewController = nil;
}
}
}
func animateCenterPanelXPosition(targetPosition targetPosition: CGFloat, velocity: CGFloat, duration: Double, completion: ((Bool) -> Void)! = nil) {
UIView.animateWithDuration(duration, delay: 0, usingSpringWithDamping: 0.7, initialSpringVelocity: velocity, options: .CurveEaseOut, animations: {
self.centerNavigationController.view.frame.origin.x = targetPosition
}, completion: completion)
}
func showShadowForCenterViewController(shouldShowShadow: Bool) {
if (shouldShowShadow) {
centerNavigationController.view.layer.shadowOpacity = 0.8
} else {
centerNavigationController.view.layer.shadowOpacity = 0.0
}
}
}
extension ContainerViewController: UIGestureRecognizerDelegate {
func handlePanGesture(recognizer: UIPanGestureRecognizer) {
let gestureIsDraggingFromLeftToRight = (recognizer.velocityInView(view).x > 0)
switch(recognizer.state) {
case .Began:
if !isLeftDrawerExpanded && gestureIsDraggingFromLeftToRight && recognizer.locationInView(view).x < (view.frame.width / 3) && centerNavigationController.viewControllers.count == 1{
addLeftPanelViewController()
showShadowForCenterViewController(true)
}
case .Changed:
if (leftViewController != nil) {
if recognizer.view?.frame.origin.x <= (view.frame.width ) * (1 - targetRatio){
recognizer.view!.frame.origin.x += recognizer.translationInView(view).x
recognizer.setTranslation(CGPointZero, inView: view)
}
}
case .Ended:
if (leftViewController != nil) {
let velocityInX = recognizer.velocityInView(view).x
let currentX = recognizer.view!.frame.origin.x
if gestureIsDraggingFromLeftToRight {
let finalX = view.frame.width * (1 - targetRatio)
let hasMovedGreaterThanHalfway = recognizer.view!.center.x * 2 > view.bounds.size.width
let distance = finalX - currentX
let rawDuration = distance / velocityInX
let duration = rawDuration < 0.8 ? rawDuration : 0.8
let springVelocity = (currentX / (view.frame.width * (1 - targetRatio)))
animateLeftPanel(shouldExpand: hasMovedGreaterThanHalfway, velocity: springVelocity, duration: Double(duration))
} else {
let finalX: CGFloat = 0
let hasMovedGreaterThanHalfway = recognizer.view!.center.x / 2 > view.bounds.size.width
let distance = finalX - currentX
let rawDuration = fabs(distance / velocityInX)
let duration = rawDuration < 0.8 ? rawDuration : 0.8
let springVelocity = fabs(currentX / (view.frame.width * (1 - targetRatio)))
animateLeftPanel(shouldExpand: hasMovedGreaterThanHalfway, velocity: springVelocity, duration: Double(duration))
}
}
default:
break
}
}
}
extension UIStoryboard {
class func mainStoryboard() -> UIStoryboard { return UIStoryboard(name: "Main", bundle: NSBundle.mainBundle()) }
class func leftViewController() -> LeftDrawerViewController? {
return mainStoryboard().instantiateViewControllerWithIdentifier("LeftDrawerViewController") as? LeftDrawerViewController
}
class func centerViewController() -> HomeScreenViewController? {
return mainStoryboard().instantiateViewControllerWithIdentifier("HomeScreenViewController") as? HomeScreenViewController
}
}