我有一个带有水平collectionView的collectionViewController,就像在Paper App中一样。我添加了平移手势以从一个布局更改为另一个布局,我使用了交互式转换。如果你在动画结束时拖动并等待它会很好,但是如果你拖动几次并且不要等待动画完成或取消应用会引发异常:
Assertion failure in -[UICollectionView _finishInteractiveTransitionShouldFinish:finalAnimation:], /SourceCache/UIKit_Sim/UIKit-2935.137/UICollectionView.m:2691
*** Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: 'the collection was not prepared for an interactive transition. see startInteractiveTransitionToCollectionViewLayout:completion:'
手势处理程序代码:
- (void)oneFingerGesture:(UIPanGestureRecognizer *)sender
{
if (sender.state == UIGestureRecognizerStateEnded ||
sender.state == UIGestureRecognizerStateCancelled)
{
if (self.transitionLayout.transitionProgress > 0.2) {
[self.collectionView finishInteractiveTransition];
} else {
[self.collectionView cancelInteractiveTransition];
}
}else
{
CGPoint point = [sender locationInView:sender.view];
if (sender.state == UIGestureRecognizerStateBegan && !self.transitionLayout && !_isInTransition)
{
invertPan = self.largeLayout == self.collectionView.collectionViewLayout;
UICollectionViewLayout *toLayout = invertPan ? self.smallLayout : self.largeLayout;
self.transitionLayout = [self.collectionView startInteractiveTransitionToCollectionViewLayout:toLayout
completion:^(BOOL completed, BOOL finish) {
self.transitionLayout = nil;
_isInTransition = NO; }];
self.initialTapPoint = point;
_isInTransition = YES;
}else if(sender.state == UIGestureRecognizerStateChanged && self.transitionLayout && _isInTransition)
{
CGFloat distance = _initialTapPoint.y - point.y;
if (invertPan) {
distance = -distance;
}
CGFloat dimension = self.collectionView.bounds.size.height - 200;
CGFloat progress = MAX(MIN(((distance)/ dimension), 1.0), 0.0);
[self.transitionLayout setTransitionProgress:progress];
}
}
}
答案 0 :(得分:1)
文档说明对finishInteractiveTransition:
和cancelInteractiveTransition:
的调用将分别安装转换的布局对象。但是,这似乎不会立即发生。因此,如果触发和驱动转换的手势可以快速连续发生,则在调用两种方法之一来结束转换之前,检查当前布局是否是UICollectionViewTransitionLayout或其子类是不够的。
我通过引入BOOL ivar(_isFinishingOrCancellingTransition)解决了这个问题,以避免结束已经在结束过程中的转换:
if (_isFinishingOrCancellingTransition) return;
if (!self.transitionLayout) return;
if (self.collectionView.collectionViewLayout != self.transitionLayout) return;
_isFinishingOrCancellingTransition = YES;
if (self.transitionLayout.transitionProgress > 0.5)
{
[self.collectionView finishInteractiveTransition];
}
else
{
[self.collectionView cancelInteractiveTransition];
}
然后在转换完成时重置BOOL:
self.transitionLayout = [self.collectionView startInteractiveTransitionToCollectionViewLayout:toLayout completion:^(BOOL completed, BOOL finish) {
self.transitionLayout = nil;
_isFinishingOrCancellingTransition = NO;
}];