akaru
akaru

Reputation: 6317

UITableView pull to refresh causing flickering. How to prevent it?

I'm doing that pull-down-to-refresh thing. In scrollViewDidEndDecelerating I check if the offset is past a certain point and in scrollViewDidEndDragging I set the contentInset so as to keep the pulled-down section visible.

However, this results in flickering, probably due to the contentInset being reset during scrolling animation. I thought I might be able to prevent this by setting the targetContentOffset in scrollViewWillEndDragging, but it doesn't seem to do the trick.

 - (void)scrollViewDidEndDragging:(UIScrollView *)scrollView willDecelerate:(BOOL)decelerate 
{

     if (scrollView.contentOffset.y < -kRefreshViewDelta) 
     {
         self.tableView.contentInset = UIEdgeInsetsMake(kRefreshViewHeight, 0.0f, 0.0f, 0.0f);

     }
}

- (void)scrollViewWillEndDragging:(UIScrollView *)scrollView withVelocity:(CGPoint)velocity targetContentOffset:(inout CGPoint *)targetContentOffset
 {
     if (scrollView.contentOffset.y  < -kRefreshViewDelta) 
     {
          targetContentOffset->y = kRefreshViewHeight ;
     }
 }

Upvotes: 5

Views: 5948

Answers (3)

sc0rp10n
sc0rp10n

Reputation: 1118

Mike's answer worked for me (but I couldn't up-vote or comment on it). It appears that wrapping my code in the animation block eliminated the flicker for me.

- (void)scrollViewDidEndDragging:(UIScrollView *)scrollView willDecelerate:(BOOL)decelerate 
{
    if (scrollView.contentOffset.y < 0 && scrollView.contentInset.top < 0)
    {
        // shows table header view
        // setting inset without using animation block causes flicker
        [UIView animateWithDuration:0.1 animations:^
        {
            scrollView.contentInset = UIEdgeInsetsZero;
        }];
    }

    // hides table header view
    if (scrollView.contentOffset.y > 44 && scrollView.contentInset.top == 0)
    {
        scrollView.contentInset = UIEdgeInsetsMake(-44, 0, 0, 0);
    }
}

Upvotes: 4

Sanchit Paurush
Sanchit Paurush

Reputation: 6152

I tried a different mechanism for this pull to refresh. Please check the code

- (void)scrollViewWillBeginDragging:(UIScrollView *)scrollView
{
    if (!reloading)
    {
        checkForRefresh = YES;  //  only check offset when dragging
    }
}

- (void)scrollViewDidScroll:(UIScrollView *)scrollView
{
    if (reloading) return;

    if (checkForRefresh) {
        if (refreshHeaderView.isFlipped
            && scrollView.contentOffset.y > -65.0f
            && scrollView.contentOffset.y < 0.0f
            && !reloading) {
            [refreshHeaderView flipImageAnimated:YES];
            [refreshHeaderView setStatus:kPullToReloadStatus];


        } else if (!refreshHeaderView.isFlipped
                   && scrollView.contentOffset.y < -65.0f) {
            [refreshHeaderView flipImageAnimated:YES];
            [refreshHeaderView setStatus:kReleaseToReloadStatus];

        }
    }
}
- (void)scrollViewDidEndDragging:(UIScrollView *)scrollView
                  willDecelerate:(BOOL)decelerate
{
    if (reloading) return;

    if (scrollView.contentOffset.y <= - 65.0f) {
        if([self.tableView.dataSource respondsToSelector:
            @selector(reloadTableViewDataSource)]){
            [self showReloadAnimationAnimated:YES];
            [self reloadTableViewDataSource];
        }
    }
    checkForRefresh = NO;
}   


- (void)reloadTableViewDataSource
{
    [self performSelectorOnMainThread:@selector(refresh) withObject:nil waitUntilDone:NO];

}

Upvotes: 0

Mike Welsh
Mike Welsh

Reputation: 808

If you change the frame assigned to the UITableView at all (during the scrolling or otherwise), it will cause the contentInset to be reset to the default (0,0,0,0). There is some state checking for mine, but essentially this is what I've done for mine...

- (void)scrollViewDidEndDragging:(UIScrollView *)scrollView
                  willDecelerate:(BOOL)decelerate {
  if (scrollView.contentOffset.y < -kRefreshDeltaY) {
    animation = ^{
        [self setContentInset:UIEdgeInsetsMake(kRefreshDeltaY,
                                                          0, 0, 0)];
    };

    [UIView animateWithDuration:0.3
                          delay:0
                        options:UIViewAnimationOptionAllowUserInteraction
                     animations:animation
                     completion:completion];
  } // if
}

As long as I didn't lay out subviews or change the frame of the UITableView, it behaved fine for me.

Upvotes: 10

Related Questions