Я пытаюсь реализовать пользовательский интерактивный переход с перетаскиванием, используя UIViewControllerAnimatedTransitioning
и UIPercentDrivenInteractiveTransition
.
Вот код аниматора для отклонения, он просто полностью перемещает представление вниз из кадр:
final class SheetDismissAnimator: NSObject, UIViewControllerAnimatedTransitioning {
func transitionDuration(using transitionContext: UIViewControllerContextTransitioning?) -> TimeInterval {
0.5
}
func animateTransition(using transitionContext: UIViewControllerContextTransitioning) {
guard let fromVC = transitionContext.viewController(forKey: .from) else { return }
UIView.animate(withDuration: transitionDuration(using: transitionContext), animations: {
fromVC.view.frame.origin.y = transitionContext.containerView.frame.height
}, completion: { _ in
transitionContext.completeTransition(!transitionContext.transitionWasCancelled)
})
}
}
А вот код контроллера модального представления, который я пытаюсь отклонить, к которому прикреплен распознаватель жестов панорамирования:
final class ModalViewController: UIViewController {
private let customTransitionDelegate = SheetTransitioningDelegate()
private var interactionController: UIPercentDrivenInteractiveTransition?
init() {
super.init(nibName: nil, bundle: nil)
modalPresentationStyle = .custom
transitioningDelegate = customTransitionDelegate
}
required init?(coder: NSCoder) {
super.init(coder: coder)
}
override func viewDidLoad() {
super.viewDidLoad()
view.backgroundColor = .red
view.addGestureRecognizer(UIPanGestureRecognizer(target: self, action: #selector(handleGesture(_:))))
}
@objc func handleGesture(_ gesture: UIPanGestureRecognizer) {
let translate = gesture.translation(in: view)
let percent = translate.y / view.bounds.height
switch gesture.state {
case .began:
interactionController = UIPercentDrivenInteractiveTransition()
customTransitionDelegate.interactionController = interactionController
dismiss(animated: true)
case .changed:
interactionController?.update(percent)
case .cancelled:
interactionController?.cancel()
case .ended:
let velocity = gesture.velocity(in: gesture.view)
if percent > 0.5 || velocity.y > 700 {
interactionController?.finish()
} else {
interactionController?.cancel()
}
interactionController = nil
default:
break
}
}
}
Соответствующая часть Я считаю, что это функция handleGesture(_ gesture: UIPanGestureRecognizer)
, которая вычисляет процент для продвижения анимации. Вставил весь код для ясности.
Я ожидаю, что анимация будет следовать за жестом панорамирования линейно, но вместо этого происходит следующее: