3

I have a UIScrollView. It has a stack view. And this stack view contains 12 buttons. (Horizontal scroll view)

Stackview constraints :- top,leading,trailing,bottom to the scroll view and equal widths to the scroll view.

My problem is every time when I run, stack view width limits to the scroll view width and buttons are too small acording to the width of the stack view and my scroll view is not scrollable.

How to make this scrollable

user1960169
  • 3,533
  • 12
  • 39
  • 61
  • Do you have a contentview inside the scrollview or are you adding the stackview directly to to the scrollview? See [Apple's Guide to working with scrollviews](https://developer.apple.com/library/content/documentation/UserExperience/Conceptual/AutolayoutPG/WorkingwithScrollViews.html) – TheBaj Jul 14 '17 at 15:23
  • no I dont have a content view,, im adding the stack view directly into the scroll view @TheBaj – user1960169 Jul 14 '17 at 15:24
  • Well, don't do that. Read the guide and follow the steps and you should be fine. – TheBaj Jul 14 '17 at 15:24
  • @TheBaj - UIStackViews work great when added directly to a scroll view - just have to set the constraints properly. – DonMag Jul 14 '17 at 15:26
  • Right, but if he's going to add more content to the scrollview than just the stackview, it would be better to work with a content view – TheBaj Jul 14 '17 at 15:27
  • Do you want to create this layout in code or in storyboard? – rob mayoff Jul 14 '17 at 15:39
  • @TheBaj - doesn't matter... whether you're putting views + buttons + labels + image views (all types of views) as subviews of a *single content view*, or if you add them as subviews of the scroll view, you ***still*** want constraints and auto-layout to determine the `.contentSize` instead of setting it manually with some sort of calculation. – DonMag Jul 14 '17 at 15:42
  • I see, i was under the impression that it's better with a content view. Good to know. – TheBaj Jul 14 '17 at 15:43
  • @robmayoff using storyboard – user1960169 Jul 14 '17 at 15:50
  • @TheBaj - just to clarify... In *some* cases, adding subviews to a "content view" which is the subview of a scroll view will have benefits. In *other* cases, that is just adding one more level of complexity. In my view, it's just good to know (and understand) both approaches, so I can use the better method for my current task. – DonMag Jul 14 '17 at 16:26

3 Answers3

13

Step-by-Step for setting this up in IB / Storyboards...

  1. Add a view - height 50 leading/top/trailing - blue background

enter image description here

  1. add a scrollview to that view - pin leading/top/trailing/bottom to 0 - set scrollview background to yellow so we can see where it is

enter image description here

  1. add a button to the scroll view

enter image description here

  1. duplicate it so you have 12 buttons

enter image description here

  1. group them into a stack view, and set the stack view's constraints to 0 leading/top/trailing/bottom

enter image description here

  1. and set the stack view's distribution to "equal spacing"

enter image description here

  1. result running in simulator (with no code at all):

enter image description here

and the buttons scroll left and right... no code setting of .contentSize...

DonMag
  • 69,424
  • 5
  • 50
  • 86
  • when I add buttons and group them into stack view then set constraint,, then my buttons are appearing below of the scroll not sure whats wrong – user1960169 Jul 14 '17 at 16:54
3

So you want this:

demo

Here's how I did it in Xcode 8.3.3.

  1. New Project > iOS > Single View Application.

  2. Open Main.storyboard.

  3. Drag a scroll view into the scene.

  4. Pin top, leading, and trailing of the scroll view to 0. Set height to 30.

    scroll view constraints

  5. Drag a horizontal stack view into the scroll view.

  6. Pin all four edges of the stack view to 0.

    stack view constraints

  7. Set stack view spacing to 4.

  8. Drag twelve buttons into the stack view.

  9. Set target device to iPhone SE.

  10. Build & run.

Resulting document outline:

document outline

rob mayoff
  • 375,296
  • 67
  • 796
  • 848
2

If you make your Stackview width equal to the scrollview width, then that's all you'll get, and of course it won't scroll.

Don't give your Stackview a width constraint... let the buttons "fill it out".


Edit: Here is a simple example that you can run directly in a Playground page:

import UIKit
import PlaygroundSupport

class TestViewController : UIViewController {

    let scrollView: UIScrollView = {
        let v = UIScrollView()
        v.translatesAutoresizingMaskIntoConstraints = false
        v.backgroundColor = .cyan
        return v
    }()

    let stackView : UIStackView = {
        let v = UIStackView()
        v.translatesAutoresizingMaskIntoConstraints = false
        v.axis = .horizontal
        v.distribution = .equalSpacing
        v.spacing = 10.0
        return v
    }()


    override func viewDidLoad() {
        super.viewDidLoad()

        // add the scroll view to self.view
        self.view.addSubview(scrollView)

        // constrain the scroll view to 8-pts on each side
        scrollView.leftAnchor.constraint(equalTo: view.leftAnchor, constant: 8.0).isActive = true
        scrollView.topAnchor.constraint(equalTo: view.topAnchor, constant: 8.0).isActive = true
        scrollView.rightAnchor.constraint(equalTo: view.rightAnchor, constant: -8.0).isActive = true
        scrollView.bottomAnchor.constraint(equalTo: view.bottomAnchor, constant: -8.0).isActive = true


        // add the stack view to the scroll view 
        scrollView.addSubview(stackView)

        // constrain the stackview view to 8-pts on each side
        //   this *also* controls the .contentSize of the scrollview
        stackView.leftAnchor.constraint(equalTo: scrollView.leftAnchor, constant: 8.0).isActive = true
        stackView.topAnchor.constraint(equalTo: scrollView.topAnchor, constant: 8.0).isActive = true
        stackView.rightAnchor.constraint(equalTo: scrollView.rightAnchor, constant: -8.0).isActive = true
        stackView.bottomAnchor.constraint(equalTo: scrollView.bottomAnchor, constant: -8.0).isActive = true

        // add ten buttons to the stack view
        for i in 1...10 {

            let b = UIButton()
            b.translatesAutoresizingMaskIntoConstraints = false
            b.setTitle("Button \(i)", for: .normal)
            b.backgroundColor = .blue
            stackView.addArrangedSubview(b)

        }

    }

}

let vc = TestViewController()
vc.view.backgroundColor = .yellow
PlaygroundPage.current.liveView = vc
DonMag
  • 69,424
  • 5
  • 50
  • 86
  • So I want to give every button the width constraint? – user1960169 Jul 14 '17 at 15:22
  • You don't *need* to, because `UIButton` has an intrinsic width, based on the label. Or, you can give them explicit width constraints. – DonMag Jul 14 '17 at 15:25
  • I deleted the width constraint of the stack view also the equalwidth to the scroll view. And set each buttons width constraints. And I set the content size of the scrollview by code width=120*12 and heigth=scrollview.height. but scrollview is not scrolling. – user1960169 Jul 14 '17 at 15:29
  • 1
    Don't set the `.contentSize` - that's what constraints are for. Make sure your stack view distribution is set to equal spacing. – DonMag Jul 14 '17 at 15:32
  • distribution is Fill equally do I need to set equal spacing? But I dont want spaces in between those buttons – user1960169 Jul 14 '17 at 15:33
  • Set the spacing to 0 if you don't want space between the buttons. If you set the Stack view to "Fill equally" you are saying "make each object in this stack of views the same width - based on the total width of the stack view". What you *want* to do is say "make the stack view the width of all these equal-width views" – DonMag Jul 14 '17 at 15:39
  • from storyboard. I set the spacing 0 but no luck :( – user1960169 Jul 14 '17 at 15:40
  • Let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/149237/discussion-between-donmag-and-user1960169). – DonMag Jul 14 '17 at 15:42