Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

UITableView with UIRefreshControl under a semi-transparent status bar

I've created a UITableView which I want to scroll underneath my semi-transparent black status bar. In my XIB, I just set the table view's y position to -20 and it all looks fine.

Now, I've just added a pull-to-refresh iOS6 UIRefreshControl which works however, because of the -20 y position, it drags from behind the status bar. I'd like it's "stretched to" position to be under the status bar rather than behind.

It makes sense why it's messing up but there doesn't seem to be any difference changing it's frame and the tableview's content insets etc don't make a difference.

The docs suggest that once the refreshControl has been set, the UITableViewController takes care of it's position from then on.

Any ideas?

like image 619
NonatomicRetain Avatar asked Oct 16 '12 11:10

NonatomicRetain


3 Answers

You can subclass the UIRefreshControl and implement layoutSubviews like so:

@implementation RefreshControl {
    CGFloat topContentInset;
    BOOL topContentInsetSaved;
}

- (void)layoutSubviews {
    [super layoutSubviews];

    // getting containing scrollView
    UIScrollView *scrollView = (UIScrollView *)self.superview;

    // saving present top contentInset, because it can be changed by refresh control
    if (!topContentInsetSaved) {
        topContentInset = scrollView.contentInset.top;
        topContentInsetSaved = YES;
    }

    // saving own frame, that will be modified
    CGRect newFrame = self.frame;

    // if refresh control is fully or partially behind UINavigationBar
    if (scrollView.contentOffset.y + topContentInset > -newFrame.size.height) {
        // moving it with the rest of the content
        newFrame.origin.y = -newFrame.size.height;

    // if refresh control fully appeared
    } else {
        // keeping it at the same place
        newFrame.origin.y = scrollView.contentOffset.y + topContentInset;
    }

    // applying new frame to the refresh control
    self.frame = newFrame;
}

It takes tableView's contentInset into account, but you can change topContentInset variable to whatever value you need and it will handle the rest.

I hope the code is documented enough to understand how it works.

like image 136
Anthony Dmitriyev Avatar answered Sep 18 '22 15:09

Anthony Dmitriyev


Just subclass the UIRefreshControl and override layoutSubviews like this:

- (void)layoutSubviews
{
    UIScrollView* parentScrollView = (UIScrollView*)[self superview];

    CGSize viewSize = parentScrollView.frame.size;

    if (parentScrollView.contentInset.top + parentScrollView.contentOffset.y == 0 && !self.refreshing) {
        self.hidden = YES;
    } else {
        self.hidden = NO;
    }

    CGFloat y = parentScrollView.contentOffset.y + parentScrollView.scrollIndicatorInsets.top + 20;

    self.frame = CGRectMake(0, y, viewSize.width, viewSize.height);

    [super layoutSubviews];
}
like image 28
Cherpak Evgeny Avatar answered Sep 20 '22 15:09

Cherpak Evgeny


The current upvoted answer does not play well with the fact you pull the component down (as Anthony Dmitriyev pointed out), the offset is incorrect. The last part is to fix it.

Either way: subclass the UIRefreshControl with the following method:

- (void)layoutSubviews
{
    UIScrollView* parentScrollView = (UIScrollView*)[self superview];
    CGFloat extraOffset = parentScrollView.contentInset.top;

    CGSize viewSize = parentScrollView.frame.size;

    if (parentScrollView.contentInset.top + parentScrollView.contentOffset.y == 0 && !self.refreshing) {
        self.hidden = YES;
    } else {
        self.hidden = NO;
    }

    CGFloat y = parentScrollView.contentOffset.y + parentScrollView.scrollIndicatorInsets.top + extraOffset;

    if(y > -60 && !self.isRefreshing){
        y = -60;
    }else if(self.isRefreshing && y <30)
    {
        y = y-60;
    }
    else if(self.isRefreshing && y >=30)
    {
        y = (y-30) -y;
    }

    self.frame = CGRectMake(0, y, viewSize.width, viewSize.height);

    [super layoutSubviews];
}
like image 36
Kevin R Avatar answered Sep 18 '22 15:09

Kevin R