更改setContentOffset的速度:动画:?

时间:2010-12-10 01:06:18

标签: iphone objective-c uitableview animation

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

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

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

16 个答案:

答案 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 ))
    }) 
}    
}