UIPercentDrivenInteractiveTransition无法在快速手势上完成动画
我创建了一个交互式过渡。 我的func animateTransition(transitionContext: UIViewControllerContextTransitioning)
很正常,我得到容器UIView
,我添加了两个UIViewControllers
然后我在UIView.animateWithDuration(duration, animations, completion)
做动画更改。
我从UIViewController
添加了一个UIScreenEdgePanGestureRecognizer
。 它运作良好,除非我做一个非常快速的平底锅。
在最后一个场景中,应用程序没有响应,仍然在相同的UIViewController
(转换似乎没有工作)但后台任务运行。 当我运行Debug View Hierarchy
,我看到新的UIViewController
而不是前一个,而前一个(至少它的UIView
)代表它应该在转换结束时站立的位置。
我做了一些打印和检查点,从中我可以说,当问题发生时, 动画的完成 (我的animateTransition
方法中的那个) 没有到达 ,所以我不能调用transitionContext.completeTransition
方法来完成或不转换。
我也可以看到泛有时从UIGestureRecognizerState.Began
直接进入UIGestureRecognizerState.Ended
而不经过UIGestureRecognizerState.Changed
。
当它通过UIGestureRecognizerState.Changed
,每个UIGestureRecognizerState.Changed
状态的translation
和 velocity
保持不变。
编辑:
这是代码:
animateTransition
方法
func animateTransition(transitionContext: UIViewControllerContextTransitioning) { self.transitionContext = transitionContext let containerView = transitionContext.containerView() let screens: (from: UIViewController, to: UIViewController) = (transitionContext.viewControllerForKey(UITransitionContextFromViewControllerKey)!, transitionContext.viewControllerForKey(UITransitionContextToViewControllerKey)!) let parentViewController = presenting ? screens.from : screens.to let childViewController = presenting ? screens.to : screens.from let parentView = parentViewController.view let childView = childViewController.view // positionning the "to" viewController's view for the animation if presenting { offStageChildViewController(childView) } containerView.addSubview(parentView) containerView.addSubview(childView) let duration = transitionDuration(transitionContext) UIView.animateWithDuration(duration, animations: { if self.presenting { self.onStageViewController(childView) self.offStageParentViewController(parentView) } else { self.onStageViewController(parentView) self.offStageChildViewController(childView) }}, completion: { finished in if transitionContext.transitionWasCancelled() { transitionContext.completeTransition(false) } else { transitionContext.completeTransition(true) } }) }
手势和手势处理程序:
weak var fromViewController: UIViewController! { didSet { let screenEdgePanRecognizer = UIScreenEdgePanGestureRecognizer(target: self, action: "presentingViewController:") screenEdgePanRecognizer.edges = edge fromViewController.view.addGestureRecognizer(screenEdgePanRecognizer) } } func presentingViewController(pan: UIPanGestureRecognizer) { let percentage = getPercentage(pan) switch pan.state { case UIGestureRecognizerState.Began: interactive = true presentViewController(pan) case UIGestureRecognizerState.Changed: updateInteractiveTransition(percentage) case UIGestureRecognizerState.Ended: interactive = false if finishPresenting(pan, percentage: percentage) { finishInteractiveTransition() } else { cancelInteractiveTransition() } default: break } }
知道会发生什么吗?
编辑2:
以下是未公开的方法:
override func getPercentage(pan: UIPanGestureRecognizer) -> CGFloat { let translation = pan.translationInView(pan.view!) return abs(translation.x / pan.view!.bounds.width) } override func onStageViewController(view: UIView) { view.transform = CGAffineTransformIdentity } override func offStageParentViewController(view: UIView) { view.transform = CGAffineTransformMakeTranslation(-view.bounds.width / 2, 0) } override func offStageChildViewController(view: UIView) { view.transform = CGAffineTransformMakeTranslation(view.bounds.width, 0) } override func presentViewController(pan: UIPanGestureRecognizer) { let location = pan.locationInView((fromViewController as! MainViewController).tableView) let indexPath = (fromViewController as! MainViewController).tableView.indexPathForRowAtPoint(location) if indexPath == nil { pan.state = .Failed return } fromViewController.performSegueWithIdentifier("chartSegue", sender: pan) }
- 我删除了“over”添加行=>没有修复它
- 我在
.Ended
添加了updateInteractiveTransition
,在.Ended
,在=>中都没有修复它 - 我在我的
toViewController
的视图层打开了toViewController
并且一直让它开始=>没有修复它
但问题是,在进行快速交互式手势时,为什么它的响应速度不够快
只要我的手指足够长,它实际上可以使用快速交互式手势。 例如,如果我在超过(比方说)1cm时非常快速地平移,那就没关系。 如果我在小于1厘米的小表面(再说一次)上快速平移,那就不行了
可能的候选者包括动画的视图太复杂(或具有阴影等复杂效果)
我也考虑过复杂的观点,但我认为我的观点并不复杂。 有一堆按钮和标签,一个自定义UIControl
充当分段,一个图表(一旦控制器出现就加载),并在viewController中加载一个xib。
好的,我刚刚创建了一个包含MINIMUM类和对象的项目 ,以便触发问题。 因此,要触发它,您只需从右向左快速轻扫即可。
我注意到它第一次很容易工作,但如果你第一次正常拖动视图控制器,那么触发它会更加困难(甚至不可能?)。 在我的完整项目中,它并不重要。
当我诊断出这个问题时,我注意到在animateTransition
运行之前,手势的变化和结束的状态事件正在发生。 所以动画在它开始之前就被取消/完成了!
我尝试使用GCD动画同步队列,以确保UIPercentDrivenInterativeTransition
的更新直到`animate:之后才会发生:
private let animationSynchronizationQueue = dispatch_queue_create("com.domain.app.animationsynchronization", DISPATCH_QUEUE_SERIAL)
然后我有一个实用工具方法来使用这个队列:
func dispatchToMainFromSynchronizationQueue(block: dispatch_block_t) { dispatch_async(animationSynchronizationQueue) { dispatch_sync(dispatch_get_main_queue(), block) } }
然后我的手势处理程序确保更改和结束状态通过该队列路由:
func handlePan(gesture: UIPanGestureRecognizer) { switch gesture.state { case .Began: dispatch_suspend(animationSynchronizationQueue) fromViewController.performSegueWithIdentifier("segueID", sender: gesture) case .Changed: dispatchToMainFromSynchronizationQueue() { self.updateInteractiveTransition(percentage) } case .Ended: dispatchToMainFromSynchronizationQueue() { if isOkToFinish { self.finishInteractiveTransition() } else { self.cancelInteractiveTransition() } } default: break } }
所以,我有手势识别器的.Began
状态暂停该队列,我让动画控制器在animationTransition
恢复该队列(确保队列在该方法运行之后再次启动,然后手势继续尝试更新UIPercentDrivenInteractiveTransition
对象。