Изменить скорость setContentOffset: animated :? - PullRequest
38 голосов
/ 10 декабря 2010

Есть ли способ изменить скорость анимации при прокрутке UITableView с помощью setContentOffset: animated :?Я хочу прокрутить его наверх, но медленно.Когда я пытаюсь выполнить следующее, это приводит к тому, что несколько нижних ячеек исчезают до начала анимации (в частности, те, которые не будут видны при выполнении прокрутки):

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

Любой другой способ обойтипроблема?Существует закрытый метод _setContentOffsetAnimationDuration, который работает, но я не хочу, чтобы меня отклонили из магазина приложений.

Ответы [ 15 ]

90 голосов
/ 02 февраля 2012
[UIView animateWithDuration:2.0 animations:^{
    scrollView.contentOffset = CGPointMake(x, y);
}];

Работает.

14 голосов
/ 11 февраля 2011

Я взял ответ 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: animated:.

11 голосов
/ 10 декабря 2010

Нет прямого способа сделать так, как вы это написали.Единственный способ, которым я могу сделать это, это сделать движение / анимацию самостоятельно.

Например, перемещение 1px каждые 1/10 секунды должно имитировать очень медленную анимацию прокрутки.(Так как математика с линейной анимацией очень проста!)

Если вы хотите получить более реалистичный или модный эффект и смоделировать эффект easy-in easy-off, то вам понадобятся математические вычисления для расчета пути Безье, чтобы вы зналиточная позиция в каждую 1/10 секунды, например

По крайней мере, первый подход не должен быть таким сложным.Просто используйте или -performSelector:withObject:afterDelay or NSTimers с

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

Надеюсь, это поможет

7 голосов
/ 05 июня 2017

Установка смещения контента напрямую у меня не сработала. Тем не менее, упаковка setContentOffset(offset, animated: false) внутри блока анимации сделала свое дело.

UIView.animate(withDuration: 0.5, animations: {
                self.tableView.setContentOffset(
               CGPoint(x: 0, y: yOffset), animated: false)
            })
5 голосов
/ 04 января 2011

Мне любопытно, нашли ли вы решение вашей проблемы.Моей первой идеей было использовать animateWithDuration:animations: вызов с блоком, устанавливающим contentOffset:

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

Побочные эффекты

Хотя это работает для простых примеров, оно также имеет очень нежелательные побочные эффекты.В отличие от setContentOffset:animated: все, что вы делаете в методах делегатов, также становится анимированным, как и метод делегатов scrollViewDidScroll:.

Я прокручиваю мозаичный скролл-просмотр с многоразовыми плитками.Это проверяется в scrollViewDidScroll:.Когда они действительно используются повторно, они получают новую позицию в представлении прокрутки, но это становится анимированным, поэтому есть плитки, анимирующие весь путь через представление.Выглядит круто, но совершенно бесполезно.Другим нежелательным побочным эффектом является то, что возможное тестирование попадания плиток и границ моего вида прокрутки мгновенно становится бесполезным, потому что contentOffset уже находится на новой позиции, как только выполняется блок анимации.Это заставляет вещи появляться и исчезать, пока они еще видны, относительно того, где они были переключены только за пределами представления прокрутки.

С setContentOffset:animated: это все не так.Похоже, что UIScrollView не использует тот же метод для внутреннего использования.

Есть ли у кого-нибудь еще предложения по изменению скорости / продолжительности выполнения UIScrollView setContentOffset:animated:?

2 голосов
/ 02 октября 2013

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


}
1 голос
/ 27 марта 2018

Вы можете установить продолжительность следующим образом:

scrollView.setValue (5.0, forKeyPath: «contentOffsetAnimationDuration») scrollView.setContentOffset (CGPoint (x: 100, y: 0), animated: true)

Это также позволит вам получить все ваши обычные обратные вызовы делегатов.

1 голос
/ 20 февраля 2013

ЕСЛИ все, что вы пытаетесь сделать, это прокручивать свое прокручиваемое изображение, я думаю, вы должны использовать прокручиваемый прямоугольник до видимого.Я только что опробовал этот код

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

, и он прокручивает вид прокрутки до нужного мне места на любой период, для которого я его устанавливаю.Ключ устанавливает animate в false.Когда было установлено значение true, скорость анимации была значением по умолчанию, установленным методом

0 голосов
/ 10 ноября 2018

Я использую transitionWithView:duration:options:animations:completion:

        [UIView transitionWithView:scrollView duration:3 options:(UIViewAnimationOptionCurveLinear) animations:^{
        transitionWithView:scrollView.contentOffset = CGPointMake(contentOffsetWidth, 0);
    } completion:nil];

UIViewAnimationOptionCurveLinear - это опция, позволяющая анимации происходить равномерно в течение.

Хотя я обнаружил, что во время анимации метод делегата scrollViewDidScroll не вызывается, пока не закончится анимация.

0 голосов
/ 14 июня 2017

На самом деле ответ TK189 частично верен.

Чтобы добиться настраиваемого изменения анимированного содержимого contentOffset при надлежащем повторном использовании ячеек компонентами UITableView и UICollectionView, вам просто нужно добавить вызов layoutIfNeeded внутри блока анимации:

[UIView animateWithDuration:2.0 animations:^{
    tableView.contentOffset = CGPointMake(x, y);
    [tableView layoutIfNeeded];
}];
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...