在UICollectionView中创建到indexPath的慢速滚动

时间:2012-10-22 07:43:26

标签: ios scroll uiviewanimation nsindexpath 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];

这会产生所需的滚动速度,但只有最后几个单元格在系列中可见。我怀疑它们(甚至是起始的可见细胞)都会立即出现。

有什么想法吗?

5 个答案:

答案 0 :(得分:16)

您可以尝试这种方法:

@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);
}

答案 1 :(得分:12)

我使用“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)];
                 }];

答案 2 :(得分:7)

你也可能有一个"慢"滚动到你UICollectionView的末尾,而不必跳过"跳跃"从indexpath到indexpath。我在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的动画时间决定。你可以(我还没试过)添加一个0秒的NSTimer,这样你就可以在用户滚动上使它无效。

答案 3 :(得分:3)

对于其他任何发现这一点的人,我已经更新了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()
    }
}

调整dif和修饰符的值可调整大多数情况下的持续时间/缓和程度。

答案 4 :(得分:0)

在.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;
        }
    }
}

希望它有用。