TransWikia.com

Adding UIView to UIScrollView does not change content size?

Stack Overflow Asked on December 5, 2021

I’m adding a very large UIView to a UIScrollView, however the scroll view does not scroll to show the whole subview.

When I add a label to the UIScrollView, it does scroll to show that label.

On the actual project I’m working on, I added many views within the scrollView and it is not scrolling at all. This is a simplified example to show my problem:

import UIKit

class ViewController: UIViewController {
    
    let scrollView: UIScrollView = {
        let scroll = UIScrollView()
        scroll.backgroundColor = .blue
        scroll.translatesAutoresizingMaskIntoConstraints = false
        return scroll
    }()
    
    let viewDoesntWork: UIView = {
        let view = UIView()
        view.backgroundColor = .purple
        view.translatesAutoresizingMaskIntoConstraints = false
        return view
    }()
    
    let labelWorks: UILabel = {
         let label = UILabel()
         label.text = "Why this work?"
         label.backgroundColor = .green
         label.translatesAutoresizingMaskIntoConstraints = false
         return label
     }()
    
    
    override func viewDidLoad() {
        super.viewDidLoad()
        view.backgroundColor = .red
        
        // Add scrollView to view, 20 from edges of view on all sides
        view.addSubview(scrollView)
        scrollView.leftAnchor.constraint(equalTo: view.leftAnchor, constant: 20).isActive = true
        scrollView.topAnchor.constraint(equalTo: view.topAnchor, constant: 20).isActive = true
        scrollView.rightAnchor.constraint(equalTo: view.rightAnchor, constant: -20).isActive = true
        scrollView.bottomAnchor.constraint(equalTo: view.bottomAnchor, constant: -20).isActive = true
        
        
        // OPTION 1 (does not work):
        // Add viewDoesntWork to view, make it much bigger than the scrollView fits
        scrollView.addSubview(viewDoesntWork)
        viewDoesntWork.topAnchor.constraint(equalTo: scrollView.topAnchor, constant: 20).isActive = true
        viewDoesntWork.leftAnchor.constraint(equalTo: scrollView.leftAnchor, constant: 20).isActive = true
        viewDoesntWork.widthAnchor.constraint(equalToConstant: 1000).isActive = true
        viewDoesntWork.heightAnchor.constraint(equalToConstant: 1000).isActive = true
        
        
        // OPTION 2 (works):
        // Add labelWorks to scrollView, and it does scroll to it. 
        // Uncomment this to see that work.
        // scrollView.addSubview(labelWorks)
        // labelWorks.topAnchor.constraint(equalTo: scrollView.topAnchor, constant: 1000).isActive = true
        // labelWorks.leftAnchor.constraint(equalTo: scrollView.leftAnchor, constant: 1000).isActive = true
        // labelWorks.rightAnchor.constraint(equalTo: scrollView.rightAnchor, constant: -20).isActive = true
        // labelWorks.bottomAnchor.constraint(equalTo: scrollView.bottomAnchor, constant: -20).isActive = true

    }
}

As is, this does not scroll. But, if you comment out the specified section, it does.

Why is this? How can it make it such that adding subViews to the scrollView makes it scroll?

Thanks!

2 Answers

The answer of matt causes a [LayoutConstraints] problem in the console here is my simplified Answer

/* 
 I  shortened and  simplified your code, I also added some 
 explanations such that you could understand that's why the code will 
 seem long
*/
// let's call the viewDoesntWork view1

// first of all you didn't give a frame to the view1
/* 
secondly you didn't set the content size(the content size is the 
size of the scrollable area) of the scrollView!!
if the scrollView doesn't have a contentSize , it won't scroll
 */


/* 
 you don't need to set translatesAutoresizingMaskIntoConstraints = 
false for labelWorks

 Adding UIView to UIScrollView does not change the content size, you 
 have to set it manually
*/
import UIKit


class ViewController: UIViewController {

