Подтвердить что ты не робот

Продолжительность анимации для UICollectionView selectItemAtIndexPath: анимированная: scrollPosition:

Я попытался установить продолжительность (с обычными методами, которые я бы попробовал) для установки продолжительности анимации для метода UICollectionView selectItemAtIndexPath:animated:scrollPosition: (или метода scrollToItemAtIndexPath:atScrollPosition:animated:). Я пробовал [UIView setAnimationDuration], и я попробовал обернуть его в CATransaction. Я не увенчался успехом до этого, чтобы изменить продолжительность анимации (хотя я признаю, что мог ошибиться в этой логике).

Мысли?

ОБНОВЛЕНИЕ:

Я пробовал здесь множество подходов. Самое близкое решение - сделать то, что мы обычно делали бы для анимации UIScrollView (путем установки анимированного аргумента: NO и упаковки его в блок анимации UIView). Это отлично работает для scrollview. Однако, по какой-то причине это винты с процессом создания UICollectionView.

Я привел пример ниже, используя два подхода. Каждый подход предполагает, что у вас есть 4 раздела с 4 элементами в каждом разделе. Кроме того, анимация предполагает, что вы перемещаетесь от 0,0 до 3,3.

Использование анимации по умолчанию

Часть вопроса здесь, безусловно, связана с UICollectionView. Если вы примете следующий подход (используя параметр анимации по умолчанию) - все работает нормально:

[self.collectionView scrollToItemAtIndexPath:[NSIndexPath indexPathForItem:3 inSection:3]
                                atScrollPosition:UICollectionViewScrollPositionCenteredHorizontally
                                        animated:YES];

Когда это выполняется, каждая ячейка между текущими видимыми ячейками и ячейкой назначения создается. Я включил запись в метод collectionView:cellForItemAtIndexPath::

2013-05-18 09:33:24.366 DEF-CV-Testing[75463:c07] Transition
Cell Created for Index Path: <NSIndexPath 0x8913f40> 2 indexes [0, 1]
Cell Created for Index Path: <NSIndexPath 0x75112e0> 2 indexes [0, 2]
Cell Created for Index Path: <NSIndexPath 0xfe1a6c0> 2 indexes [0, 3]
Cell Created for Index Path: <NSIndexPath 0x89159e0> 2 indexes [1, 0]
Cell Created for Index Path: <NSIndexPath 0x8a10e70> 2 indexes [1, 1]
Cell Created for Index Path: <NSIndexPath 0x7510d90> 2 indexes [1, 2]
Cell Created for Index Path: <NSIndexPath 0x75112a0> 2 indexes [1, 3]
Cell Created for Index Path: <NSIndexPath 0x8915a00> 2 indexes [2, 0]
Cell Created for Index Path: <NSIndexPath 0x75111c0> 2 indexes [2, 1]
Cell Created for Index Path: <NSIndexPath 0xfe17f30> 2 indexes [2, 2]
Cell Created for Index Path: <NSIndexPath 0xfe190c0> 2 indexes [2, 3]
Cell Created for Index Path: <NSIndexPath 0xfe16920> 2 indexes [3, 0]
Cell Created for Index Path: <NSIndexPath 0x75112a0> 2 indexes [3, 1]
Cell Created for Index Path: <NSIndexPath 0xfe1a4f0> 2 indexes [3, 2]
Cell Created for Index Path: <NSIndexPath 0x75142d0> 2 indexes [3, 3]

Использование пользовательской анимации

При переносе метода scrollToItemAtIndexPath: в блок анимации UIView элементы создаются неправильно. См. Пример кода здесь:

[UIView animateWithDuration:5.0 delay:0.0 options:0 animations:^{
    [self.collectionView scrollToItemAtIndexPath:[NSIndexPath indexPathForItem:3 inSection:3]
                                atScrollPosition:UICollectionViewScrollPositionCenteredHorizontally
                                        animated:NO];
} completion:^(BOOL finished) {
    NSLog(@"Completed");
}];

В настоящее время видимые ячейки исчезают, и создается только целевая. Я включил тот же журнал в метод collectionView:cellForItemAtIndexPath::

Transition
Cell Created for Index Path: <NSIndexPath 0x71702f0> 2 indexes [3, 3]
Completed
4b9b3361

Ответ 1

У меня были аналогичные проблемы с UITableView, которые я решил с помощью следующего кода:

[CATransaction begin];
[CATransaction setCompletionBlock:onCompletion];
[CATransaction setAnimationDuration:duration];

[self.collectionView scrollToItemAtIndexPath:[NSIndexPath indexPathForItem:3 inSection:3]
                            atScrollPosition:UICollectionViewScrollPositionCenteredHorizontally
                                    animated:YES];

[CATransaction commit];

Очевидно, вы не можете называть его animated:NO, потому что код анимации внутри метода важен. Использование CATransaction для обертывания анимации работало для меня.

