Reputation: 6317
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
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
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
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