Продолжительность анимации для 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
Ответы
Ответ 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];
});