Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
//
// SimpleScrollingStack.swift
// A super-simple demo of a scrolling UIStackView in iOS 9
//
// Created by Paul Hudson on 10/06/2015.
// Learn Swift at www.hackingwithswift.com
// @twostraws
//
import UIKit
class ViewController: UIViewController {
var scrollView: UIScrollView!
var stackView: UIStackView!
override func viewDidLoad() {
super.viewDidLoad()
scrollView = UIScrollView()
scrollView.translatesAutoresizingMaskIntoConstraints = false
view.addSubview(scrollView)
view.addConstraints(NSLayoutConstraint.constraintsWithVisualFormat("H:|[scrollView]|", options: .AlignAllCenterX, metrics: nil, views: ["scrollView": scrollView]))
view.addConstraints(NSLayoutConstraint.constraintsWithVisualFormat("V:|[scrollView]|", options: .AlignAllCenterX, metrics: nil, views: ["scrollView": scrollView]))
stackView = UIStackView()
stackView.translatesAutoresizingMaskIntoConstraints = false
stackView.axis = .Vertical
scrollView.addSubview(stackView)
scrollView.addConstraints(NSLayoutConstraint.constraintsWithVisualFormat("H:|[stackView]|", options: NSLayoutFormatOptions.AlignAllCenterX, metrics: nil, views: ["stackView": stackView]))
scrollView.addConstraints(NSLayoutConstraint.constraintsWithVisualFormat("V:|[stackView]", options: NSLayoutFormatOptions.AlignAllCenterX, metrics: nil, views: ["stackView": stackView]))
for _ in 1 ..< 100 {
let vw = UIButton(type: UIButtonType.System)
vw.setTitle("Button", forState: .Normal)
stackView.addArrangedSubview(vw)
}
}
override func viewDidLayoutSubviews() {
super.viewDidLayoutSubviews()
scrollView.contentSize = CGSize(width: stackView.frame.width, height: stackView.frame.height)
}
}
@mrdaios

This comment has been minimized.

Copy link

commented Jul 17, 2015

it's very good!

@dmoss18

This comment has been minimized.

Copy link

commented Sep 22, 2015

Is this not possible in IB? Does it have to be done programmatically?

@rzulkoski

This comment has been minimized.

Copy link

commented Nov 3, 2015

It is not necessary to override viewDidLayoutSubviews() here. Just change line 33 to also attach to the bottom of the scrollView with this visualFormatString: "V:|[stackView]|" (Notice the added '|' at the end of the string)

After making this change everything works as expected and you don't have to set the contentSize manually.

@kaksisa

This comment has been minimized.

Copy link

commented Feb 5, 2016

For some strange reason I had trouble with this example depending on what I placed in the stackView. With the buttons in the stackView as per this example I noticed viewDidLayoutSubviews() was called twice. The first time the stackView frame size was 0 and the second time correct. When I placed only labels inside the stackView viewDidLayoutSubviews() was only called once with the 0 frame size and thus the scrollView contentSize was not set correctly. I found overriding viewDidAppear:animated instead solved this problem.

@Jon889

This comment has been minimized.

Copy link

commented Feb 5, 2016

In line 44 you can do scrollView.contentSize = stackView.frame.size

Doesn't seem much point making a new CGSize.

@cargath

This comment has been minimized.

Copy link

commented Mar 18, 2016

Hm, when i replace the UIButtons with UIViews, they don't appear. Does anyone know what i am doing wrong?

for _ in 1 ..< 100 {
    let view = UIView(frame: CGRect(x: 0, y: 0, width: 42, height: 42))
    view.backgroundColor = UIColor(red: CGFloat(drand48()), green: CGFloat(drand48()), blue: CGFloat(drand48()), alpha: 1.0)
    stackView.addArrangedSubview(view)
}
@luzemma

This comment has been minimized.

Copy link

commented Apr 17, 2016

Hi cargath!

You need to put this line before add the view "view.heightAnchor.constraintEqualToConstant(100).active = true". It works for me.

@JamWils

This comment has been minimized.

Copy link

commented May 9, 2016

@cargath, a UIView has no intrinsic content size like the UIButton. You have to give each one a size so the UIStackView can figure out how to lay it out.

@lucasp90

This comment has been minimized.

Copy link

commented Jun 1, 2016

I've managed to make it work adding what @rzulkoski pointed out. Thanks a lot!!

@dolubajo

This comment has been minimized.

Copy link

commented Jun 28, 2016

@twostraws I've taken this example and tried to center align the buttons, and it doesn't seem to work, does anyone know why ?

Here's a detailed explanation of this problem: http://stackoverflow.com/q/38074366/502130

UPDATE

I've fixed the center alignment problem by setting an extra equal width constraint on the scrollView with the stackView

scrollView.addConstraints(NSLayoutConstraint.constraintsWithVisualFormat("H:[stackView(==scrollView)]", options: .AlignAllCenterX, metrics: nil, views: ["stackView": stackView, "scrollView": scrollView]))
@CGS-Christopher-Seidl

This comment has been minimized.

Copy link

commented Jul 11, 2016

This is great, it really helped me with my project!

@DevAndArtist

This comment has been minimized.

Copy link

commented Aug 15, 2016

@twostraws

Here is a better trick!

Remove this:

override func viewDidLayoutSubviews() {
    super.viewDidLayoutSubviews()
    scrollView.contentSize = CGSize(width: stackView.frame.width, height: stackView.frame.height)       
}

And add | to your constraints:

scrollView.addConstraints(NSLayoutConstraint.constraintsWithVisualFormat("V:|[stackView]|", options: NSLayoutFormatOptions.AlignAllCenterX, metrics: nil, views: ["stackView": stackView]))

Setting Top and Bottom constraints doesn't mean setting a fixed height on UIScrollView.

Learned that here.

@falnatsheh

This comment has been minimized.

Copy link

commented Jul 13, 2017

Awesome! I converted the constraints to SnapKit and incorporated @DevAndArtist note, you could view the code here.

@nicolas-miari

This comment has been minimized.

Copy link

commented Mar 28, 2018

Why is it .AlignAllCenterX for both "H" and "V"? Shouldn't it be .AlignAllCenterY on each second line?

@krishnastvSMSC

This comment has been minimized.

Copy link

commented May 15, 2019

Tap action is not working for StackView objects, how we can add tap gestures for this scroll of stack view.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.