128

I'm currently migrating my app on ios 7 and I've been stuck for hours on the new navigationcontroller/bar management.

Before, when we had a navigation controller, we had a snippet like this :

UINavigationController *navController = [[UINavigationController alloc]initWithRootViewController:[[MainViewController alloc]init]];

In interface builder, we had the choice to set an existing navigationbar for the view and everything match the content of the real view.

OK so now, i have no clue of how to design properly with interface builder. I still have my snippet to initialize my navcontroller. However in the interface builder for my MainViewController if I set a status bar to translucent or opaque navigation bar, i have an offset of 44px at the top (see below).


Interface Builder_________________________And the result


Now, if i set status bar to none, there is no offset at top but since the view on simulator is smaller because of navigation bar the bottom of the view in interface builder is cut off.

Interface Builder_________________________And the result

I guess i'm really missing something here but i can't find any topic or apple info in iOS7 Transitions Guide about that.

Thanks for your help


EDIT

As we can see in the pictures, the first child of the view is a UIScrollView which contains both labels, the problem does not appear when there is no scrollview. It also appears if it's a UITableView. If a label is outside the UIScrollView, there is no offset to that label.

Martijn Pieters
  • 1,048,767
  • 296
  • 4,058
  • 3,343
streem
  • 9,044
  • 5
  • 30
  • 41
  • You may want to use Autolayout if you are not, so you can make sure certain views are a set distance away from the top/bottom/side of the screen – erdekhayser Sep 23 '13 at 20:12
  • I'm indeed not using Autolayout, but using it (ticking the checkbox) does not solve the problem. – streem Sep 23 '13 at 21:02
  • With Autolayout, you must set constraints in order for the views to stay in place. Xcode does not know what you want automatically. – erdekhayser Sep 23 '13 at 21:10
  • Seeing your previous edit, I just discovered your issue. Unfortunately, it is not the most obvious solution. Rather than trying to explain it all over again, I used this video on Youtube to learn how to set up scroll views. http://www.youtube.com/watch?v=PgeNPRBrB18&feature=youtu.be Good Luck. It took me a couple times to watch it to fully understand what he is doing. – erdekhayser Sep 23 '13 at 21:12

9 Answers9

289

OK so i found the solution, I have set in my controller the property:

self.automaticallyAdjustsScrollViewInsets = false

I don't really understand the true benefit of this property though, (or why the default value is true)

The only documentation i found was there:

Update

In iOS 11 automaticallyAdjustsScrollViewInsets is deprecated

You should now use:

self.tableView.contentInsetAdjustmentBehavior = .never

I also encourage you to check this question and its answer to get a better understanding of those properties

streem
  • 9,044
  • 5
  • 30
  • 41
  • 12
    Great find. UIScrollView in storyboard is really complicated. I wish Apple makes it a bit seamless in future versions of Xcode. – p0lAris Oct 08 '13 at 03:41
  • 4
    This code prevents my `UIScrollView` from scrolling. But without this I can't get rid off the offset. Weired... – scaryguy Jan 12 '14 at 19:42
  • 9
    This flag can also be switched off in your storyboard/nib, the View Controller has an "Adjust Scroll View Insets" checkbox. I've been banging my head against a wall for so long now trying to sort out my problems with scroll views and auto layout, further complicated by supporting iOS 6 & 7. So thanks so much for finally providing a solution! – Newtz Jan 28 '14 at 11:59
  • 2
    App document would tell you that setting navigationbar.translucent = YES would prevent navigationbar from pushing the content down. It is the biggest lie and costed me many hours of work until this post. In addition, you must set self.automaticallyAdjustsScrollViewInsets = NO; Thank you so much for this post!!!!!!! Apple and apple? – user779764 Feb 16 '14 at 01:11
  • I found that this caused my UIScrollView's bounds to shift down by the height of the nav bar (-64points). I manually overrode this to 0, but found the UISrollView would still scroll in the y-axis, and "snap" to an imaginary line at -64. Your solution solved this. – gdbj Dec 24 '14 at 10:07
  • Fantastic, solved all my woes with my webviews in my scrollview. – BountyBob May 27 '15 at 13:28
  • http://stackoverflow.com/questions/24691614/why-is-uiscrollview-leaving-space-on-top-and-does-not-scroll-to-the-bottom – Jayesh Miruliya Mar 16 '16 at 07:19
  • Have been struggling with this issue for long enough now. Can't thank you enough. previously tried hiding UINavigationBar entirely, but it had different issues associated with it. – Shubham Naik Sep 17 '16 at 06:05
  • doc link is dead – Cœur Jun 28 '17 at 13:14
