Using UIScrollView with Autolayout on Xcode using Swift
Note : This post is based on Using UIScrollView with Auto Layout in iOS published on Atomic Object blog.
TL; DR; The code to support UIScrollView
with autolayout is open-sourced and hosted on Github. The wrapper can be found here and example on how to use it is listed here
Recently I read an article about using UIScrollView
with Autolayout
on iOS platform. I was quite fascinated by it as my experience using both of them together has always been terrible. After reading an article, I thought, why not make this even easier by making a wrapper? I that's how this post came to life.
To facilitate using any UIScrollView
with autolayout, I built a wrapper so that anyone should be able to make it work without worrying about underlying constraints and set up associated with this combination.
Let's call this wrapper a ScrollViewAutolayoutCreator
. We will be supporting following features to it,
- Ability to add any view as a sub-view to it and our
scrollView
should be able to resize vertically to accommodate these added views (I have intentionally left out horizontal scrolling for the sake of simplicity) - Ability to specify padding in vertical direction
- Being able to scroll to all the way vertically in both directions
First, let's begin by writing a wrapper which can allow us to easily add vertical scrolling support for arbitrary number of views with any spacing between them. Let's call this wrapper a ScrollViewAutolayoutCreator
. You can find the full source code for wrapper here.
Initializer of ScrollViewAutolayoutCreator
just takes one parameter namely superView
. This is the view to which we want to add our UIScrollView
subclass as a subview.
Now, let's create an instance of ScrollViewAutolayoutCreator
.
// We are using `self.view` of a current viewController as a superView
let autolayoutScrollView = ScrollViewAutolayoutCreator(superView: self.view)
ScrollViewAutolayoutCreator
has a property namely contentView
to which we will add required subviews.
Let's create some sample views and add them as subviews to autolayoutScrollView.contentView
.
let label = UILabel()
label.translatesAutoresizingMaskIntoConstraints = false
label.numberOfLines = 0
label.text = "hello hi buddy\nadadasd\nadadasdas d sd asd asd \na da d adas d\nasdasd"
label.backgroundColor = .green
let sampleView = UIView()
sampleView.translatesAutoresizingMaskIntoConstraints = false
sampleView.backgroundColor = .red
let bottomLabel = UILabel()
bottomLabel.translatesAutoresizingMaskIntoConstraints = false
bottomLabel.numberOfLines = 0
bottomLabel.text = "hello hi buddy\nadadasd\nadadasdas d sd asd asd \na da d adas d\nasdasd"
bottomLabel.backgroundColor = .yellow
let contentView = autolayoutScrollView.contentView
contentView.addSubview(label)
contentView.addSubview(sampleView)
contentView.addSubview(bottomLabel)
Now let's add missing constraints to our sub-views.
Horizontal constraints:
Adding horizontal constraints is as simple as constraining left and right anchors to respective anchors on super-view. However, as long as we have list of all the sub-views, the wrapper provides a way to automatically add them with padding.
// Attach horizontal Constraints
autolayoutScrollView.addHorizontalConstraints(views: [label, sampleView, bottomLabel], horizontalPadding: 20.0)
Vertical constraints:
This is slightly more complicated as we have a vertically scrolling view, thus we want to make sure all the constraints between views as well as those on top and bottom are correctly set up. Here too wrapper makes it as simple as just passing an array of UIView
s and padding between all the views.
// Attach vertical Constraints
autolayoutScrollView.addVerticalConstraints(views: [label, sampleView, bottomLabel], verticalPadding: 100.0)
Note: It is important to note that usage of two above mentioned methods is completely optional. Provided methods add generic constraints with uniform padding. However, there could be cases when you want to add custom constraints in either directions. In which case you don't have to call them
For example, if you decide to have custom constraints in vertical direction, your code might look like this,
NSLayoutConstraint.activate([
label.topAnchor.constraint(equalTo: contentView.topAnchor, constant: 20.0),
sampleView.topAnchor.constraint(equalTo: label.bottomAnchor, constant: 400.0),
bottomLabel.topAnchor.constraint(equalTo: sampleView.bottomAnchor, constant: 400.0),
bottomLabel.bottomAnchor.constraint(equalTo: contentView.bottomAnchor, constant: -20)
])
Bonus methods:
The wrapper provides two more bonus methods to scroll all the way to the top and bottom
func scrollToTop()
func scrollToBottom()
This is it for this post. Below is the video with demo how this whole setup looks like on the simulator.
This is my very first attempt to re-write this wrapper from Objective-C into Swift. If you see any issues with the implementation or have a suggestion for improvement, I would love to hear from you! Thanks for reading!