Calculating contentSize for UIScrollView when using Auto Layout

30,280

Solution 1

Giving content size programatically is not good way. The below solution which will work using autolayout, dont need to set content size at all. It will calculate as per how many UI fields added to view.

Step 1 :

Add Scrollview to view in storyboard and add leading, trailing, top and bottom constraints (All values are zero).

Step 2 :

Don't add directly views which you need on directly scrollview, First add one view to scrollview (that will be our content view for all UI elements). Add below constraints to this view.

1) Leading, trailing, top and bottom constraints (All values are zero).

2) Add equal height, equal width to Main view (i.e. which contains scrollview). For equal height set priority to low. (This is the important step for setting content size).

3) Height of this content view will be according to the number of views added to the view. let say if you added last view is one label and his Y position is 420 and height is 20 then your content view will be 440.

Step 3 : Add constraints to all of views which you added within content view as per your requirement.

For reference :

enter image description here

enter image description here

I hope this will definitely help you.

Solution 2

Though I finally got to solve this issue and make things work. I noticed that all I could find on the net as related answers was directed to storyboard users. But nothing to do it programmatically that I could put my hands on.

So I decided to make an extremely simple demo app to show how this can be achieved. I hope it will be useful to someone at some point.

Here is the address to get it on GitHub: https://github.com/zaxonus/AutoLayScroll

Solution 3

I also used constraints programmatically to dynamically modify UIScrollView's contentSize . I pretty much followed Shrikant's instructions but for step 2.1, I set centerX to the scrollViews.centerX rather than set the leading and trailing margins (No idea why the former works, while the latter doesn't). Then as a last step, after adding the final subview, I did the following:

contentView.layoutIfNeeded() //set a frame based on constraints
scrollView.contentSize = CGSize(width: contentView.frame.width, height: contentView.frame.height)

Hope this helps somebody in the future.

Solution 4

All you need to do is to make sure that the first subview's top anchor is constrained to the scrollView's top anchor and the last subview's bottom anchor is constrained to the scrollView's bottom anchor

Solution 5

If you don't want to use storyboards, and just use constraints, you can follow the guide here

https://redflowerinc.com/implement-uiscrollview-using-constraints-no-need-to-use-content-size/

Use can use bottom anchor and pin your views to the scroll view. By using constraints you don't need to use content size.

Share:
30,280
Michel
Author by

Michel

I am currently developing iOS software, mainly using Swift. With a total of about 20 apps on the appStore, the main ones being related to language learning. For some examples see: http://www.sofisfun.net/Language/ and http://www.sofisfun.net/Calculators/ I recently got to work on Heroku to port some projects from the Parse.com site to open source Parse-Server, that got me on the way to get my hands on Node.JS where I built this little prime number site to get familiar with the environment. And I more recently got interested in Clojure, where I built this as a trial project.

Updated on August 06, 2021

Comments

  • Michel
    Michel over 2 years

    Here is a quick question about something which works, but could be written much better. I have a UIScrollView and a list of objects laid out inside, one under the other. Everything is done during viewDidLoad() and the placement of the objects uses Auto Layout. Here is what I do to set the contentSize height of the UIScrollView to its appropriate value.

    override func viewDidAppear(animated: Bool) {
        super.viewDidAppear(animated)
        globalView.contentSize = CGSize(width: globalView.frame.width,
                                        height: globalView.frame.height * 1.59)
    }
    

    It works, but the arbitrary value 1.59 has obviously been decided by me trying a few possible values. What is the proper way to compute the contentSize in such a case? I am doing everything programmatically. Searching the net didn't lead me to any simple and clear answer, so eventhough it may be a somewhat duplicate question I decided to reformulate it.