我创建了一个互动转换。我的func animateTransition(transitionContext: UIViewControllerContextTransitioning)
很正常,我收到了容器UIView
,我添加了两个UIViewControllers
然后我在UIView.animateWithDuration(duration, animations, completion)
中进行了动画更改。
我从UIScreenEdgePanGestureRecognizer
向UIViewController
添加UIViewController
。它运作良好,除非我做一个非常快速的平底锅。
在最后一个场景中,应用程序没有响应,仍然在同一个Debug View Hierarchy
(过渡似乎没有奏效)但后台任务运行。当我运行UIViewController
时,我会看到新的UIView
而不是之前的animateTransition
,前一个(至少它的transitionContext.completeTransition
)代表它应该站在最后的位置转型。
我做了一些打印和检查点,从中我可以说当问题发生时,动画完成(我的UIGestureRecognizerState.Began
方法中的那个)< strong>未达到,因此我无法调用UIGestureRecognizerState.Ended
方法来完成转换。
我也可以看到平底锅有时会从UIGestureRecognizerState.Changed
直接转到UIGestureRecognizerState.Changed
而不经过translation
。
当velocity
, UIGestureRecognizerState.Changed
和 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
}
}
方法
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)
}
手势和手势处理程序:
updateInteractiveTransition
知道会发生什么吗?
编辑2:
以下是未公开的方法:
.Began
.Ended
中的toViewController
中添加了UIControl
,两个=&gt;没有解决它$('<canvas/>', { id: 'mycanvas', height: 500, width: 200});
视图图层上启用了shouldRasterize并且一直让它开始=&gt;没有解决它但问题是,为什么在进行快速交互式手势时,它的响应速度不够快
只要我的手指足够长,它实际上可以使用快速交互式手势。例如,如果我在超过(比方说)1厘米时非常快速地平移,那就没问题了。如果我在一个不到1厘米的小表面(再说一次)上快速平移,那就不行了
可能的候选者包括动画的视图太复杂(或者具有阴影等复杂效果)
我也考虑过一个复杂的观点,但我认为我的观点并不复杂。有一堆按钮和标签,一个自定义{{1}}充当分段,一个图表(一旦控制器出现就加载),一个xib被加载到viewController中。
好的,我刚刚创建了一个带有MINIMUM类和对象的project,以便触发问题。因此,要触发它,您只需从右向左快速轻扫即可。
我注意到它第一次很容易工作,但是如果你第一次正常拖动视图控制器,那么触发它会更加困难(甚至不可能?)。在我的完整项目中,它并不重要。
答案 0 :(得分:10)
当我诊断出这个问题时,我注意到手势的变化和结束状态事件发生在animateTransition
之前。所以动画在它开始之前就被取消/完成了!
我尝试使用GCD动画同步队列,以确保在{animate:
之后才发生UIPercentDrivenInterativeTransition
的更新。
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
对象之前运行。
答案 1 :(得分:0)
遇到相同的问题,尝试使用serialQueue.suspend()/ resume(),不起作用。
此问题是因为当平移手势过快时,结束状态早于animateTransition开始,然后context.completeTransition无法运行,整个动画变得混乱了。
我的解决方案是在发生这种情况时强制运行context.completeTransition。
例如,我有两个班级:
class SwipeInteractor: UIPercentDrivenInteractiveTransition {
var interactionInProgress = false
...
}
class AnimationController: UIViewControllerAnimatedTransitioning {
func animateTransition(using transitionContext: UIViewControllerContextTransitioning) {
if !swipeInteractor.interactionInProgress {
DispatchQueue.main.asyncAfter(deadline: .now()+transitionDuration) {
if context.transitionWasCancelled {
toView?.removeFromSuperview()
} else {
fromView?.removeFromSuperview()
}
context.completeTransition(!context.transitionWasCancelled)
}
}
...
}
...
}
interactionInProgress在手势开始时设置为true,在手势结束时设置为false。
答案 2 :(得分:0)
我有一个类似的问题,但是编程动画触发器没有触发动画完成块。我的解决方案就像Sam一样,除了不是在短暂的延迟后进行调度,而是在finish
实例上手动调用UIPercentDrivenInteractiveTransition
。
class SwipeInteractor: UIPercentDrivenInteractiveTransition {
var interactionInProgress = false
...
}
class AnimationController: UIViewControllerAnimatedTransitioning {
private var swipeInteractor: SwipeInteractor
..
func animateTransition(using transitionContext: UIViewControllerContextTransitioning) {
...
if !swipeInteractor.interactionInProgress {
swipeInteractor.finish()
}
...
UIView.animateWithDuration(...)
}
}