Disable horizontal scroll in UIScrollView with autolayout

29,607

Solution 1

1) Horizontal scroll enables automatically when the content width in scrollView more than width of scrollView. Therefore, in order to avoid horizontal scrolling is necessary to make width of the content inside scrollView less than or equal to scrollView width.

Leading space and trailing space can't set specific width to views, they just stretch them. In regular views, they no stretch for more than width of view, but scrollView is a special view, actually, with an infinite content width. Therefore, trailing space and leading space constraints in scrollView change the width of views to their maximum possible values (In case with UILabel you can see resize to fit the text).

To avoid horizontal scrolling, you need to set specific width of each view, less than or equal to scrollView width. Specific width of views may be set with width constraints.

Instead of setting each view width, much better to add a view–container and set width to it, and inside it place the views as needed.

Views hierarchy:

View
    -> ScrollView
        -> ContainerView
            -> UILabel
            -> UILabel
            -> ... other views that you need

Autolayout constraints:

ScrollView
    -> leading space to View : 0
    -> trailing space to View : 0
    -> top space to View : 0
    -> bottom space to View : 0

Container View
    -> leading space to ScrollView : 0
    -> trailing space to ScrollView : 0
    -> top space to ScrollView : 0
    -> bottom space to ScrollView : 0
    -> width equal to ScrollView : 0

To set width equal constraint ctrl+drag from containerView to scrollView.

width equal constraint

2) Vertical scroll is dependent on the total height of content. Blank space can be, if the last element inside containerView has a large value of the bottom space to superview.

Or do you mean bounce effect? You can disable vertical bounce of scrollView.

Solution 2

You can also easily do this in code. In my case, I have a UIStackView that's the only subview of a UIScrollView

// Create the stack view
let stackView = UIStackView()
stackView.translatesAutoresizingMaskIntoConstraints = false
// Add things to the stack view....

// Add it as a subview to the scroll view
scrollView.addSubview(stackView)

// Use auto layout to pin the stack view's sides to the scroll view
NSLayoutConstraint.activate([
    stackView.leadingAnchor.constraint(equalTo: scrollView.leadingAnchor),
    scrollView.trailingAnchor.constraint(equalTo: stackView.trailingAnchor),

    stackView.topAnchor.constraint(equalTo: scrollView.topAnchor),
    scrollView.bottomAnchor.constraint(equalTo: stackView.bottomAnchor)
])

// Now make sure the thing doesn't scroll horizontally
let margin: CGFloat = 40

scrollView.contentInset = UIEdgeInsets(top: margin, left: margin, bottom: margin, right: margin)

scrollView.widthAnchor.constraint(equalTo: view.widthAnchor).isActive = true

let stackViewWidthConstraint = stackView.widthAnchor.constraint(equalTo: scrollView.widthAnchor)
stackViewWidthConstraint.constant = -(margin * 2)
stackViewWidthConstraint.isActive = true

The NSLayoutConstraint.activate bit is taken from Dave DeLong's excellent UIView extension here: https://github.com/davedelong/MVCTodo/blob/master/MVCTodo/Extensions/UIView.swift#L26

Share:
29,607

Related videos on Youtube

Panich Maxim
Author by

Panich Maxim

Updated on July 09, 2022

Comments

  • Panich Maxim
    Panich Maxim almost 2 years

    I want to create view with only vertical scroll. As it turned out it is epic hard to do in iOs. I have done this steps:

    1) Create UIViewController in storyboard;

    2) Add ScrollView inside View in UIViewController and add 0 constrains to each side.

    3) Add elements in scrollview, as result: enter image description here

    After I launch my app all works, but:

    1) How should I disable horizontal scroll? I add 0 constrain to the right to my scrollView + 0 constrain to the right to my uilabel (as u see on screen for some reasons it is not attached to the right, it has different constrain, but in property I set constrain = 0) and, as I thought, label text supposed to be in my screen bounds, but when I launch app I can scroll to right, i.e. uilable text didn't wrap, my scrollview just resize to fit the text.I tried to set my scrollView in code: scrollView.contentSize = CGSize(UIScreen.mainScreen().bounds.width, height: 800), but didn't help.

    2) If I scroll to much, then blank space appears and this is not cool, how to fix it?

  • Houman
    Houman over 8 years
    This was an excellent solution. Unlike most other solutions, this can be done just in interface builder, without need to set the contentSize manually in code.
  • Parimal
    Parimal about 8 years
    Thank you, But my all the control is not responding. Textfield and buttons are not clickable.