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

Анимация содержимого UIScrollViewInset вызывает скачок заикания

Я воспользовался настраиваемым элементом управления обновлением (мой собственный класс, а не подкласс), и по какой-то причине, начиная с перехода на iOS 8, установка содержимого. В представлении прокрутки (в частности, UICollectionView) для запуска анимации обновления происходит странный переход/заикание. Вот мой код:

- (void)containingScrollViewDidScroll:(UIScrollView *)scrollView
{
    CGFloat scrollPosition = scrollView.contentOffset.y + scrollView.contentInset.top;

    if( scrollPosition > 0 || self.isRefreshing )
    {
        return;
    }

    CGFloat percentWidth = fabs( scrollPosition ) / self.frame.size.height / 2;

    CGRect maskFrame = self.maskLayer.frame;

    maskFrame.size.width = self.imageLayer.frame.size.width * percentWidth;

    [CATransaction begin];
    [CATransaction setValue:(id)kCFBooleanTrue forKey:kCATransactionDisableActions];
    self.maskLayer.frame = maskFrame;
    [CATransaction commit];
}

- (void)containingScrollViewDidEndDragging:(UIScrollView *)scrollView
{
    if( ( self.maskLayer.frame.size.width >= self.imageLayer.frame.size.width ) && !self.isRefreshing )
    {
        self.isRefreshing = YES;
        [self setLoadingScrollViewInsets:scrollView];
        [self startAnimation];
        [self sendActionsForControlEvents:UIControlEventValueChanged];
    }
}

- (void)setLoadingScrollViewInsets:(UIScrollView *)scrollView
{
    UIEdgeInsets loadingInset = scrollView.contentInset;
    loadingInset.top += self.frame.size.height;

    UIViewAnimationOptions options = UIViewAnimationOptionAllowUserInteraction | UIViewAnimationOptionBeginFromCurrentState;

    [UIView animateWithDuration:0.2 delay:0 options:options animations:^
    {
        scrollView.contentInset = loadingInset;
    }
    completion:nil];
}

Как только пользователь освободится для обновления, я обновляю contentInset до высоты элемента управления обновлением. Я полагаю, что анимация уменьшила бы заикание/прыткость, что и в iOS 7. Но в iOS 8, когда scrollView освобождается от перетаскивания, вместо того, чтобы просто анимировать содержимое ContentInset, содержимое представления прокрутки скачкообразно падает с точки выпуска быстро, а затем анимирует плавно. Я не уверен, что это ошибка в iOS 8 или что-то еще. Я также попытался добавить:

scrollView.contentOffset = CGPointZero;

в блоке анимации, который ничего не изменил.

Есть ли у кого-нибудь идеи? Любая помощь будет высоко оценен. Спасибо!

4b9b3361

Ответ 1

Я изменил метод с моим блоком анимации на:

- (void)setLoadingScrollViewInsets:(UIScrollView *)scrollView
{
    UIEdgeInsets loadingInset = scrollView.contentInset;
    loadingInset.top += self.view.frame.size.height;

    CGPoint contentOffset = scrollView.contentOffset;

    [UIView animateWithDuration:0.2 animations:^
    {
        scrollView.contentInset = loadingInset;
        scrollView.contentOffset = contentOffset;
    }];
}

Ответ 2

- (void)scrollViewDidEndDragging:(UIScrollView *)scrollView willDecelerate:(BOOL)decelerate{
    CGPoint point = scrollView.contentOffset;

    static CGFloat refreshViewHeight = 200.0f;

    if (scrollView.contentInset.top == refreshViewHeight) {
        //openning
        if (point.y>-refreshViewHeight) {
            //will close
            //必须套两层animation才能避免闪动!
            [UIView animateWithDuration:0 animations:NULL completion:^(BOOL finished) {
                [UIView animateWithDuration:0.25 animations:^{
                    scrollView.contentOffset = CGPointMake(0.0f, 0.0f);
                    scrollView.contentInset = UIEdgeInsetsMake(0.0f, 0.0f, 0.0f, 0.0f);
                } completion:NULL];
            }];

        }
    }
    else{
        //closing
        static CGFloat openCriticalY = 40.0f;//会执行打开的临界值
        if(point.y<-openCriticalY){
            //will open
            [UIView animateWithDuration:0 animations:NULL completion:^(BOOL finished) {
                [UIView animateWithDuration:0.25 animations:^{
                    scrollView.contentInset = UIEdgeInsetsMake(refreshViewHeight, 0.0f, 0.0f, 0.0f);
                    scrollView.contentOffset = CGPointMake(0.0f, -refreshViewHeight);
                } completion:NULL];
            }];
        }
    }
}

вы можете попробовать это, ключ использует две анимации.

Ответ 3

Чтобы удалить прыжок, ответ ryanthon сделает трюк. В моем приложении с iOS9.0 никакой блок анимации даже не требуется для удаления прыжка, просто сбросив контентОффсет после установки contentInset выполнит трюк.

Если вы хотите контролировать скорость прокрутки таблицыView, скрывая представление обновления, двойной трюк блоков анимации в user3044484 ответ будет делать магию, одного блока анимации недостаточно.

if (self.tableView.contentInset.top == 0)
{
    UIEdgeInsets tableViewInset = self.tableView.contentInset;
    tableViewInset.top = -1.*kTableHeaderHeight;
    [UIView animateWithDuration: 0 animations: ^(void){} completion:^(BOOL finished) {
        [UIView animateWithDuration: 0.5 animations:^{
        //no need to set contentOffset, setting contentInset will change contentOffset accordingly.
            self.tableView.contentInset = tableViewInset;  
        }];
    }];
}

Ответ 4

У меня была та же проблема, и я перенесла свой блок анимации в...

- (void)scrollViewWillBeginDecelerating:(UIScrollView *)scrollView

делегировать метод. Не идеально, но я пока не могу определить проблему. Похоже, что scrollView -layoutSubviews метод чаще всего вызывается под iOS8, вызывая оживленные анимации.

Ответ 5

Два решения:

  • отключить отскок при загрузке и включить откат при завершении загрузки
  • после установки вставки содержимого при загрузке, установите значение смещения содержимого с постоянным значением

Ответ 6

Я разрешил: -

  • Отключите Bounce, когда ContentInset обновляется до contentOffsetY.
  • Следить за содержимымОфис и обновить до TableView ContentInset.
 var contentOffsetY:CGFloat = 100
    func tracScrollContent(location: UIScrollView) {
        if(location.contentOffset.y  == -contentOffsetY ) {
            tblView.isScrollEnabled = true
            tblView.bounces = false
            tblView.contentInset = UIEdgeInsets(top: contentOffsetY, left: 0, bottom: 0, right: 0)
        }else if(location.contentOffset.y >= 0 ){
            tblView.bounces = true
            tblView.contentInset = UIEdgeInsets(top: 0, left: 0, bottom: 0, right: 0)
        }
    }

Github Demo Swift-3