Initial points to note
Delete
scrollView.frame = self.view.bounds
It is pointless to give scrollView
a frame
, as you are going to give it a frame later through the use of constraints.
Delete
scrollView.autoresizingMask = .flexibleHeight
You are using constraints, not the autoresizing mask, to give the scroll view its frame and later resizing behavior.
Delete
scrollView.contentSize = CGSize(width: self.view.frame.width, height: contentView.frame.height)
Once the scroll view is under the influence of constraints, you must use constraints, not contentSize
, to give it a content size that determines scroll behavior.
Adding the content view
With those preliminaries out of the way, let's talk about how you add the content view to the scroll view:
scrollView.addSubview(contentView)
contentView.topAnchor.constraint(equalTo: scrollView.topAnchor).isActive = true
contentView.bottomAnchor.constraint(equalTo: scrollView.bottomAnchor).isActive = true
contentView.leadingAnchor.constraint(equalTo: scrollView.leadingAnchor).isActive = true
contentView.trailingAnchor.constraint(equalTo: scrollView.trailingAnchor).isActive = true
That is not exactly wrong, but it is very outmoded. You should pin the content view to the scroll view's content layout guide; that is what it is for. So, wherever you have equalTo: scrollView
, change it to equalTo: scrollView.contentLayoutGuide
.
Scrolling
Okay! Now everything is assembled and we are ready to talk about scrolling. What makes the scroll view scrollable, in this configuration, is that the content view is bigger than the scroll view itself. Well, so far, that's not true; in fact, the content view has no size at all. So we must proceed to give it some size.
Your attempt to do that is rather feeble. Let's extract the key lines where you give the content view height and width constraints:
contentView.widthAnchor.constraint(equalTo: view.widthAnchor).isActive = true
contentView.heightAnchor.constraint(equalTo: view.heightAnchor).isActive = true
(Delete the other two lines, as they are not really doing anything useful now.) So now is the content view any bigger than the scroll view? Well, maybe, but if so, only by a tiny bit, because the content view is merely the size of the main view, and the scroll view is either that same size or a tiny bit smaller.
Since we are just demonstrating, it would be better to make the content view a lot bigger than the scroll view, so we can do some major scrolling. Change the second line to this:
contentView.heightAnchor.constraint(equalTo: view.heightAnchor, multiplier:2 ).isActive = true
Yeah, baby! Now we can really scroll.
Making the content more visible
Still, it's a little hard to see what's happening (everything is white on white), so I suggest you fill the content view with some color that will permit us to see what's going on. Declare a self-drawing view as follows:
class MyView : UIView {
override class var layerClass : AnyClass { CAGradientLayer.self }
override func willMove(toSuperview newSuperview: UIView?) {
let lay = self.layer as! CAGradientLayer
lay.colors = [UIColor.red.cgColor, UIColor.green.cgColor]
}
}
Now change
let view = UIView()
to
let view = MyView()
Now it is very obvious when you scroll to the bottom; the real green is visible at the bottom.
Summary
Here is the complete code of the corrected example:
class MyView : UIView {
override class var layerClass : AnyClass { CAGradientLayer.self }
override func willMove(toSuperview newSuperview: UIView?) {
let lay = self.layer as! CAGradientLayer
lay.colors = [UIColor.red.cgColor, UIColor.green.cgColor]
}
}
class ViewController: UIViewController {
lazy var contentView : UIView = {
let view = MyView()
view.translatesAutoresizingMaskIntoConstraints = false
return view
}()
lazy var scrollView : UIScrollView = {
let scrollView = UIScrollView(frame: .zero)
scrollView.backgroundColor = .white
scrollView.bounces = true
scrollView.translatesAutoresizingMaskIntoConstraints = false
return scrollView
}()
override func viewDidLoad() {
super.viewDidLoad()
view.addSubview(scrollView)
scrollView.topAnchor.constraint(equalTo: view.safeAreaLayoutGuide.topAnchor).isActive = true
scrollView.leadingAnchor.constraint(equalTo: view.safeAreaLayoutGuide.leadingAnchor).isActive = true
scrollView.trailingAnchor.constraint(equalTo: view.safeAreaLayoutGuide.trailingAnchor).isActive = true
scrollView.bottomAnchor.constraint(equalTo: view.safeAreaLayoutGuide.bottomAnchor).isActive = true
scrollView.addSubview(contentView)
contentView.topAnchor.constraint(equalTo: scrollView.contentLayoutGuide.topAnchor).isActive = true
contentView.bottomAnchor.constraint(equalTo: scrollView.contentLayoutGuide.bottomAnchor).isActive = true
contentView.leadingAnchor.constraint(equalTo: scrollView.contentLayoutGuide.leadingAnchor).isActive = true
contentView.trailingAnchor.constraint(equalTo: scrollView.contentLayoutGuide.trailingAnchor).isActive = true
contentView.widthAnchor.constraint(equalTo: view.widthAnchor).isActive = true
contentView.heightAnchor.constraint(equalTo: view.heightAnchor, multiplier:2 ).isActive = true
}
}