我将UINavigationController
子类化,并创建了一个处理推送和弹出过渡的非交互式动画对象。要完成此操作,如何添加UIScreenEdgePanGestureRecognizer
来处理下面的自定义流行动画?我有点困惑,从这里去哪里,所以任何帮助都会很棒,谢谢!
class CustomNavigationController: UINavigationController {
override func viewDidLoad() {
super.viewDidLoad()
delegate = self
isNavigationBarHidden = true
}
}
extension CustomNavigationController: UINavigationControllerDelegate {
// noninteractive animator objects
func navigationController(_ navigationController: UINavigationController, animationControllerFor operation: UINavigationControllerOperation, from fromVC: UIViewController, to toVC: UIViewController) -> UIViewControllerAnimatedTransitioning? {
switch operation {
case .push:
return CustomPushAnimator()
case .pop:
return CustomPopAnimator()
default:
return nil
}
}
// the interactive animator controller
func navigationController(_ navigationController: UINavigationController, interactionControllerFor animationController: UIViewControllerAnimatedTransitioning) -> UIViewControllerInteractiveTransitioning? {
switch animationController {
case is CustomPopAnimator:
return CustomInteractiveController()
default:
return nil
}
}
// the noninteractive push animator
class CustomPushAnimator: NSObject, UIViewControllerAnimatedTransitioning {
// push transition duration
func transitionDuration(using transitionContext: UIViewControllerContextTransitioning?) -> TimeInterval {
return 0.2
}
// push transition animation
func animateTransition(using transitionContext: UIViewControllerContextTransitioning) {
let viewWidth = UIScreen.main.bounds.width
let viewHeight = UIScreen.main.bounds.height
let containerView = transitionContext.containerView
let toViewController = transitionContext.viewController(forKey: .to)
containerView.addSubview((toViewController?.view)!)
toViewController?.view.frame = CGRect(x: viewWidth, y: 0, width: viewWidth, height: viewHeight)
UIView.animate(withDuration: transitionDuration(using: transitionContext), delay: 0, options: UIViewAnimationOptions.curveEaseInOut, animations: {
toViewController?.view.frame = CGRect(x: 0, y: 0, width: viewWidth, height: viewHeight)
}, completion: { finished in
transitionContext.completeTransition(!transitionContext.transitionWasCancelled)
})
}
}
// the noninteractive pop animator
class CustomPopAnimator: NSObject, UIViewControllerAnimatedTransitioning {
// pop transition duration
func transitionDuration(using transitionContext: UIViewControllerContextTransitioning?) -> TimeInterval {
return 0.2
}
// pop transition animation
func animateTransition(using transitionContext: UIViewControllerContextTransitioning) {
let viewWidth = UIScreen.main.bounds.width
let viewHeight = UIScreen.main.bounds.height
let containerView = transitionContext.containerView
let fromViewController = transitionContext.viewController(forKey: .from)
let toViewController = transitionContext.viewController(forKey: .to)
containerView.insertSubview((toViewController?.view)!, belowSubview: (fromViewController?.view)!)
UIView.animate(withDuration: transitionDuration(using: transitionContext), delay: 0, options: UIViewAnimationOptions.curveEaseInOut, animations: {
fromViewController?.view.frame = CGRect(x: viewWidth, y: 0, width: viewWidth, height: viewHeight)
}, completion: { finished in
fromViewController?.view.removeFromSuperview()
transitionContext.completeTransition(!transitionContext.transitionWasCancelled)
})
}
}
class CustomInteractiveController: NSObject, UIViewControllerInteractiveTransitioning {
func startInteractiveTransition(_ transitionContext: UIViewControllerContextTransitioning) {
// I think the edge screen pan gesture goes here? Again, any advice is greatly appreciated!
}
}
答案 0 :(得分:1)
通常,编写交互式自定义过渡动画的过程是:
在转换开始之前,您必须已经让视图控制器负责代表的过渡。
您将拥有一个跟踪交互式手势的手势识别器。当手势识别器识别时,它会触发向新视图控制器的转换。
随着转换的开始,代表将被要求提供动画控制器。您将返回一个UIViewControllerAnimatedTransitioning对象。
还会要求代表提供交互控制器。您将返回UIViewControllerInteractiveTransitioning对象(或nil
以防止转换为交互)。该对象实现startInteractiveTransition(_:)
。
手势识别器继续在转换上下文中不断调用updateInteractiveTransition(_:)
,以及管理动画的帧。
手势迟早会结束。此时,我们必须决定是否声明过渡完成或取消。一种典型的方法是,如果用户执行完整手势的一半以上,则构成完成;否则,它构成取消。我们相应地完成动画。
动画现已完成,并调用其完成功能。我们必须调用转换上下文的finishInteractiveTransition
或cancelInteractiveTransition
,然后使用参数调用其completeTransition(_:)
,说明转换是完成还是取消。
我们调用了animationEnded
,我们会进行清理。
过去,您可以使用UIPercentDrivenInteractiveTransition对象来帮助您,但我现在总是使用UIViewPropertyAnimator来制作自定义过渡动画(iOS 10及更高版本);你必须从重写整个代码开始这样做。我通常保留三个实例属性:UIViewPropertyAnimator,转换上下文(因为手势识别器需要引用),以及Bool标志,说明这是否是交互式动画(因为相同的代码可以重用于交互式和非交互式动画动画)。