我有一个导航弹出窗口附加到一个平移手势,该手势应该根据平移进行交互式弹出。
转换侦听平移手势并正确更新
当平移手势结束时'或者'取消'',转换不会完成动画的其余部分。它只是完成而没有动画。
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
}
}
MyPopTransition:
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
}
}
答案 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的某些情况下的默认行为。