Search code examples
swiftuiscrollviewuikit

Can't scroll UIScrollView after adding several images


I have trouble with a UIScrollView in UIKit. This is my code. I want my screen to be able to scroll to see all elements.

I can't scroll in my app. What's happening? I want it to scroll vertically. How can I use UIScrollView in this situation? Can I use another way to scroll my view?

class ViewController: UIViewController {
    private var image: UIImageView = {
        let image = UIImageView()
        image.translatesAutoresizingMaskIntoConstraints = false
        return image
    }()
    private var image1: UIImageView = {
        let image = UIImageView()
        image.translatesAutoresizingMaskIntoConstraints = false
        return image
    }()
    private var image2: UIImageView = {
        let image = UIImageView()
        image.translatesAutoresizingMaskIntoConstraints = false
        return image
    }()
    private var image3: UIImageView = {
        let image = UIImageView()
        image.translatesAutoresizingMaskIntoConstraints = false
        return image
    }()
    private var image4: UIImageView = {
        let image = UIImageView()
        image.translatesAutoresizingMaskIntoConstraints = false
        return image
    }()      
    private var scroll: UIScrollView = {
       let scroll = UIScrollView()
        scroll.translatesAutoresizingMaskIntoConstraints = false
        return scroll
    }()
    
    override func viewDidLoad() {
        super.viewDidLoad()
        
        view.addSubview(scroll)
        
        scroll.addSubview(image)
        scroll.addSubview(image1)
        scroll.addSubview(image2)
        scroll.addSubview(image3)
        scroll.addSubview(image4)
        scroll.addSubview(image5)

        let imagetest = UIImage(named: "test")
        image.image = imagetest
        image1.image = imagetest
        image2.image = imagetest
        image3.image = imagetest
        image4.image = imagetest

        NSLayoutConstraint.activate([
            scroll.leadingAnchor.constraint(equalTo: self.view.leadingAnchor),
            scroll.trailingAnchor.constraint(equalTo: self.view.trailingAnchor),
            scroll.topAnchor.constraint(equalTo: self.view.topAnchor),
            scroll.bottomAnchor.constraint(equalTo: self.view.bottomAnchor),
            
            image.leadingAnchor.constraint(equalTo: scroll.leadingAnchor),
            image.trailingAnchor.constraint(equalTo: scroll.trailingAnchor),
            image.topAnchor.constraint(equalTo: scroll.topAnchor, constant: 20),
            image.heightAnchor.constraint(equalToConstant: 200),
            image.widthAnchor.constraint(equalTo: scroll.widthAnchor),
    
            
            image1.leadingAnchor.constraint(equalTo: scroll.leadingAnchor),
            image1.trailingAnchor.constraint(equalTo: scroll.trailingAnchor),
            image1.topAnchor.constraint(equalTo: image.bottomAnchor, constant: 20),
            image1.heightAnchor.constraint(equalToConstant: 200),
            image1.widthAnchor.constraint(equalTo: scroll.widthAnchor),
            image1.widthAnchor.constraint(equalTo: scroll.widthAnchor),

            
            image2.leadingAnchor.constraint(equalTo: scroll.leadingAnchor),
            image2.trailingAnchor.constraint(equalTo: scroll.trailingAnchor),
            image2.topAnchor.constraint(equalTo: image1.bottomAnchor, constant: 20),
            image2.heightAnchor.constraint(equalToConstant: 200),
            image2.widthAnchor.constraint(equalTo: scroll.widthAnchor),

            
            image3.leadingAnchor.constraint(equalTo: scroll.leadingAnchor),
            image3.trailingAnchor.constraint(equalTo: scroll.trailingAnchor),
            image3.topAnchor.constraint(equalTo: image2.bottomAnchor, constant: 20),
            image3.heightAnchor.constraint(equalToConstant: 200),
            image3.widthAnchor.constraint(equalTo: scroll.widthAnchor),

            
            image4.leadingAnchor.constraint(equalTo: scroll.leadingAnchor),
            image4.trailingAnchor.constraint(equalTo: scroll.trailingAnchor),
            image4.topAnchor.constraint(equalTo: image3.bottomAnchor, constant: 20),
            image4.heightAnchor.constraint(equalToConstant: 200),
            image4.widthAnchor.constraint(equalTo: scroll.widthAnchor),
        ])     
    }
}

Solution

  • UIScrollView has two special layout guides you should use: frameLayoutGuide and contentLayoutGuide. The former is used to size and position the scroll view itself. The latter is used to size and position the content within the scroll view.

    Update your constraints to the following to make it work as desired:

    NSLayoutConstraint.activate([
        // Size and position the scroll view within the view controller
        scroll.frameLayoutGuide.leadingAnchor.constraint(equalTo: self.view.leadingAnchor),
        scroll.frameLayoutGuide.trailingAnchor.constraint(equalTo: self.view.trailingAnchor),
        scroll.frameLayoutGuide.topAnchor.constraint(equalTo: self.view.topAnchor),
        scroll.frameLayoutGuide.bottomAnchor.constraint(equalTo: self.view.bottomAnchor),
    
        // Ensure content view width is the same width as the scrollview
        scroll.contentLayoutGuide.widthAnchor.constraint(equalTo: scroll.frameLayoutGuide.widthAnchor),
    
        // Size and position the image within the content view
        image.leadingAnchor.constraint(equalTo: scroll.contentLayoutGuide.leadingAnchor),
        image.trailingAnchor.constraint(equalTo: scroll.contentLayoutGuide.trailingAnchor),
        image.topAnchor.constraint(equalTo: scroll.contentLayoutGuide.topAnchor, constant: 20),
        image.heightAnchor.constraint(equalToConstant: 200),
    
        image1.leadingAnchor.constraint(equalTo: scroll.contentLayoutGuide.leadingAnchor),
        image1.trailingAnchor.constraint(equalTo: scroll.contentLayoutGuide.trailingAnchor),
        image1.topAnchor.constraint(equalTo: image.bottomAnchor, constant: 20),
        image1.heightAnchor.constraint(equalToConstant: 200),
    
        image2.leadingAnchor.constraint(equalTo: scroll.contentLayoutGuide.leadingAnchor),
        image2.trailingAnchor.constraint(equalTo: scroll.contentLayoutGuide.trailingAnchor),
        image2.topAnchor.constraint(equalTo: image1.bottomAnchor, constant: 20),
        image2.heightAnchor.constraint(equalToConstant: 200),
    
        image3.leadingAnchor.constraint(equalTo: scroll.contentLayoutGuide.leadingAnchor),
        image3.trailingAnchor.constraint(equalTo: scroll.contentLayoutGuide.trailingAnchor),
        image3.topAnchor.constraint(equalTo: image2.bottomAnchor, constant: 20),
        image3.heightAnchor.constraint(equalToConstant: 200),
    
        image4.leadingAnchor.constraint(equalTo: scroll.contentLayoutGuide.leadingAnchor),
        image4.trailingAnchor.constraint(equalTo: scroll.contentLayoutGuide.trailingAnchor),
        image4.topAnchor.constraint(equalTo: image3.bottomAnchor, constant: 20),
        image4.bottomAnchor.constraint(equalTo: scroll.contentLayoutGuide.bottomAnchor, constant: -20),
        image4.heightAnchor.constraint(equalToConstant: 200),
    ])
    

    All of the images set their horizontal position to the leading and trailing anchors of the content guide. This implicitly gives each image its width so there is no need to also set the image width.

    The top of the first image is anchored to the top of the content guide.

    The bottom of the last image is anchored to the bottom of the content guide.

    The width of the content guide is set to the scroll view's width so there is no horizontal scrolling.