UICollectionView interactiveTransitionToCollectionViewLayout вылетает с исключением

#ios #objective-c #uicollectionview

#iOS #objective-c #uicollectionview

Вопрос:

У меня есть контроллер collectionViewController с горизонтальным представлением коллекции, как в приложении Paper. Я добавил жест панорамирования для перехода с одного макета на другой и использовал интерактивный переход. Это хорошо работает, если вы перетаскиваете и ждете завершения анимации, но если вы перетаскиваете быстрее несколько раз и не ждете завершения или отмены анимации, приложение выдает исключение:

 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 amp;amp; !self.transitionLayout amp;amp; !_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 amp;amp; self.transitionLayout amp;amp; _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. Вы пробовали пошагово выполнять отладку этим методом?

Ответ №1:

В документации указано, что вызывается finishInteractiveTransition: и cancelInteractiveTransition: устанавливается объект layout, к которому и из которого происходит переход, соответственно. Однако, похоже, это происходит не сразу. Таким образом, если запуск жеста и управление переходом могут происходить в быстрой последовательности, недостаточно проверить, является ли текущий макет UICollectionViewTransitionLayout или его подклассом, прежде чем вызывать один из двух методов для завершения перехода.

Я решил проблему, введя BOOL ivar (_isfinishing или cancellingtransition), чтобы избежать завершения перехода, который уже находится в процессе завершения:

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

Комментарии:

1. Это было не совсем то, что мне было нужно, но это определенно направило меня в правильном направлении. Спасибо!