24

I'm developing my app to work with iOS7. I have a UINavigationController I'm pushing a UIViewController that has a ScrollView inside it. Inside the scrollView I have a tableView. Is it possible to achieve that when I scroll the tableView inside the scrollView the list will appear behind that Status bar. Same why it would be if I had a UINavigationController and a UIViewController with a tableView in it.

So this it the hierarchy :

UINavigationController -> UIViewController -> UIScrollView -> UITableView .

and I want that when a user scroll the table,the cells in the top will be visible under the status bar.

If there is no UIScrollView it happens automatically in iOS7.

Thanks.

Cezar
  • 55,636
  • 19
  • 86
  • 87
user958880
  • 487
  • 1
  • 7
  • 18

9 Answers9

38

Just set automaticallyAdjustsScrollViewInsets to NO in the viewController init method.

In Storyboard, you can switch the property directly in the property panel when the UIViewController is selected.

If you use xib, just set it like this:

- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
    self.automaticallyAdjustsScrollViewInsets = NO;
}

Note: this is right since iOS7 and still in iOS8.

Eneko Alonso
  • 18,884
  • 9
  • 62
  • 84
LeChatNoir
  • 1,128
  • 10
  • 9
  • 2
    This is the right solution, as it does not depend on the status bar height, which is not always 20px (depends on the phone being on a call, etc). – Eneko Alonso May 18 '15 at 22:53
  • 1
    Also, you can set this behavior in the storyboard. Select your viewController and uncheck the option "Adjust Scroll View Insets". – Pedro Matos Jun 11 '16 at 18:17
  • thank you dear friend, I have wasted my half day because of this thing. – smoothumut Sep 12 '20 at 07:09
37

none of the above workd for me, until I noticed that I had to set Content Insets from Automatically to Never in the interfacebuilder:

enter image description here

MQLN
  • 2,292
  • 2
  • 18
  • 33
29

Starting with iOS 11 you can use this new property with a fallback (Swift 4):

if #available(iOS 11.0, *) {
    scrollView.contentInsetAdjustmentBehavior = .never
} else {
    self.automaticallyAdjustsScrollViewInsets = false
}
Zorayr
  • 23,770
  • 8
  • 136
  • 129
Skoua
  • 3,373
  • 3
  • 38
  • 51
5

The answer from Skoua might work in some situations, but does have certain side-effects on iOS11 and later. Most notably, the scroll view will start propagating safe areas to its children, which can mess up your layout while scrolling if you use the safe areas or layout margins.

Apple explains this very well and in detail in this WWDC session and also mentions explicitly that contentInsetAdjustmentBehavior = .never can have side-effects and is not what you should use in most cases.


To get a scroll view that does not mess up our layout, but shows its content below the status bar (or navigation bar), you should observe the safe area of your scroll view and adjust your custom content insets accordingly:

private var scrollViewSafeAreaObserver: NSKeyValueObservation!

override func viewDidLoad() {

    ...

    if #available(iOS 11.0, *) {
        self.scrollViewSafeAreaObserver = self.scrollView.observe(\.safeAreaInsets) { [weak self] (_, _) in
            self?.scrollViewSafeAreaInsetsDidChange()
        }
    } else {
        self.automaticallyAdjustsScrollViewInsets = false
    }
}

@available(iOS 11.0, *)
func scrollViewSafeAreaInsetsDidChange() {
    self.scrollView.contentInset.top = -self.scrollView.safeAreaInsets.top
}

deinit {
    self.scrollViewSafeAreaObserver?.invalidate()
    self.scrollViewSafeAreaObserver = nil
}

Why does this work? Because we leave contentInsetAdjustmentBehavior = .automatic. This will give us normal behaviour when it comes to scrolling and non-scrolling axis, but the UIScrollView will also "convert" any safe areas to content insets. Since we don't want this for our top edge, we simply set the negative top safe area as our custom insets, which will counter any insets set by the scroll view.

BlackWolf
  • 5,239
  • 5
  • 33
  • 60
3

Thats just dumb from Apple. One more weird behaviour to worry about. Anyhow, I ended up setting the scroll view content inset for top to -20 (from IB).

codrut
  • 810
  • 10
  • 19
  • I've observed that **-20 to [other object edge]** constraints can often fix these odd UI offset behaviors. – Sitric Jul 22 '15 at 18:17
1

I found the solution! Just set:

self.automaticallyAdjustsScrollViewInsets = false

on the view controller that has the UIScrollView.

Codetard
  • 2,441
  • 28
  • 34
0

You probably has seen this recommendation a thousand times but, check the 'The Status Bar' section on the iOS 7 transition guide(can't post the direct link here).

Blunt resuming, on ios7 the status bar is part of the view. This means that almost anything you put on your view, will be under the bar, unless you say the contrary. A work around i found for that problem was making the status bar opaque.

Another way could be disabling the status bar on that specific view. Like on this thread.

Community
  • 1
  • 1
xicocaio
  • 867
  • 1
  • 10
  • 27
0

I have had a similar sort of problem, and I found that to ensure my scrollview content doesn't go under the status bar, I applied a setContentInset.

So in your situation, if you are using an inset, I would use suggest using UIScrollViewDelegate or scrollViewDidScroll tailored to your tableview. If a scroll is occurring, disregard the scrollview inset.

kjbradley
  • 335
  • 2
  • 4
  • 20
0

don't hide the statusBar, the scrollView won't jump

side
  • 31
  • 4