更改setContentOffset的速度:动画:?

Jor*_*Kay 38 iphone animation objective-c uitableview

有没有办法在UITableView使用setContentOffset 滚动时改变动画的速度:动画:?我想将它滚动到顶部,但慢慢地.当我尝试以下操作时,它会导致底部的几个单元格在动画开始之前消失(特别是滚动完成时不可见的那些):

[UIView beginAnimations:nil context:nil];
[UIView setAnimationDuration:3.0];
[self.tableView setContentOffset:CGPointMake(0, 0)];
[UIView commitAnimations];
Run Code Online (Sandbox Code Playgroud)

还有其他方法解决这个问题吗?有一种私有方法_setContentOffsetAnimationDuration可以使用,但我不想被应用商店拒绝.

TK1*_*189 90

[UIView animateWithDuration:2.0 animations:^{
    scrollView.contentOffset = CGPointMake(x, y);
}];
Run Code Online (Sandbox Code Playgroud)

有用.

  • 好吧,如果您的滚动视图是一个uitableview,它就不起作用.创建和重用单元失败. (38认同)
  • 也不适用于`UICollectionView`. (8认同)
  • 嗯,它有效,但不是在问题的背景下.我的细胞也在消失! (4认同)

Jos*_*phH 14

我已经采纳了nacho4d的答案并实现了代码,因此我认为对于其他人来说这个问题看看工作代码会有所帮助:

我向我的班级添加了成员​​变量:

CGPoint startOffset;
CGPoint destinationOffset;
NSDate *startTime;

NSTimer *timer;
Run Code Online (Sandbox Code Playgroud)

和属性:

@property (nonatomic, retain) NSDate *startTime;
@property (nonatomic, retain) NSTimer *timer;
Run Code Online (Sandbox Code Playgroud)

和一个计时器回调:

- (void) animateScroll:(NSTimer *)timerParam
{
    const NSTimeInterval duration = 0.2;

    NSTimeInterval timeRunning = -[startTime timeIntervalSinceNow];

    if (timeRunning >= duration)
    {
        [self setContentOffset:destinationOffset animated:NO];
        [timer invalidate];
        timer = nil;
        return;
    }
    CGPoint offset = [self contentOffset];

    offset.x = startOffset.x +
        (destinationOffset.x - startOffset.x) * timeRunning / duration;

    [self setContentOffset:offset animated:NO];
}
Run Code Online (Sandbox Code Playgroud)

然后:

- (void) doAnimatedScrollTo:(CGPoint)offset
{
    self.startTime = [NSDate date];
    startOffset = self.contentOffset;
    destinationOffset = offset;

    if (!timer)
    {
        self.timer = [NSTimer scheduledTimerWithTimeInterval:0.01
                                                      target:self
                                                    selector:@selector(animateScroll:)
                                                    userInfo:nil
                                                     repeats:YES];
    }
}
Run Code Online (Sandbox Code Playgroud)

你还需要在dealloc方法中清理定时器.由于计时器将保留对目标的引用(self)并且self具有对计时器的引用,因此在viewWillDisappear中取消/销毁计时器的一些清理代码也可能是个好主意.

对上述内容的任何评论或改进建议都会受到欢迎,但它与我合作很好,并解决了我在setContentOffset中遇到的其他问题:动画:

  • 不要将NSTimer用于动画,请使用CADisplayLink.例如:http://www.bigspaceship.com/ios-animation-intervals/ (2认同)

nac*_*o4d 11

没有直接的方法可以做到这一点,也没有按照你写的方式.我能做到这一点的唯一方法就是通过我自己制作动作/动画.

例如,每1/10秒移动1px应该模拟一个非常慢的滚动动画.(因为它的线性动画数学非常简单!)

如果你想获得更逼真或更真实并且模拟易于轻松的效果,那么你需要一些数学来计算贝塞尔曲线路径,这样你就可以知道每1/10秒的确切位置,例如

至少第一种方法不应该那么困难.只需使用或-performSelector:withObject:afterDelay or NSTimers使用

-[UIScrollView setContentOffset:(CGPoint*)];`
Run Code Online (Sandbox Code Playgroud)

希望能帮助到你


小智 9

直接设置内容偏移对我不起作用.但是,setContentOffset(offset, animated: false)在动画块中包装可以解决问题.

UIView.animate(withDuration: 0.5, animations: {
                self.tableView.setContentOffset(
               CGPoint(x: 0, y: yOffset), animated: false)
            })
Run Code Online (Sandbox Code Playgroud)


epo*_*gee 5

我很好奇你是否找到了问题的解决方案.我的第一个想法是使用animateWithDuration:animations:带有设置contentOffset的块的调用:

[UIView animateWithDuration:2.0 animations:^{
    scrollView.contentOffset = CGPointMake(x, y);
}];
Run Code Online (Sandbox Code Playgroud)

副作用

虽然这适用于简单的例子,但它也有非常多的副作用.与setContentOffset:animated:您在委托方法中所做的一切相反,也会像scrollViewDidScroll:委托方法一样获得动画.

我正在滚动浏览带有可重复使用磁贴的平铺滚动视图.这将在中检查scrollViewDidScroll:.当它们被重用时,它们会在滚动视图中获得一个新位置,但是它会被动画化,因此在视图中一直有动画效果.看起来很酷,但完全没用.另一个不需要的副作用是,可能对图块进行命中测试,我的滚动视图边界立即变得无用,因为只要动画块执行,contentOffset就已经处于新位置.这使得东西在它们仍然可见的情况下显示和消失,就像它们曾经在滚动视图边界之外切换的位置一样.

有了setContentOffset:animated:这一切并非如此.看起来UIScrollView内部没有使用相同的技术.

有没有人有另一个建议来改变UIScrollView setContentOffset:animated:执行的速度/持续时间?


Igo*_*gor 5

UIView 计算最终视图,然后对其进行动画处理。这就是为什么在动画结束时不可见的单元格在开始时也不可见。为了防止这种情况需要在动画块中添加 layoutIfNeeded:

[UIView animateWithDuration:2.0 animations:^{
    [self.tableView setContentOffset:CGPointMake(0, 0)];
    [self.tableView layoutIfNeeded]
}];
Run Code Online (Sandbox Code Playgroud)

迅捷版:

UIView.animate(withDuration: 2) {
    self.tableView.contentOffset.y = 10
    self.tableView.layoutIfNeeded()
}
Run Code Online (Sandbox Code Playgroud)