Ответ 2

Для меня это работает. Очевидно, что он нуждается в некоторых настройках (чтобы иметь более точное время и заставить его прокручивать назад, снизу вверх. К настоящему времени он поддерживает только вертикальную прокрутку сверху вниз)

Вызвать что-то вроде этого:

[self scrollToIndexPath:[NSIndexPath indexPathForItem:40 inSection:0] withAnimationDuration:3.0f];

и вот код

-(void)scrollToIndexPath:(NSIndexPath *)path withAnimationDuration:(float)duration
{
    NSIndexPath *firstCell = [[self.collectionView indexPathsForVisibleItems] objectAtIndex:0];
    UICollectionViewLayoutAttributes *attributesForFirstCell = [self.collectionView layoutAttributesForItemAtIndexPath:firstCell];
    CGRect firstCellRect = attributesForFirstCell.frame;
    CGPoint startPoint = firstCellRect.origin;

    NSIndexPath *destinationCell = path;
    UICollectionViewLayoutAttributes *attributesForDestCell = [self.collectionView layoutAttributesForItemAtIndexPath:destinationCell];
    CGRect destCellRect = attributesForDestCell.frame;
    CGPoint destPoint = destCellRect.origin;

    self.destination = destPoint;

    float delta = destPoint.y - startPoint.y;

    float cycle = (delta / (50*duration));
    self.pass = (int)cycle + 1;

    self.myTimer = [NSTimer scheduledTimerWithTimeInterval:0.02 target:self selector:@selector(scrollView) userInfo:nil repeats:YES];
}



- (void) scrollView {

    float w = self.pass;

    CGPoint scrollPoint = self.collectionView.contentOffset;
    scrollPoint.y = scrollPoint.y + w;

    if (scrollPoint.y >= self.destination.y)
        [self.myTimer invalidate];
    [self.collectionView setContentOffset: scrollPoint animated: NO];
}

Ответ 3

Что, если вы поместите код в scrollViewDidScroll:?

У меня есть аналогичная проблема, которую я решил, вызвав selectItemAtIndexPath:animated:scrollPosition, а затем используя scrollViewDidScroll:, чтобы запустить то, что я обычно запускал в блоке завершения.

Конечно, вам, вероятно, придется отслеживать BOOL или два, чтобы решить, что вам нужно выполнить что-либо в scrollViewDidScroll:.

Ответ 4

Вы можете сделать это с помощью библиотеки AnimationEngine. Он обертывает CADisplayLink в блочном анимационном синтаксисе. Я отправил ответ здесь с примером кода, который анимирует contentOffset. Вам просто нужно сделать преобразование из indexPath в contentOffset.

Ответ 5

Я могу заставить это работать, оборачивая это в UIView.animate с анимированным ложным:

UIView.animate(withDuration: 0.7, delay: 0.0, options: .curveEaseInOut, animations: {
            self.collectionView.scrollToItem(at: IndexPath(row: 0, section: 0), at: .centeredHorizontally, animated: false)
        }, completion: nil)

Ответ 6

Я нашел способ прокрутки вручную и полностью обходить self.collectionView scrollToItemAtIndexPath..

Я также попытался использовать блок завершения для прокрутки различных разделов, но это привело к отрывистому опыту.

Обратите внимание, что этот пример прокручивается по вертикали - вы можете изменить это для прокрутки по горизонтали. Вам также, вероятно, придется настроить смещения так, чтобы прокрутка останавливалась в нужном месте. Опять же, я удивлен, что API не предлагает способ контролировать скорость.

-(void)scrollMethod {

    // Find the point where scrolling should stop.
    UICollectionViewLayoutAttributes *attr = [self.collectionView layoutAttributesForItemAtIndexPath:[NSIndexPath indexPathForItem:3 inSection:3]];

    CGRect cellRect = attr.frame;

    self.source = self.collectionView.frame.origin;
    self.destination = cellRect.origin;
    self.myTimer = [NSTimer scheduledTimerWithTimeInterval:0.001 target:self selector:@selector(scrollOn) userInfo:nil repeats:YES];

}

-(void)scrollOn {
    self.collectionView.contentOffset = self.source;
    // If we have crossed where we need to be, quit the timer
    if ( self.source.y > self.destination.y)
        [self.myTimer invalidate];

    self.source = CGPointMake(self.source.x, self.source.y+1);
}

Ответ 7

Фактическое решение заключается в том, что вам нужно сделать scrollToItemAtIndexPath в главной очереди. так что только вы можете получить реальную работу этого.

Пример кода:

 dispatch_async(dispatch_get_main_queue(), ^{

    [collectionView scrollToItemAtIndexPath:indexPath atScrollPosition:UICollectionViewScrollPositionCenteredHorizontally animated:NO];

});