UIPercentDrivenInteractiveTransition未完成动画

时间:2017-01-08 00:57:59

标签: ios xcode uiviewcontroller uinavigationcontroller swift3

我有一个导航弹出窗口附加到一个平移手势,该手势应该根据平移进行交互式弹出。

什么有效

转换侦听平移手势并正确更新

什么不起作用

当平移手势结束时'或者'取消'',转换不会完成动画的其余部分。它只是完成而没有动画。

FirstViewController:

extension FirstViewController: UINavigationControllerDelegate {

func navigationController(_ navigationController: UINavigationController, animationControllerFor operation: UINavigationControllerOperation, from fromVC: UIViewController, to toVC: UIViewController) -> UIViewControllerAnimatedTransitioning? {
        if operation == .push {
            myInteractionController.attachToViewControllers(fromVc: fromVC, toVc: toVC)
            return myPushTransition
        }
        return myPopTransition
    }


    func navigationController(_ navigationController: UINavigationController, interactionControllerFor animationController: UIViewControllerAnimatedTransitioning) -> UIViewControllerInteractiveTransitioning? {
        return myInteractionController.transitionInProgress ? myInteractionController : nil
    }
}

MyPopTr​​ansition:

class MyPopTransition: NSObject, UIViewControllerAnimatedTransitioning, CAAnimationDelegate {
        var initialFrame           : CGRect  = CGRect.zero
        var initialCenter          : CGPoint = CGPoint.zero
        var transitionContext      : UIViewControllerContextTransitioning?

    func transitionDuration(using transitionContext: UIViewControllerContextTransitioning?) -> TimeInterval {
        return 0.8
    }

    func animateTransition(using transitionContext: UIViewControllerContextTransitioning) {
        self.transitionContext = transitionContext
        let containerView = transitionContext.containerView
        let toVC = transitionContext.viewController(forKey: .to) as! myFirstViewController
        let fromVC = transitionContext.viewController(forKey: .from) as! mySecondViewController
        let fromVC2 = (fromVC.viewControllers![0] as! myThirdViewController)

        containerView.insertSubview(toVC.view, belowSubview: fromVC.view)

        toVC.view.alpha = 1
        fromVC.view.alpha = 1

        fromVC2.addImageViewLayerMask()
        let cropAnimation = CABasicAnimation(keyPath: "path")
        cropAnimation.delegate = self
        cropAnimation.fromValue = UIBezierPath(rect: fromVC2.imageFrame(percentage: 0)).cgPath
        cropAnimation.toValue = UIBezierPath(rect: fromVC2.imageFrame(percentage: 1)).cgPath
        cropAnimation.duration = transitionDuration(using: transitionContext)
        fromVC2.imageViewMaskLayer!.path = UIBezierPath(rect: fromVC2.imageFrame(percentage: 1)).cgPath
        fromVC2.imageViewMaskLayer!.add(cropAnimation, forKey: "cropAnimation")


        UIView.animate(withDuration: transitionDuration(using: transitionContext),
                       animations: {
                        let initialScale = self.initialFrame.height <  self.initialFrame.height ?
                            self.initialFrame.height/fromVC.view.bounds.height :
                            self.initialFrame.width/fromVC.view.bounds.width
                        fromVC2.imageView.transform = toVC.view.transform.scaledBy(x: initialScale, y: initialScale)
                        fromVC2.view.center =  self.initialCenter
        },  completion: {
            finished in

        })

    }

    func animationDidStop(_ anim: CAAnimation, finished flag: Bool) {
        if let transitionContext = self.transitionContext {
            if (transitionContext.transitionWasCancelled) {
                transitionContext.viewController(forKey: .to)?.view.removeFromSuperview()
                ((transitionContext.viewController(forKey: .from) as! mySecondViewController).viewControllers![0] as! myThirdViewController).removeImageViewLayerMask()
                (transitionContext.viewController(forKey: .from) as! mySecondViewController).pageScrollView.isScrollEnabled = true
            } else {
                 transitionContext.viewController(forKey: .from)?.view!.removeFromSuperview()
            }
            transitionContext.completeTransition(!transitionContext.transitionWasCancelled)
        }
    }
}

MyInteractionController:

class MyInteractionController: UIPercentDrivenInteractiveTransition {
        var navigationController        : UINavigationController!
        var fromViewController          : UIViewController?
        var toViewController            : UIViewController?
        var panGestureRecognizer        : UIPanGestureRecognizer = UIPanGestureRecognizer()
        var shouldCompleteTransition    = false
        var transitionInProgress        = false

    func attachToViewControllers(fromVc: UIViewController, toVc: UIViewController) {
        navigationController = toVc.navigationController
        self.fromViewController = fromVc
        self.toViewController = toVc
        self.setupGestureRecognizer()
        self.wantsInteractiveStart = true
    }


    private func setupGestureRecognizer() {
        panGestureRecognizer.delegate = self
        panGestureRecognizer.maximumNumberOfTouches = 1
        panGestureRecognizer.addTarget(self, action: #selector(self.handlePanGesture(gestureRecognizer:)))
        navigationController.view.addGestureRecognizer(panGestureRecognizer)

        guard let interactivePopGestureRecognizer = navigationController?.interactivePopGestureRecognizer
            else { return }
        panGestureRecognizer.require(toFail: interactivePopGestureRecognizer)
    }


    func handlePanGesture(gestureRecognizer: UIPanGestureRecognizer) {
        var progress = gestureRecognizer.translation(in: gestureRecognizer.view!).y / (gestureRecognizer.view!.bounds.size.height * 0.5)
        progress = min(1.0, max(0.0, progress))

        switch gestureRecognizer.state {
        case .began:
            transitionInProgress = true
            navigationController.popViewController(animated: true)

        case .changed:
                self.update(progress)

        case .cancelled, .ended:
            transitionInProgress = false
                self.finish()

        default:
            break
        }
    }

}

extension MyInteractionController: UIGestureRecognizerDelegate {
    func gestureRecognizer(_ gestureRecognizer: UIGestureRecognizer, shouldRecognizeSimultaneouslyWith otherGestureRecognizer: UIGestureRecognizer) -> Bool {
        return true
    }

    func gestureRecognizerShouldBegin(_ gestureRecognizer: UIGestureRecognizer) -> Bool {
        if gestureRecognizer == self.panGestureRecognizer {
            let translation = panGestureRecognizer.translation(in: panGestureRecognizer.view)
            let translationIsVertical = (translation.y > 0) && (abs(translation.y) > abs(translation.x))
            return translationIsVertical &&
                (navigationController?.viewControllers.count ?? 0 > 1)
        }
        return false
    }
}

1 个答案:

答案 0 :(得分:1)

FWIW,作为一种可能的解决方案,我在iOS 9上遇到了这个问题,但奇怪的是它适用于iOS 10+。我能够通过在我的UIPercentDrivenInteractiveTransition子类中实现completionSpeed和completionCurve来修复它:

 url(r'^restaurant/meal/(?P<meal_id>\d+)/delete/$', 
 views.restaurant_delete_meal, name = 'restaurant-delete-meal'),

事实上,您可能甚至不需要完成曲线覆盖。问题是[super completionSpeed]返回0.我猜这是在旧版iOS上使用UIPercentDrivenInteractiveTransition的某些情况下的默认行为。