使用setContentOffset滚动UITableView
时是否有办法更改动画的速度:动画:?我想将它滚动到顶部,但慢慢地。当我尝试以下操作时,它会导致底部的几个单元格在动画开始之前消失(特别是滚动完成时不可见的那些):
[UIView beginAnimations:nil context:nil];
[UIView setAnimationDuration:3.0];
[self.tableView setContentOffset:CGPointMake(0, 0)];
[UIView commitAnimations];
还有其他解决这个问题的方法吗?有一种私有方法_setContentOffsetAnimationDuration
可以使用,但我不想被应用商店拒绝。
答案 0 :(得分:90)
[UIView animateWithDuration:2.0 animations:^{
scrollView.contentOffset = CGPointMake(x, y);
}];
有效。
答案 1 :(得分:14)
我已经采纳了nacho4d的答案并实现了代码,所以我认为对于其他人来说这个问题看看工作代码会有所帮助:
我将成员变量添加到我的班级:
CGPoint startOffset;
CGPoint destinationOffset;
NSDate *startTime;
NSTimer *timer;
和属性:
@property (nonatomic, retain) NSDate *startTime;
@property (nonatomic, retain) NSTimer *timer;
和计时器回调:
- (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方法中清理定时器。由于计时器将保留对目标的引用(self)并且self具有对计时器的引用,因此在viewWillDisappear中取消/销毁计时器的一些清理代码也可能是个好主意。
对上述内容的任何评论或改进建议都会受到欢迎,但它与我合作很好,并解决了我在setContentOffset中遇到的其他问题:动画:。
答案 2 :(得分:11)
没有直接的方法可以做到这一点,也没有像你写的那样。我能做到这一点的唯一方法就是通过我自己制作动作/动画。
例如,每1/10秒移动1px应模拟一个非常慢的滚动动画。 (因为它的线性动画数学很容易!)
如果你想获得更逼真或更花哨的效果并模拟易于轻松的效果,那么你需要一些数学来计算贝塞尔曲线路径,这样你才能知道每1/10秒的确切位置,例如
至少第一种方法不应该那么困难。
只需使用或-performSelector:withObject:afterDelay or NSTimers
与
-[UIScrollView setContentOffset:(CGPoint*)];`
希望有所帮助
答案 3 :(得分:7)
直接设置内容偏移对我不起作用。但是,在动画块中包装setContentOffset(offset, animated: false)
可以解决问题。
UIView.animate(withDuration: 0.5, animations: {
self.tableView.setContentOffset(
CGPoint(x: 0, y: yOffset), animated: false)
})
答案 4 :(得分:5)
我很好奇你是否找到了问题的解决方案。我的第一个想法是使用animateWithDuration:animations:
调用一个块来设置contentOffset:
[UIView animateWithDuration:2.0 animations:^{
scrollView.contentOffset = CGPointMake(x, y);
}];
虽然这适用于简单的例子,但它也有非常多的副作用。与setContentOffset:animated:
相反,您在委托方法中所做的一切也都会被动画化,例如scrollViewDidScroll:
委托方法。
我正在滚动浏览带有可重复使用磁贴的平铺滚动视图。这会在scrollViewDidScroll:
中进行检查。当它们被重用时,它们会在滚动视图中获得一个新位置,但是它会被动画化,因此在视图中一直有动画效果。看起来很酷,但完全没用。另一个不需要的副作用是可能对图块进行命中测试,我的滚动视图边界立即变得无用,因为只要动画块执行,contentOffset就已经处于新位置。这使得东西在它们仍然可见的情况下显示和消失,以及它们曾经在滚动视图边界之外切换的位置。
使用setContentOffset:animated:
并非如此。看起来UIScrollView内部没有使用相同的技术。
是否还有其他人建议更改UIScrollView setContentOffset:animated:
执行的速度/持续时间?
答案 5 :(得分:2)
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];
}
答案 6 :(得分:2)
UIView计算最终视图,然后对其进行动画处理。这就是为什么动画结束时不可见的单元格也开始播放的原因。为了防止这种情况,请在动画块中添加layoutIfNeeded:
[UIView animateWithDuration:2.0 animations:^{
[self.tableView setContentOffset:CGPointMake(0, 0)];
[self.tableView layoutIfNeeded]
}];
快速版本:
UIView.animate(withDuration: 2) {
self.tableView.contentOffset.y = 10
self.tableView.layoutIfNeeded()
}
答案 7 :(得分:1)
如果你想要做的就是滚动你的滚动视图,我认为你应该使用滚动矩形来显示。我刚刚尝试了这段代码
[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];}];
并将滚动视图滚动到我需要的任何持续时间所需的位置。关键是将动画设置为false。当它设置为true时,动画速度是方法
设置的默认值答案 8 :(得分:1)
您可以按如下方式设置持续时间:
scrollView.setValue(5.0,forKeyPath:“contentOffsetAnimationDuration”)scrollView.setContentOffset(CGPoint(x:100,y:0),animated:true)
这也可以让你获得所有常规委托回调。
答案 9 :(得分:0)
对于在滚动UITableView或UICollectionView时也有消失项目问题的人,您可以展开视图本身,以便我们保存更多可见项目。对于需要滚动较远距离的情况或用户可以取消动画的情况,不建议使用此解决方案。在我正在处理的应用程序中,我只需要让视图滚动固定的100px。
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];
}];
}];
答案 10 :(得分:0)
我使用transitionWithView:duration:options:animations:completion:
[UIView transitionWithView:scrollView duration:3 options:(UIViewAnimationOptionCurveLinear) animations:^{
transitionWithView:scrollView.contentOffset = CGPointMake(contentOffsetWidth, 0);
} completion:nil];
UIViewAnimationOptionCurveLinear
是使动画均匀出现的一个选项。
虽然我发现在动画持续时间内,委托方法scrollViewDidScroll
直到动画结束才被调用。
答案 11 :(得分:-1)
您可以简单地使用基于块的动画来设置scrollview的速度。 首先计算你想要滚动的偏移点,然后简单地将该偏移值传递给这里......
[UIView animateWithDuration:1.2
delay:0.02
options:UIViewAnimationCurveLinear
animations:^{
[colorPaletteScrollView setContentOffset: offset ];
}
completion:^(BOOL finished)
{ NSLog(@"animate");
} ];
这里colorPaletteScrollView是我的自定义scrollview,offset是传递的值。
这段代码对我来说非常合适。
答案 12 :(得分:-2)
你有没有理由使用setContentOffset而不是scrollRectToVisible:动画:?
- (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];
除非那不起作用。我仍然认为你应该尝试一下。
答案 13 :(得分:-2)
实际上TK189的答案部分正确。
要实现自定义持续时间动画contentOffset更改,通过UITableView和UICollectionView组件正确重用单元格,您只需在动画块中添加 layoutIfNeeded 调用:
[UIView animateWithDuration:2.0 animations:^{
tableView.contentOffset = CGPointMake(x, y);
[tableView layoutIfNeeded];
}];
答案 14 :(得分:-3)
在Xcode 7.1上 - Swift 2.0:
function foo(options) {
options = options || {};
var a = options.a || 'peanut'; // whatever default value
var b = options.b || 'butter'; // whatever default value
console.log(a, b);
}
// ES6 allows automatic destructuring
function foo({a = 'peanut', b = 'butter'} = {}) {
console.log(a, b);
}
OR
func textFieldShouldEndEditing(textField: UITextField) -> Bool {
dispatch_async(dispatch_get_main_queue()) {
UIView.animateWithDuration(0, animations: { self.scrollView!.setContentOffset(CGPointZero,animated: true) })
}
return true
}
注意:self.scrollView!.setContentOffset(CGPointZero,animated: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
}
答案 15 :(得分:-3)
我想在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 ))
})
}
}