UICollectionView interactiveTransitionToCollectionViewLayout崩溃,异常

时间:2014-06-16 09:15:08

标签: ios objective-c uicollectionview

我有一个带有水平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];

    }
}
 }

1 个答案:

答案 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;
}];