Плавная анимация ящика с помощью 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
    }

}

0 ответов

Другие вопросы по тегам