改变setContentOffset的速度:animated:?

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

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

任何其他方式解决这个问题? 有一个私有方法_setContentOffsetAnimationDuration可以工作,但我不想被拒绝从应用程序商店。

没有一个这样做的直接方式,也没有做你写的方式。 我能做到这一点的唯一方法就是通过我自己制作动作/animation。

例如,每1/10秒移动1px应该模拟一个非常慢的滚动animation。 (因为它的线性animationmath非常容易!)

如果你想得到更真实或更奇特的效果,并且模拟easy-off的easy-off效果,那么你需要一些math来计算一个bezierpath,所以你可以知道每1/10秒的确切位置,例如

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

 -[UIScrollView setContentOffset:(CGPoint*)];` 

希望能帮助到你

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

有用。

我已经采取了nacho4d的答案,并执行代码,所以我认为这将有助于其他人来到这个问题看到工作代码:

我将成员variables添加到我的类中:

 CGPoint startOffset; CGPoint destinationOffset; NSDate *startTime; NSTimer *timer; 

和属性:

 @property (nonatomic, retain) NSDate *startTime; @property (nonatomic, retain) NSTimer *timer; 

和一个计时器callback:

 - (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]; } 

然后:

 - (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]; } } 

您还需要在dealloc方法中清除计时器。 由于计时器将保留对目标(自我)的引用,并且自己有一个对计时器的引用,所以在viewWillDisappear中取消/销毁计时器的一些清理代码也可能是一个好主意。

对上述任何意见或改进build议将是非常受欢迎的,但它与我工作得很好,并解决了我与setContentOffset:animation:其他问题。

我很好奇你是否find了解决问题的办法。 我的第一个想法是使用animateWithDuration:animations:调用块设置contentOffset:

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

副作用

虽然这只是简单的例子,但它也有非常不希望的副作用。 与setContentOffset:animated:相反setContentOffset:animated:您在委托方法中执行的所有操作也会获得animation,如scrollViewDidScroll: delegate方法。

我滚动通过与可重复使用的瓷砖平铺滚动视图。 这将得到检查在scrollViewDidScroll: 当它们被重用时,它们会在滚动视图中获得一个新的位置,但是它会变成animation,所以在视图中一直都有animation。 看起来很酷,但完全没用。 另一个不希望的副作用是可能的命中testing的瓷砖和我的滚动视图的界限立即变得无用,因为contentOffset已经在一个新的位置,只要animation块执行。 这使得东西在它们仍然可见的时候显现和消失,就像它们曾经在滚动视图边界之外被切换的位置一样。

setContentOffset:animated:这一切都不是这样。 看起来像UIScrollView内部不使用相同的技术。

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

https://github.com/dominikhofmann/PRTween

子类UITableview

 #import "PRTween.h" @interface JPTableView : UITableView{ PRTweenOperation *activeTweenOperation; } - (void) doAnimatedScrollTo:(CGPoint)destinationOffset { CGPoint offset = [self contentOffset]; activeTweenOperation = [PRTweenCGPointLerp lerp:self property:@"contentOffset" from:offset to:destinationOffset duration:1.5]; } 

如果所有你想要做的是滚动你的滚动视图我认为你应该使用滚动矩形可见。 我刚刚试过这个代码

  [UIView animateWithDuration:.7 delay:0 options:UIViewAnimationOptionCurveEaseOut animations:^{ CGRect scrollToFrame = CGRectMake(0, slide.frame.origin.y, slide.frame.size.width, slide.frame.size.height + kPaddingFromTop*2); CGRect visibleFrame = CGRectMake(0, scrollView.contentOffset.y, scrollView.frame.size.width, scrollView.frame.size.height); if(!CGRectContainsRect(visibleFrame, slide.frame)) [self.scrollView scrollRectToVisible:scrollToFrame animated:FALSE];}]; 

它将滚动视图滚动到我需要的位置,无论我设置的时间长短。 关键是将animation设置为false。 当它被设置为true时,animation速度是由方法设置的默认值

直接设置内容偏移不适用于我。 然而,在一个animation块中包装setContentOffset(offset, animated: false)是个诀窍。

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

对于在滚动UITableView或UICollectionView时也遇到消失项目问题的用户,可以展开视图本身,以便容纳更多可见项目。 对于需要滚动很长距离或用户可以取消animation的情况,build议不要使用此解决scheme。 在我正在处理的应用程序中,我只需要让视图滚动一个固定的100像素。

NSInteger scrollTo = 100;

 CGRect frame = self.collectionView.frame; frame.size.height += scrollTo; [self.collectionView setFrame:frame]; [UIView animateWithDuration:0.8 delay:0.0 options:(UIViewAnimationOptionCurveEaseIn) animations:^{ [self.collectionView setContentOffset:CGPointMake(0, scrollTo)]; } completion:^(BOOL finished) { [UIView animateWithDuration:0.8 delay:0.0 options:(UIViewAnimationOptionCurveEaseIn) animations:^{ [self.collectionView setContentOffset:CGPointMake(0, 0)]; } completion:^(BOOL finished) { CGRect frame = self.collectionView.frame; frame.size.height -= scrollTo; [self.collectionView setFrame:frame]; }]; }]; 

其实TK189的答案是部分正确的。

要实现自定义持续时间animationcontentOffset更改,通过UITableView和UICollectionView组件适当的单元重用,您只需在animation块内添加一个layoutIfNeeded调用:

 [UIView animateWithDuration:2.0 animations:^{ tableView.contentOffset = CGPointMake(x, y); [tableView layoutIfNeeded]; }]; 

您可以简单地使用基于块的animation来animation滚动视图的速度。 首先计算你想要滚动的偏移点,然后简单地传递这个偏移值,就像这里一样…..

  [UIView animateWithDuration:1.2 delay:0.02 options:UIViewAnimationCurveLinear animations:^{ [colorPaletteScrollView setContentOffset: offset ]; } completion:^(BOOL finished) { NSLog(@"animate"); } ]; 

这里colorPaletteScrollView是我的自定义滚动视图和偏移量是传递的值。

这段代码对我来说工作得很好。

是否有你使用setContentOffset而不是scrollRectToVisible的原因:animated:?

 - (void)scrollRectToVisible:(CGRect)rect animated:(BOOL)animated 

我会推荐这样做:

 [UIView beginAnimations:nil context:nil]; [UIView setAnimationDuration:3.0]; [self.tableView scrollRectToVisible:CGRectMake(0, 0, 320, 0) animated:NO]; [UIView commitAnimations]; 

除非那不起作用。 我仍然认为你应该尝试一下。

在Xcode 7.1上 – Swift 2.0:

 func textFieldShouldEndEditing(textField: UITextField) -> Bool { dispatch_async(dispatch_get_main_queue()) { UIView.animateWithDuration(0, animations: { self.scrollView!.setContentOffset(CGPointZero,animated: true) }) } return true } 

要么

 func textFieldShouldReturn(textField: UITextField) -> Bool { if(textField.returnKeyType == UIReturnKeyType.Next) { password.becomeFirstResponder() } dispatch_async(dispatch_get_main_queue()) { UIView.animateWithDuration(0, animations: { self.scrollView!.setContentOffset(CGPointZero,animated: true) }) } textField.resignFirstResponder() return true } 

注意:根据需求,self.scrollView!.setContentOffset(CGPointZero,animated:true)可以有不同的位置

例:

 let scrollPoint:CGPoint = CGPointMake(0,textField.frame.origin.y/2); scrollView!.setContentOffset(scrollPoint, animated: true); 

我想在textfield开始编辑时改变tableview的contentOffSet。

Swift 3.0

 func textFieldDidBeginEditing(_ textField: UITextField) { DispatchQueue.main.async { UIView.animate(withDuration: 0, animations: { self.sampleTableView.contentOffset = CGPoint(x: 0, y: 0 - (self.sampleTableView.contentInset.top - 200 )) }) } }