   let scrollView: UIScrollView = {
   let scroll = UIScrollView()
   scroll.backgroundColor = .blue
   scroll.translatesAutoresizingMaskIntoConstraints = false
   return scroll
       }()
   
       let viewDoesntWork: UIView = {
       let view = UIView()
       view.backgroundColor = .purple
       view.translatesAutoresizingMaskIntoConstraints = false
       return view
   }()
   
       let labelWorks: UILabel = {
        let label = UILabel()
        label.text = "Why this work?"
        label.backgroundColor = .green
        return label
        }()
   
      
   //In this function we set up the frame and other stuffs of the 
   //subviews
    
       override func viewDidLayoutSubviews() {
           super.viewDidLayoutSubviews()

           // let's give it a content size
          scrollView.contentSize  = CGSize(width:view.frame.size.width , height: 1000)
     
        viewDoesntWork.frame = CGRect(x: 20, y: 20, 
          width:view.frame.size.width , height: 800)
   /*
    viewDoesntWork.topAnchor.constraint(equalTo: 
    scrollView.topAnchor, constant: 20).isActive = true isn't 
    necessary anymore 
    since we set the y = 20 , the same goes for letfAnchor and x = 20
   */
        /*
        In my opinion , you don't need to set constraints for the size 
        of the viewDoesntWork
        */
    
        labelWorks.frame = CGRect(x:view.center.x , y: 
        viewDoesntWork.frame.size.height + 20 + 40 , width:120, 
          height: 20)
        // I added your label below the viewDoesntWork
        /* 
   you don't need to set constraints, these are just some 
   calculations since you know the content size
     */
       }

       override func viewDidLoad() {
       super.viewDidLoad()
       view.backgroundColor = .red
       
       // Add scrollView to view, 20 from edges of view on all sides
       view.addSubview(scrollView)
       scrollView.addSubview(viewDoesntWork)
        scrollView.addSubview(labelWorks)
    scrollView.leftAnchor.constraint(equalTo: view.leftAnchor, constant: 
 20).isActive = true
    scrollView.topAnchor.constraint(equalTo: view.topAnchor, constant: 
20).isActive = true
     scrollView.rightAnchor.constraint(equalTo: view.rightAnchor, constant: 
-20).isActive = true
    scrollView.bottomAnchor.constraint(equalTo: view.bottomAnchor, constant: 
-20).isActive = true
       
       }
   }

Answered by Soren Nguia on December 5, 2021

The two things are not at all parallel. You have an example of what works, but in your other example you are not doing that, and that is why it doesn't work. Change:

viewDoesntWork.topAnchor.constraint(equalTo: scrollView.topAnchor, constant: 20).isActive = true
viewDoesntWork.leftAnchor.constraint(equalTo: scrollView.leftAnchor, constant: 20).isActive = true
viewDoesntWork.widthAnchor.constraint(equalToConstant: 1000).isActive = true
viewDoesntWork.heightAnchor.constraint(equalToConstant: 1000).isActive = true

To:

viewDoesntWork.topAnchor.constraint(equalTo: scrollView.topAnchor, constant: 0).isActive = true
viewDoesntWork.leftAnchor.constraint(equalTo: scrollView.leftAnchor, constant: 0).isActive = true
viewDoesntWork.widthAnchor.constraint(equalToConstant: 1000).isActive = true
viewDoesntWork.heightAnchor.constraint(equalToConstant: 1000).isActive = true
viewDoesntWork.bottomAnchor.constraint(equalTo: scrollView.bottomAnchor, constant: 0).isActive = true
viewDoesntWork.rightAnchor.constraint(equalTo: scrollView.rightAnchor, constant: 0).isActive = true

Answered by matt on December 5, 2021

Add your own answers!

Ask a Question

Get help from others!

© 2024 TransWikia.com. All rights reserved. Sites we Love: PCI Database, UKBizDB, Menu Kuliner, Sharing RPP