20

My UIViewController is embedded in a navigation controller. I programmatically add the navigation buttons and now trying to add a scrollView below this navigation bar. The problem I'm having is this is filling the full frame size and going under the navigation bar.

How do I programmatically set constraints of this scrollview?

var scrollView: UIScrollView!
var containerView = UIView()

override func viewDidLoad() {
    super.viewDidLoad()
    self.navigationItem.title = "Filters"
    // add some buttons on the navigation

    self.scrollView = UIScrollView()
    self.scrollView.backgroundColor = UIColor.grayColor()
    self.scrollView.contentSize = CGSizeMake(self.view.frame.size.width, self.view.frame.size.height)

    containerView = UIView()

    scrollView.addSubview(containerView)
    view.addSubview(scrollView)

    let label = UILabel(frame: CGRectMake(0, 0, 100, 21))
    label.text = "my label"
    containerView.addSubview(label)
}
Cœur
  • 37,241
  • 25
  • 195
  • 267

7 Answers7

60

While Clafou's answer is certainly correct, if you don't need transparency and want to start under navigation bar, the really proper way is to change behavior of the ViewController so it fits the content properly. To do that, you have two options:

1) Assuming you have Storyboard, go to ViewController Attributes Inspector and disable "Under top bars"

enter image description here

2) Assuming you are everything through code, you will want to look for following properties - edgesForExtendedLayout, and extendedLayoutIncludesOpaqueBars. There is great answer for that already on SO so I won't cover it here.

Hope it helps!

Community
  • 1
  • 1
Jiri Trecak
  • 5,092
  • 26
  • 37
  • 1
    Exactly what i needed and managed to find out how to do this programatically too. Thanks –  Jul 15 '15 at 12:00
  • Can't believe that's all it took... I had a weird problem where I had a scrollview getting stuck under the top bar, but then popping out from under it after showing and dismissing the keyboard. There was probably a deeper problem, but this fix did the trick, at least. – Terry Torres Jan 03 '19 at 16:41
25

The only way I managed to get this working on iOS11 was like this

if (@available(iOS 11.0, *)) {
    scrollView.contentInsetAdjustmentBehavior = UIScrollViewContentInsetAdjustmentNever;
} else {
    // Fallback on earlier versions
}
Zayin Krige
  • 3,229
  • 1
  • 35
  • 34
8

In Swift 5

let scrollView = UIScrollView()
scrollView.translatesAutoresizingMaskIntoConstraints = false
scrollView.addSubview(imageView)
scrollView.contentInsetAdjustmentBehavior = .never

NSLayoutConstraint.activate([
    scrollView.topAnchor.constraint(equalTo: view.safeAreaLayoutGuide.topAnchor)
])
damo
  • 849
  • 12
  • 16
4

While using auto-layout, just make sure that you give the top-constraint of UIScrollView with Top Layout Guide, not with superview of scroll view.

Ravi Sisodia
  • 776
  • 1
  • 5
  • 20
  • Thanks! Can you please explain the difference? Or where can I see visual documentation on this matter? – Andres Jun 14 '17 at 21:16
0

In Objective-C I usually set the 'edgesForExtendedLayout' Property to UIRectEdgeNone:

if ([self respondsToSelector:@selector(edgesForExtendedLayout)])
    self.edgesForExtendedLayout = UIRectEdgeNone;

Nevertheless I would recommend to bind the Constraints to the topLayoutGuide

func addScrollViewConstraints() {
    var scrollViewContraints = [NSLayoutConstraint]()
    scrollViewContraints.append(NSLayoutConstraint(item: scrollView,
        attribute: NSLayoutAttribute.Top,
        relatedBy: NSLayoutRelation.Equal,
        toItem: self.topLayoutGuide,
        attribute:NSLayoutAttribute.Bottom,
        multiplier: 1.0,
        constant: 0.0))
    scrollViewContraints.append(NSLayoutConstraint(item: scrollView,
        attribute: NSLayoutAttribute.Bottom,
        relatedBy: NSLayoutRelation.Equal,
        toItem: self.bottomLayoutGuide,
        attribute:NSLayoutAttribute.Top,
        multiplier: 1.0,
        constant: 0.0))
    scrollViewContraints.append(NSLayoutConstraint(item: scrollView,
        attribute: NSLayoutAttribute.Leading,
        relatedBy: NSLayoutRelation.Equal,
        toItem: self.view,
        attribute:NSLayoutAttribute.Leading,
        multiplier: 1.0,
        constant: 0.0))
    scrollViewContraints.append(NSLayoutConstraint(item: scrollView,
        attribute: NSLayoutAttribute.Trailing,
        relatedBy: NSLayoutRelation.Equal,
        toItem: self.view,
        attribute:NSLayoutAttribute.Trailing,
        multiplier: 1.0,
        constant: 0.0))
    self.view.addConstraints(scrollViewContraints)
}

Hope this works for you.

cr0ss
  • 533
  • 4
  • 18
0

for placing any view under the navigation bar use this code:

yourView.topAnchor.constraint(equalTo: topLayoutGuide.bottomAnchor).isActive = true
jamal zare
  • 1,037
  • 12
  • 13
0

Another solution from https://stackoverflow.com/a/75143442/851258

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