instanceof
instanceof

Reputation: 1466

Add Views to UIScrollView Programmatically

I have added the following code to my UIViewController:

override func viewDidLoad() {
    super.viewDidLoad()

    viewBrochures.isUserInteractionEnabled = true
    let brochure1: UIImageView = UIImageView(image: UIImage(named: "image1")!)
    brochure1.translatesAutoresizingMaskIntoConstraints = false
    brochure1.contentMode = .scaleAspectFit
    brochure1.frame = CGRect(x: 0, y: 0, width: UIScreen.main.bounds.width, height: 400)
    viewBrochures.addSubview(brochure1)
    let brochure2: UIImageView = UIImageView(image: UIImage(named: "image2")!)
    brochure2.translatesAutoresizingMaskIntoConstraints = false
    brochure2.contentMode = .scaleAspectFit
    brochure2.frame = CGRect(x: 0, y: 0, width: UIScreen.main.bounds.width, height: 400)
    viewBrochures.addSubview(brochure2)
    let brochure3: UIImageView = UIImageView(image: UIImage(named: "image3")!)
    brochure3.translatesAutoresizingMaskIntoConstraints = false
    brochure3.contentMode = .scaleAspectFit
    brochure3.frame = CGRect(x: 0, y: 0, width: UIScreen.main.bounds.width, height: 400)
    viewBrochures.addSubview(brochure3)
    let brochure4: UIImageView = UIImageView(image: UIImage(named: "image4")!)
    brochure4.translatesAutoresizingMaskIntoConstraints = false
    brochure4.contentMode = .scaleAspectFit
    brochure4.frame = CGRect(x: 0, y: 0, width: UIScreen.main.bounds.width, height: 400)
    viewBrochures.addSubview(brochure4)


    viewBrochures.addConstraint(NSLayoutConstraint(item: brochure1,
                                                attribute: .trailing,
                                                    relatedBy: .equal,
                                                    toItem: viewBrochures,
                                                    attribute: .trailingMargin,
                                                    multiplier: 1,
                                                    constant: 0))
    viewBrochures.addConstraint(NSLayoutConstraint(item: brochure1,
                                                  attribute: .leading,
                                                  relatedBy: .equal,
                                                  toItem: viewBrochures,
                                                  attribute: .leadingMargin,
                                                  multiplier: 1,
                                                  constant: 0))
    viewBrochures.addConstraint(NSLayoutConstraint(item: brochure1,
                                                  attribute: .top,
                                                  relatedBy: .equal,
                                                  toItem: viewBottomButtons,
                                                  attribute: .bottom,
                                                  multiplier: 1,
                                                  constant: 10))
    viewBrochures.addConstraint(NSLayoutConstraint(item: brochure1,
                                                  attribute: .bottom,
                                                  relatedBy: .equal,
                                                  toItem: brochure2,
                                                  attribute: .top,
                                                  multiplier: 1,
                                                  constant: 10))


    viewBrochures.addConstraint(NSLayoutConstraint(item: brochure2,
                                                  attribute: .trailing,
                                                  relatedBy: .equal,
                                                  toItem: viewBrochures,
                                                  attribute: .trailingMargin,
                                                  multiplier: 1,
                                                  constant: 0))
    viewBrochures.addConstraint(NSLayoutConstraint(item: brochure2,
                                                  attribute: .leading,
                                                  relatedBy: .equal,
                                                  toItem: viewBrochures,
                                                  attribute: .leadingMargin,
                                                  multiplier: 1,
                                                  constant: 0))
    viewBrochures.addConstraint(NSLayoutConstraint(item: brochure2,
                                                  attribute: .top,
                                                  relatedBy: .equal,
                                                  toItem: brochure1,
                                                  attribute: .bottom,
                                                  multiplier: 1,
                                                  constant: 10))
    viewBrochures.addConstraint(NSLayoutConstraint(item: brochure2,
                                                  attribute: .bottom,
                                                  relatedBy: .equal,
                                                  toItem: brochure3,
                                                  attribute: .top,
                                                  multiplier: 1,
                                                  constant: 10))


    viewBrochures.addConstraint(NSLayoutConstraint(item: brochure3,
                                                  attribute: .trailing,
                                                  relatedBy: .equal,
                                                  toItem: viewBrochures,
                                                  attribute: .trailingMargin,
                                                  multiplier: 1,
                                                  constant: 0))
    viewBrochures.addConstraint(NSLayoutConstraint(item: brochure3,
                                                  attribute: .leading,
                                                  relatedBy: .equal,
                                                  toItem: viewBrochures,
                                                  attribute: .leadingMargin,
                                                  multiplier: 1,
                                                  constant: 0))
    viewBrochures.addConstraint(NSLayoutConstraint(item: brochure3,
                                                  attribute: .top,
                                                  relatedBy: .equal,
                                                  toItem: brochure2,
                                                  attribute: .bottom,
                                                  multiplier: 1,
                                                  constant: 10))
    viewBrochures.addConstraint(NSLayoutConstraint(item: brochure3,
                                                  attribute: .bottom,
                                                  relatedBy: .equal,
                                                  toItem: brochure4,
                                                  attribute: .top,
                                                  multiplier: 1,
                                                  constant: 10))


    viewBrochures.addConstraint(NSLayoutConstraint(item: brochure4,
                                                  attribute: .trailing,
                                                  relatedBy: .equal,
                                                  toItem: viewBrochures,
                                                  attribute: .trailingMargin,
                                                  multiplier: 1,
                                                  constant: 0))
    viewBrochures.addConstraint(NSLayoutConstraint(item: brochure4,
                                                  attribute: .leading,
                                                  relatedBy: .equal,
                                                  toItem: viewBrochures,
                                                  attribute: .leadingMargin,
                                                  multiplier: 1,
                                                  constant: 0))
    viewBrochures.addConstraint(NSLayoutConstraint(item: brochure4,
                                                  attribute: .top,
                                                  relatedBy: .equal,
                                                  toItem: brochure3,
                                                  attribute: .bottom,
                                                  multiplier: 1,
                                                  constant: 10))
    viewBrochures.addConstraint(NSLayoutConstraint(item: brochure4,
                                                  attribute: .bottomMargin,
                                                  relatedBy: .greaterThanOrEqual,
                                                  toItem: viewBrochures,
                                                  attribute: .bottom,
                                                  multiplier: 1,
                                                  constant: 10))

}

