Здесь ниже вы можете увидеть результат моего кода. Обратите внимание, что второй раз, когда я нажимаю кнопку «Назад», анимация не работает.
С уважением
![enter image description here](https://i.stack.imgur.com/SXOok.gif)
Я часами пытался понять, в чем проблема с моей анимацией, но не могу найти источник проблемы. Я безуспешно искал ответ в inte rnet. Итак, это моя проблема.
Я помещаю анимацию в finish()
, если переход превышает 50% от view.bounds.width
и cancel()
в противном случае
Это мои шаги
- Обработка анимации до менее 50%
- Анимация возвращается
- Нажмите кнопку Назад в
UINavigationItem
и анимации работает быстро
Это мой код в Animator
class Animator: UIPercentDrivenInteractiveTransition, UIViewControllerAnimatedTransitioning {
private var pausedTime: CFTimeInterval = 0
private var isLayerBased: Bool { operation == .pop }
let animationDuration = 1.0
weak var storedContext: UIViewControllerContextTransitioning?
var interactive: Bool = false
var operation: UINavigationController.Operation = .push
func handlePan(recognizer: UIScreenEdgePanGestureRecognizer)
{
// This part is only for get percent of the translation in the screen with the finger
let translation = recognizer.translation(in: recognizer.view!.superview!)
var progress: CGFloat = abs(translation.x / recognizer.view!.superview!.bounds.width)
progress = min(max(progress, 0.01), 0.99)
switch recognizer.state {
case .changed:
update(progress)
case .cancelled, .ended:
if progress < 0.5 {
cancel()
} else {
finish()
}
interactive = false
default:
break
}
}
override func update(_ percentComplete: CGFloat) {
super.update(percentComplete)
if isLayerBased {
let animationProgress = TimeInterval(animationDuration) * TimeInterval(percentComplete)
storedContext?.containerView.layer.timeOffset = pausedTime + animationProgress
}
}
override func cancel() {
if isLayerBased {
restart(forFinishing: false)
}
super.cancel()
}
override func finish() {
if isLayerBased {
restart(forFinishing: true)
}
super.finish()
}
private func restart(forFinishing: Bool)
{
let transitionLayer = storedContext?.containerView.layer
transitionLayer?.beginTime = CACurrentMediaTime()
transitionLayer?.speed = forFinishing ? 1 : -1
}
func animateTransition(using transitionContext: UIViewControllerContextTransitioning)
{
if interactive && isLayerBased {
let transitionLayer = transitionContext.containerView.layer
self.pausedTime = transitionLayer.convertTime(CACurrentMediaTime(), from: nil)
transitionLayer.speed = 0
transitionLayer.timeOffset = pausedTime
}
self.storedContext = transitionContext
if operation == .pop {
let fromVC = transitionContext.viewController(forKey: .from)!
let toVC = transitionContext.viewController(forKey: .to)!
let animation = CABasicAnimation(keyPath: "transform")
animation.fromValue = NSValue(caTransform3D: CATransform3DIdentity)
animation.toValue = NSValue(caTransform3D: CATransform3DMakeScale(0.001, 0.001, 1))
animation.duration = animationDuration
animation.delegate = self
fromVC.view.layer.removeAllAnimations()
fromVC.view.layer.add(animation, forKey: nil)
} else if operation == .push {
// The Push Animation
// ...
}
}
}
extension Animator: CAAnimationDelegate {
func animationDidStop(_ anim: CAAnimation, finished flag: Bool) {
if let context = self.storedContext
{
print("COMPLETE TRANSITION & ANIMATION STOP")
context.completeTransition(!context.transitionWasCancelled)
}
self.storedContext = nil
}
}
Это был мой аниматор class
. В моем MainViewController единственный интересный код:
class MainViewController: UIViewController, UINavigationControllerDelegate {
let animator = Animator()
override func viewDidLoad() {
super.viewDidLoad()
self.navigationController?.delegate = self
}
func navigationController(_ navigationController: UINavigationController, animationControllerFor operation: UINavigationController.Operation, from fromVC: UIViewController, to toVC: UIViewController) -> UIViewControllerAnimatedTransitioning? {
animator.operation = operation
return animador
}
func navigationController(_ navigationController: UINavigationController, interactionControllerFor animationController: UIViewControllerAnimatedTransitioning) -> UIViewControllerInteractiveTransitioning? {
if ! animator.interactive {
return nil
}
return animador
}
}
А в моем DetailViewController у меня это
class DetailViewController: UIViewController {
weak var animator: Animator?
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
if let masterVC = navigationController!.viewControllers.first as? ViewController {
animador = masterVC.animador
}
let pan = UIScreenEdgePanGestureRecognizer(target: self, action: #selector(didPan(recognizer:)))
pan.edges = .left
view.addGestureRecognizer(pan)
}
@objc func didPan(recognizer: UIScreenEdgePanGestureRecognizer)
{
if recognizer.state == .began
{
animador?.interactive = true
self.navigationController?.popViewController(animated: true)
}
animador?.handlePan(recognizer: recognizer)
}