Подтвердить что ты не робот

Измените скорость setContentOffset: анимированный:?

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

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

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

4b9b3361

Ответ 1

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

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

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

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

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

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

Ответ 2

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

Он работает.

Ответ 3

Я принял 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:.

Ответ 4

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

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

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

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

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

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

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

Ответ 5

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

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

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

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

Ответ 7

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

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

Ответ 8

Для людей, у которых также есть проблемы с исчезающими элементами при прокрутке 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];
    }];
}];

Ответ 9

Собственно ответ TK189 является частично правильным.

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

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

Ответ 10

Вы можете просто использовать блочную анимацию для анимации скорости scrollview. Сначала вычислите точку смещения, которую вы хотите прокрутить, а затем просто передайте это значение смещения, как здесь.....

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

здесь colorPaletteScrollView - это мое собственное scrollview, а смещение - это пройденное значение.

этот код отлично работает для меня.

Ответ 11

Есть ли причина, по которой вы используете 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];

Если это не работает. Я все еще думаю, что вы должны попробовать.

Ответ 12

В 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);

Ответ 13

Я хотел изменить 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 ))
    }) 
}    
}