And also:

override func viewDidLayoutSubviews() {
    scrlMain.contentSize = viewBrochures.bounds.size
}

Note that I have setup my UIScrollView and my container view (viewBrochures) in the storyboard already, I just need to add images to the container, and then be able to scroll them vertically, because they don't fit into the screen. In the scrollview's container view, I already have 2 other views that need to be above these new images (images need to be below the 2 views, and all of them together (2 views + images) need to scroll together in the scrollview). These other 2 views have already been added in the storyboard without issues. As you can see I've created the images and added constraints to them programmatically. I've added 4 constraints for each image, one for leading, one for trailing, one for top, and one for bottom. The top most image I have constrained to the bottom of the view directly above, and the bottom most image I have constrained to the bottom of the container view using a greaterThanOrEqual constraint. I have also seen somewhere on SO that adding "translatesAutoresizingMaskIntoConstraints = false" to an image is needed when adding images to a scrollview in code, but I'm not sure exactly what it does and if it is needed.

So this code works for adding the images, but the problem is the scrollview won't scroll, at all. I am not sure if this is the correct way of doing this, so feel free to suggest me any other options. As you can see I used autolayout and layout constraints. If you can see if there is anything wrong with my implementation of it, any advise and/or correction would be appreciated.

Upvotes: 2

Views: 4917

Answers (1)

joern
joern

Reputation: 27620

There are two main issues with your approach:

  1. When working with AutoLayout you should not set any frames manually. AutoLayout does that for you and does not like it when you interfere.
  2. When working with UIScrollViews and AutoLayout you should not set the UIScrollView's contentSize. As long as your constraints are set correctly the UIScrollView will automatically adjust its contentSize and scroll its content.

Also you do not really need the viewBrochures container view (unless it does anything except being a container for the images). You can simply add your 2 above views and all the images as direct subviews of your UIScrollView.

To make your scroll view work you have to do the following:

  1. The topmost subview must have a top constraint with the UIScrollView
  2. All other subviews must have a top constraint with the bottom constraint of the subview above them
  3. The bottommost subview must have a bottom constraint with the UIScrollView

You also have to take care that the subviews do not become wider that your scrollview (or the scrollview will suddenly also scroll horizontally). To do that you have to set a width constraint on one of the subviews that is equal to the scrollview's width.

If you still have difficulties making it work have a look at this blogpost I wrote some time ago where I describe a similar scenario than yours.

I also created this gist with a working example.

Upvotes: 5

Related Questions