Создание медленной прокрутки в indexPath в UICollectionView
Я работаю над проектом, где я использую UICollectionView, чтобы создать "тиккер изображения", где я рекламирую серию логотипов. CollectionView - это один элемент с высоким и двенадцатью пунктами и показывает от двух до трех элементов за раз (в зависимости от размера видимых логотипов).
Я хотел бы сделать медленную автоматическую прокрутку анимации от первого элемента до последнего, а затем повторить.
Кто-нибудь мог сделать эту работу? Я могу заставить прокрутку работать с помощью
[myCollection scrollToItemAtIndexPath:[NSIndexPath indexPathForRow:(myImages.count -1) inSection:0] atScrollPosition:UICollectionViewScrollPositionRight animated:YES];
Но это слишком быстро!
[UIView animateWithDuration:10 delay:2 options:(UIViewAnimationOptionAutoreverse + UIViewAnimationOptionRepeat) animations:^{
[myCollection scrollToItemAtIndexPath:[NSIndexPath indexPathForRow:(myImages.count -1) inSection:0] atScrollPosition:UICollectionViewScrollPositionRight animated:NO];
} completion:nil];
Это дает желаемую скорость прокрутки, но в этой серии видны только последние несколько ячеек. Я подозреваю, что они (и даже начальные видимые клетки) немедленно освобождаются.
Любые мысли?
Ответы
Ответ 1
Вы можете попробовать этот подход:
@property (nonatomic, assign) CGPoint scrollingPoint, endPoint;
@property (nonatomic, strong) NSTimer *scrollingTimer;
@synthesize scrollingPoint, endPoint;
@synthesize scrollingTimer;
- (void)scrollSlowly {
// Set the point where the scrolling stops.
self.endPoint = CGPointMake(0, 300);
// Assuming that you are starting at {0, 0} and scrolling along the x-axis.
self.scrollingPoint = CGPointMake(0, 0);
// Change the timer interval for speed regulation.
self.scrollingTimer = [NSTimer scheduledTimerWithTimeInterval:0.015 target:self selector:@selector(scrollSlowlyToPoint) userInfo:nil repeats:YES];
}
- (void)scrollSlowlyToPoint {
self.collectionView.contentOffset = self.scrollingPoint;
// Here you have to respond to user interactions or else the scrolling will not stop until it reaches the endPoint.
if (CGPointEqualToPoint(self.scrollingPoint, self.endPoint)) {
[self.scrollingTimer invalidate];
}
// Going one pixel to the right.
self.scrollingPoint = CGPointMake(self.scrollingPoint.x, self.scrollingPoint.y+1);
}
Ответ 2
Я использую трюк "1 пиксельный смещение. При прокрутке программным способом просто установите конец contentOffset.x
на 1 пиксель больше/меньше, чем нужно. Это должно быть незаметно. И в блоке завершения установите его на фактическое значение. Таким образом, вы можете избежать преждевременной проблемы с деинхронизацией ячейки и получить плавную анимацию прокрутки;)
Вот пример прокрутки на правую страницу (например, со страницы 1 на 2). Обратите внимание, что в блоке animations:
я фактически прокручиваю на один пиксель меньше (pageWidth * nextPage - 1
). Затем я восстанавливаю правильное значение в блоке completion:
.
CGFloat pageWidth = self.collectionView.frame.size.width;
int currentPage = self.collectionView.contentOffset.x / pageWidth;
int nextPage = currentPage + 1;
[UIView animateWithDuration:1
delay:0
options:UIViewAnimationOptionCurveEaseOut
animations:^{
[self.collectionView setContentOffset:CGPointMake(pageWidth * nextPage - 1, 0)];
} completion:^(BOOL finished) {
[self.collectionView setContentOffset:CGPointMake(pageWidth * nextPage, 0)];
}];
Ответ 3
У вас также может быть "медленная" прокрутка до конца UICollectionView
без необходимости "перескакивать" из индексного пути в индексный путь. Я создал это быстро для представления коллекции в приложении TVOS
:
func autoScroll () {
let co = collectionView.contentOffset.x
let no = co + 1
UIView.animateWithDuration(0.001, delay: 0, options: .CurveEaseInOut, animations: { [weak self]() -> Void in
self?.collectionView.contentOffset = CGPoint(x: no, y: 0)
}) { [weak self](finished) -> Void in
self?.autoScroll()
}
}
Я просто называю autoScroll()
в viewDidLoad()
, а остальная часть сама по себе заботится. Скорость прокрутки определяется временем анимации UIView
. Вы могли бы (я не пробовал) добавить NSTimer с 0
секунд вместо этого, чтобы вы могли аннулировать его на userscroll.
Ответ 4
Для кого-либо, кто нашел это, я обновил предложение Masa для работы над Swift, и я немного поучаствовал в этом, так что он больше похож на оригинальный анимированный звонок scrollItemsToIndexPath. На мой взгляд, у меня есть сотни предметов, поэтому устойчивый темп не был для меня вариантом.
var scrollPoint: CGPoint?
var endPoint: CGPoint?
var scrollTimer: NSTimer?
var scrollingUp = false
func scrollToIndexPath(path: NSIndexPath) {
let atts = self.collectionView!.layoutAttributesForItemAtIndexPath(path)
self.endPoint = CGPointMake(0, atts!.frame.origin.y - self.collectionView!.contentInset.top)
self.scrollPoint = self.collectionView!.contentOffset
self.scrollingUp = self.collectionView!.contentOffset.y > self.endPoint!.y
self.scrollTimer?.invalidate()
self.scrollTimer = NSTimer.scheduledTimerWithTimeInterval(0.01, target: self, selector: "scrollTimerTriggered:", userInfo: nil, repeats: true)
}
func scrollTimerTriggered(timer: NSTimer) {
let dif = fabs(self.scrollPoint!.y - self.endPoint!.y) / 1000.0
let modifier: CGFloat = self.scrollingUp ? -30 : 30
self.scrollPoint = CGPointMake(self.scrollPoint!.x, self.scrollPoint!.y + (modifier * dif))
self.collectionView?.contentOffset = self.scrollPoint!
if self.scrollingUp && self.collectionView!.contentOffset.y <= self.endPoint!.y {
self.collectionView!.contentOffset = self.endPoint!
timer.invalidate()
} else if !self.scrollingUp && self.collectionView!.contentOffset.y >= self.endPoint!.y {
self.collectionView!.contentOffset = self.endPoint!
timer.invalidate()
}
}
Тонкая настройка значений diff и модификаторов позволяет регулировать длительность/уровень удобства для большинства ситуаций.
Ответ 5
В файле .h,
объявите этот таймер,
NSTimer *Timer;
Поместите этот код таймера,
[CollectionView reloadData];
Timer = [NSTimer scheduledTimerWithTimeInterval:3 target:self selector:@selector(AutoScroll) userInfo:nil repeats:YES];
то
#pragma mark- Auto scroll image collectionview
-(void)AutoScroll
{
if (i<[Array count])
{
NSIndexPath *IndexPath = [NSIndexPath indexPathForRow:i inSection:0];
[self.ImageCollectionView scrollToItemAtIndexPath:IndexPath
atScrollPosition:UICollectionViewScrollPositionRight animated:NO];
i++;
if (i==[Array count])
{
i=0;
}
}
}
Надеюсь, это будет полезно.