1

I'm trying to use a UIScrollView on my view as the content that I want to show won't fit on the screen. I work purely programmatically and cannot seem to grasp why my UIScrollView simply will not work when adding constraints. It works perfectly with frames but I that's the awkward, old way of doing things. I want to be able to add views to the scroll view and of course scroll down as it goes off screen. I have tried to add a topView as one of the views I want to be able to add and scroll with the scrollview but no joy. Where am I going wrong? Any help will be highly appreciated.

class ScrollTest: UIViewController {

    override func viewDidLoad() {
        super.viewDidLoad()

        view.backgroundColor = .white

        setupviews()
    }

    let topView: UIView = {
        let view = UIView()
        view.backgroundColor = .yellow
        return view
    }()

    let containerView: UIView = {
        let view = UIView()
        view.backgroundColor = .white
        return view
    }()

    let scrollView: UIScrollView = {
        let sv = UIScrollView()
        sv.backgroundColor = .white
        sv.translatesAutoresizingMaskIntoConstraints = false
        return sv
    }()

    func setupviews() {
        view.addSubview(scrollView)
        scrollView.addSubview(containerView)

        containerView.addSubview(topView)

        scrollView.leftAnchor.constraint(equalTo: view.leftAnchor).isActive = true
        scrollView.rightAnchor.constraint(equalTo: view.rightAnchor).isActive = true
        scrollView.topAnchor.constraint(equalTo: view.topAnchor).isActive = true
        scrollView.bottomAnchor.constraint(equalTo: view.bottomAnchor).isActive = true
//
        _ = containerView.anchor(scrollView.topAnchor, left: scrollView.leftAnchor, bottom: scrollView.bottomAnchor, right: scrollView.rightAnchor, topConstant: 0, leftConstant: 0, bottomConstant: 0, rightConstant: 0, widthConstant: 0, heightConstant: 700)

        _ = topView.anchor(view.topAnchor, left: view.leftAnchor, bottom: nil, right: view.rightAnchor, topConstant: 100, leftConstant: 0, bottomConstant: 0, rightConstant: 0, widthConstant: 0, heightConstant: 50)
    }
}
Daniel Dramond
  • 1,538
  • 2
  • 15
  • 26
  • My answer here has a complete example that you can run in a Playground page: https://stackoverflow.com/questions/44931898/using-scrollview-programmatically-in-swift-3/44933358#44933358 – DonMag Jul 06 '17 at 20:33

1 Answers1

4

Couple of things. First, your containerView is missing translatesAutoresizingMaskIntoConstraints = false. Second, mostly, an UI objects needs four constraints to be valid. So you are missing some of them for your container view.

Here is a complete working code

let scrollView: UIScrollView = {
    let sv = UIScrollView()
    sv.backgroundColor = .red
    sv.translatesAutoresizingMaskIntoConstraints = false
    return sv
}()

let containerView: UIView = {
    let view = UIView()
    view.backgroundColor = .white
    view.translatesAutoresizingMaskIntoConstraints = false
    return view
}()

override func viewDidLoad() {
    super.viewDidLoad()

    view.addSubview(scrollView)

    scrollView.contentSize = CGSize(width: 320, height: 1500)

    scrollView.leftAnchor.constraint(equalTo: view.leftAnchor).isActive = true
    scrollView.rightAnchor.constraint(equalTo: view.rightAnchor).isActive = true
    scrollView.topAnchor.constraint(equalTo: view.topAnchor).isActive = true
    scrollView.bottomAnchor.constraint(equalTo: view.bottomAnchor).isActive = true

    scrollView.addSubview(containerView)

    containerView.leftAnchor.constraint(equalTo: scrollView.leftAnchor).isActive = true
    containerView.topAnchor.constraint(equalTo: scrollView.topAnchor).isActive = true
    containerView.widthAnchor.constraint(equalToConstant: 200).isActive = true
    containerView.heightAnchor.constraint(equalToConstant: 100).isActive = true

}

Results is like

enter image description here

Fangming
  • 24,551
  • 6
  • 100
  • 90
  • Cheers. Could you please explain the 320 width value for the scrollView content? Why not view.frame.width? – Daniel Dramond Jul 06 '17 at 20:19
  • Also, when I want to have a top, left, right and height constraint, it doesn't work. It only allows me to have a top, left, height and width – Daniel Dramond Jul 06 '17 at 20:28
  • @ChelsMcKay Please use self.frame. I am just being convenient. For your second question, you mean for your container view? – Fangming Jul 06 '17 at 21:28
  • I figured that I was only allowed to anchor to the top and bottom of a scroll view. If i wanted something to anchor top, bottom, left and right, I'd have to anchor it to the top and bottom of the scroll view BUT anchor the left and right to the view – Daniel Dramond Jul 07 '17 at 11:00
  • Is it possible to NOT hardcode `height: 1500` and use `scrollView.frame.height * 5` for example? I think it won't work. – Van Du Tran Nov 14 '17 at 21:03
  • @VanDuTran I can't see why you can not do that. I am just giving a height that is longer than the height of the frame so that the view is scrollable – Fangming Nov 14 '17 at 22:05
  • @FangmingNing I tried it and it doesn't work, because scrollView.frame.height is zero at the time of initialization (since when anchors are used, heights and width are set at a later time, not when you declare them). – Van Du Tran Nov 16 '17 at 16:08
  • @VanDuTran ok sure..... I think the correct way to do it is to calculate the content height, say, adds up views and then set the height – Fangming Nov 16 '17 at 16:14
  • @FangmingNing I thought sometimes a better way was to use top and bottom anchors to set height since we have different screen sizes. But that doesn't work. However, we're now off topic :) – Van Du Tran Nov 16 '17 at 16:59