Skip to content

Instantly share code, notes, and snippets.

@twostraws
Created June 10, 2015 19:06
Show Gist options
  • Star 77 You must be signed in to star a gist
  • Fork 12 You must be signed in to fork a gist
  • Save twostraws/a02d4cc09fc7bc16859c to your computer and use it in GitHub Desktop.
Save twostraws/a02d4cc09fc7bc16859c to your computer and use it in GitHub Desktop.
//
// 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
Copy link

mrdaios commented Jul 17, 2015

it's very good!

@dmoss18
Copy link

dmoss18 commented Sep 22, 2015

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

@rzulkoski
Copy link

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
Copy link

kaksisa 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
Copy link

Jon889 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
Copy link

cargath 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
Copy link

luzemma 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
Copy link

JamWils 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
Copy link

lucasp90 commented Jun 1, 2016

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

@truseed
Copy link

truseed 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
Copy link

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

@DevAndArtist
Copy link

DevAndArtist 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
Copy link

falnatsheh commented Jul 13, 2017

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

@nicolas-miari
Copy link

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

@krishnastvSMSC
Copy link

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