92

@Justafinger's answer worked like a charm for me as well.

Just wanted to add that this setting can also be adjusted easily from the interface builder.

  1. Select your view controller
  2. Click the 'Attributes Inspector' tab
  3. Uncheck 'Adjust Scroll View Insets'
  4. Enjoy!

enter image description here

Myxtic
  • 5,679
  • 5
  • 48
  • 69
11

I was running into this same issue, but I found a rather odd property on the ViewController in interface builder that seems to have been causing this for me. There is an "Extend Edges" set of check boxes. I removed the "Under Top Bars" check, and everything started laying out properly for me.

Ben Nicholas
  • 111
  • 1
  • 2
2

With automaticallyAdjustsScrollViewInsets set to YES (the default setting) there is a mismatch in scrollview positioning between ios6 and ios7, so to make them consistent you need to disable this setting. However, ios6 will crash if it comes across automaticallyAdjustsScrollViewInsets, so you either need to make a programatic change of automaticallyAdjustsScrollViewInsets conditional on ios7 or else switch off the option using the storyboard/NIB

dawid
  • 374
  • 5
  • 9
2

I had a similar problem, after dismissing a viewController, the contentOffset from my tableView was changed to (0, -64).

my solution was a little weird, I tried all the other answers but had no success, the only thing that fixed my problem was to switch the tableView position in the controls tree of the .xib

it was the first control in the parent View like this:

before

I moved the tableView right after the ImageView and it worked:

after

it seems that putting the table view in the first position was causing the trouble, and moving the table view to another position fixed the problem.

P.D. I'm not using autoLayout neither storyboards

hope this can help someone!

Chuy47
  • 2,391
  • 1
  • 30
  • 29
  • I noticed this weird behavior, i believe the logic behind is that the scrollViewInsets are automatically ajusted when a scrollview is the first child. Otherwise it does not really make sense because your scrollview is probaby not full screen. – streem Apr 14 '14 at 15:31
1

I also face this problem.

UIScrollView content size is calculate by OS as other sizes, origins provided by constraint system - that's why OS has doubtfulness.

How to fix - You should explicitly define content size of UIScrollView:

  1. Embed scrollable content to UIView (I rename it to ContentView)
  2. Add constraints:

ContentView.Weight = View.Weight and ContentView.Height = View.Height

enter image description here

Bista
  • 7,869
  • 3
  • 27
  • 55
maslovsa
  • 1,589
  • 1
  • 14
  • 15
0

It seems like a work around solution is to view the storyboard file as "iOS 6.1 and earlier" (select storyboard file->File inspector->Interface Builder Document->View As. Positioning subviews in this mode shows the offset.

swhitman
  • 772
  • 6
  • 20
  • Well, i'm not using storyboard. However I'm not sure it's an ios6 to ios7 problem, the example above has been fully created with iOS 7. Moreover, I edited my question, it only appears (as far as i know) with uiscrollview and uitableview. – streem Sep 23 '13 at 21:06
  • Hmm interesting...Looking into this you can add variant="6xAndEarlier" to the top of the XIB in the document element, as this is the difference when flipping the bit I mentioned above. And FYI this issue happens for uiwebview as well for me. – swhitman Sep 24 '13 at 15:19
0

Thank you guys for the solutions! I struggled for hours trying to solve the problem. Everything was ok when there was no Navigation Bar involved but it went haywire the moment I embedded the ViewController in a NavigationController.

I solved it by unchecking the Adjust Scroll View Insets and the Under Top Bars. Both of these are located in the ViewController's Attribute Inspector. Thanks a million!

0

Accepted answer by @streem caused some weird behavior with UILabel acting as sections.

This worked for me:

if let navBar = navigationController?.navigationBar {
    scrollView.contentInset = UIEdgeInsets(top: -navBar.frame.size.height, left: 0.0, bottom: 0.0, right: 0.0)
}
Alterecho
  • 665
  • 10
  • 25