【问题标题】:UIPercentDrivenInteractiveTransition Not Finishing AnimationUIPercentDrivenInteractiveTransition 未完成动画
【发布时间】:2023-03-10 14:13:01
【问题描述】:

我有一个附加到平移手势的导航弹出,它应该根据平移交互弹出。

什么有效

Transition 监听平移手势并正确更新

什么不起作用

当平移手势“结束”或“取消”时,过渡不会完成动画的其余部分。它只是在没有动画的情况下快速完成。

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)
        }
    }
}

我的交互控制器:

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
    }
}

【问题讨论】:

  • 我没有做视图属性动画师的主要原因之一是,我必须为图层蒙版设置动画,我相信我只能通过 CABasicAnimation 来做到这一点?
  • 我只是想通过向下手势交互地“弹出”视图控制器。
  • 好的,对不起,我没有任何帮助。我所有的代码都在 iOS 10 中用 UIViewPropertyAnimator 替换了 UIPercentDrivenInteractiveTransition,所以我没有 UIPercentDrivenInteractiveTransition 的 Swift 3 示例。但我会尝试将一个较旧的示例翻译成 Swift 3 并发布给你看。
  • 好的,这里是:github.com/mattneub/Programming-iOS-Book-Examples/blob/… 您可以下载并运行示例项目。请注意,它与您正在执行的操作不同:它不是导航控制器,而是选项卡视图控制器,您可以在其中将视图从屏幕边缘侧向滑动。但原理应该是完全一样的。
  • 谢谢。让我知道是否有某些原因导致它在您的情况下无法正常工作...

标签: ios xcode uiviewcontroller uinavigationcontroller swift3


【解决方案1】:

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

-(CGFloat)completionSpeed {
  return 1.0;
}

-(UIViewAnimationCurve)completionCurve {
  return UIViewAnimationCurveEaseOut;
}

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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2022-01-26
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-09-16
    相关资源
    最近更新 更多