Search code examples
swiftxcodeuiscrollviewuistackview

UIScrollView with vertical stackview scrolls horizontally but not vertically


I followed the exact code of a similar question's answer and while it scrolled vertically for them it does not for me. The label in the code is just a test there are far more in the actual program but they are added from firebase later on so I'm not sure if that changes anything. While it's not super important I would prefer to figure this out programmatically as I am more capable in that area. I'm not great at asking questions or providing the right code so the whole project is here

`

@IBOutlet weak var history: UIStackView!
@IBOutlet weak var scrollView: UIScrollView!

var ref: DatabaseReference!


override func viewDidLoad() {
    super.viewDidLoad()
    view.addSubview(scrollView)

    ref = Database.database().reference()
    
    let label = UILabel(frame: CGRect.init())
    label.text = "Label"
    history.addArrangedSubview(label)
    
    scrollView.contentSize = CGSize(width: view.bounds.width, height: view.bounds.height)

    history.leadingAnchor.constraint(equalTo: scrollView.leadingAnchor).isActive = true
    history.trailingAnchor.constraint(equalTo: scrollView.trailingAnchor).isActive = true
    history.bottomAnchor.constraint(equalTo: scrollView.bottomAnchor).isActive = true
    history.topAnchor.constraint(equalTo: scrollView.topAnchor).isActive = true
    history.widthAnchor.constraint(equalTo: scrollView.widthAnchor).isActive = true
    //history.heightAnchor.constraint(lessThanOrEqualTo: scrollView.heightAnchor).isActive = true

    scrollView.addSubview(history)
    view.addSubview(scrollView)
    `

Solution

  • You're doing a bunch of things wrong...

    Your code shows @IBOutlet for both the history stack view and the scrollView, which implies you've added them in Storyboard? If so, you should not be doing:

    scrollView.addSubview(history)
    view.addSubview(scrollView)
    

    because they already exist when added in Storyboard. Also, one would expect you to have added the constraints in Storyboard.

    However, if you want to do it all from code, flow this extremely simple example:

    class ViewController: UIViewController {
    
        var history: UIStackView!
        var scrollView: UIScrollView!
        
        override func viewDidLoad() {
            super.viewDidLoad()
            
            history = UIStackView()
            // vertical stack
            history.axis = .vertical
            // arranged subviews fill the width
            history.alignment = .fill
            // distribution
            history.distribution = .fill
            // spacing
            history.spacing = 12
            
            scrollView = UIScrollView()
            // so we can see it
            scrollView.backgroundColor = .cyan
            
            // we're using auto-layout constraints
            scrollView.translatesAutoresizingMaskIntoConstraints = false
            history.translatesAutoresizingMaskIntoConstraints = false
    
            // add the stack view to the scroll view
            scrollView.addSubview(history)
            
            // add the scroll view to the view
            view.addSubview(scrollView)
    
            // no no no... let auto-layout handle it
            //scrollView.contentSize = CGSize(width: view.bounds.width, height: view.bounds.height)
            
            // respect safe area
            let g = view.safeAreaLayoutGuide
            
            NSLayoutConstraint.activate([
                
                // constrain scroll view with 20-pts on each side
                scrollView.topAnchor.constraint(equalTo: g.topAnchor, constant: 20.0),
                scrollView.leadingAnchor.constraint(equalTo: g.leadingAnchor, constant: 20.0),
                scrollView.trailingAnchor.constraint(equalTo: g.trailingAnchor, constant: -20.0),
                scrollView.bottomAnchor.constraint(equalTo: g.bottomAnchor, constant: -20.0),
    
                // constrain stack view to all 4 sides of scroll view with 8-pts on each side
                history.topAnchor.constraint(equalTo: scrollView.topAnchor, constant: 8.0),
                history.leadingAnchor.constraint(equalTo: scrollView.leadingAnchor, constant: 8.0),
                history.trailingAnchor.constraint(equalTo: scrollView.trailingAnchor, constant: -8.0),
                history.bottomAnchor.constraint(equalTo: scrollView.bottomAnchor, constant: -8.0),
                
                // constrain stack view width to scroll view width minus 16 (for 8-pts on each side)
                history.widthAnchor.constraint(equalTo: scrollView.widthAnchor, constant: -16),
    
            ])
    
            // let's add 30 labels to the stack view
            for i in 1...30 {
                let label = UILabel()
                label.text = "Label: \(i)"
                // so we can see the label frames
                label.backgroundColor = .yellow
                history.addArrangedSubview(label)
            }
    
        }
        
    }
    

    As a side note: it would benefit you greatly to read the documentation and work through several scroll view tutorials. It looks like you tried to use pieces from the question you linked to without knowing what any of it meant.