12

I have a UINavigationController in my app. The UINavigationBar is set to opaque and all the scroll views do not overlap underneath the bar.

In one view I have a UITableView. The frame of the UITableView is (0 0; 320 504) on my iPhone 5. i.e. the height is 568 - 64 (the height of the nav bar and status bar).

The contentInset of the UITableView is (0, 0, 0, 0). When the table view first loads the contentOffset is (0, 0).

This is fine. Works brilliantly.

I added a UIRefreshControl to the table view. This works a couple of times but then after a few times of doing pull to refresh then the content at the top gets "stuck" under the nav bar.

When this happens I inspect the contentInset and it is now (-60, 0, 0, 0).

Is there any way to stop the UIRefreshControl from changing the contentInset?

Fogmeister
  • 76,236
  • 42
  • 207
  • 306
  • Removed my answer since you obviuosly already ruled it out. You are calling endRefreshing, I assume? – jhilgert00 Nov 20 '13 at 16:54
  • No worries. Yeah, when I call `endRefreshing` on the control it disappears. This works fine a few times but then it freaks out and the `contentInset` changes hiding the top few rows under the navigation bar. – Fogmeister Nov 20 '13 at 16:56
  • You could probably get away with resetting your frame after the refresh, but you shouldn't have to. – jhilgert00 Nov 20 '13 at 16:59
  • I've got round it for now by manually setting the contentInset back to 0 after ending the refresh. But now it doesn't animate the disappearance of the refresh control. It just jumps back. If I try animate it it crashes. lol – Fogmeister Nov 20 '13 at 17:00
  • One last thing you might try is adding the UIRefreshControl in IB. on the Storyboard if you click on the UITableviewController, and in the Attributes Inspecter, set the Refreshing setting to enabled, it adds a UIRefresh controll for you. Then you can link an IBAction to it or ad a selector in viewDidLoad. Might be worth a shot. – jhilgert00 Nov 20 '13 at 17:04
  • Ah, it sounds like you might be on to something with that. Unfortunately though, I'm using a UIViewController with a UITableView rather than a UITableViewController. I'll def give it a try next time. Thanks – Fogmeister Nov 20 '13 at 17:46

4 Answers4

7

This is probably the reason why UIRefreshControl is currently only supported on UITableViewController, rather than by addition to any scrollview (which you can get away with, in many cases).

The refresh control does its magic by tinkering with the content insets of the scrollview - particularly when it ends refreshing. Unfortunately the view controller is also tinkering with the content insets of the scroll view to fit it under the translucent nav and status bars. Fun ensues. Is this also an issue on iOS 6 (or, "good old iOS6" as I called it when dealing with the same issue).

The quickest solution is probably to add your table view as a child UITableViewController instead of a simple subview. I think that UITableViewController manages the insets for you at the end of the refresh. If that doesn't work, I've got workarounds for this but it will have to wait until I get back in the office.

jrturton
  • 118,105
  • 32
  • 252
  • 268
  • 1
    I seem to have fixed this now. I realised that the `completionBlock` of `NSOperation` is called on the same thread as the operation. This is where I was calling `endRefreshing`. I dispatched this to the main thread and it's working now without changing the `contentInset`. Do you have a link to anything about `UIRefreshControl` only officially support `UITVC`? – Fogmeister Nov 21 '13 at 00:29
  • The docs say that it is made to be assigned to a UITVC. The addSubview: thing is only mentioned on SO, never in the docs. – jrturton Nov 21 '13 at 07:03
  • See Dave DeLong's comment on this answer: http://stackoverflow.com/a/12502450/852828 – jrturton Nov 21 '13 at 08:55
  • I changed the whole thing to a uitvc instead and it all works fine now. Even after changing to the main thread I had problems with it showing strange behaviour. – Fogmeister Nov 22 '13 at 22:00
  • I am having exactly same problem.I am using UiRefreshControl with a UICollectionView.It seemed to change my contentInset.After endRefresh I am again setting my contentInset to proper value.It that way ok? Or Do we have to refrain from using UIRefreshControl with CollectionView – user1010819 Dec 10 '13 at 01:35
7

I will add this answer here in case any one has problems with UIRefreshControl by changing the control properties (attributed title, tint, etc...):

Don't mess with the UIRefreshControl on -viewDidLoad:, use -viewDidAppear: instead.

Bruno Philipe
  • 1,091
  • 11
  • 20
  • 1
    Make sure that you put a condition if(!refreshControl) else everytime your page appears it add refreshcontrol to it. – George Aug 31 '16 at 15:34
5

Reset your table view contentInset.

-(void)pullToRefresh
{
    [self.tableView reloadData];
    [self.refreshControl endRefreshing];
    [self.tableView setContentInset:UIEdgeInsetsMake(0, 0, 0, 0)];
}
situee
  • 2,710
  • 2
  • 22
  • 27
4

You need override setContentInset: in you UICollectionView

- (void)setContentInset:(UIEdgeInsets)contentInset {
  if (self.tracking) {
    CGFloat difference = contentInset.top - self.contentInset.top;
    CGPoint translation = [self.panGestureRecognizer translationInView:self];
    translation.y -= difference * 3.0 / 2.0;
    [self.panGestureRecognizer setTranslation:translation inView:self];
  }
  [super setContentInset:contentInset];
}
Sergey Petruk
  • 781
  • 7
  • 13