I have a Scroll View, in which I have a Stack View. In the Stack View I have arranged subviews of either UITextView or UILabel elements. All is done programmatically, without storyboard.
The Scroll View appears and I can scroll it nicely. But unfortunately it scrolls not only vertically (top to bottom) but also horizontally (to the right, out the screen) which I don't want to (this is the reason I have numberOfLines set on the UILabel too, tried to set equal width to the scroll and stack views as the stack view's left/right attributes are connected to the view).
If it's important, this function is called either in viewDidLoad or upon touching a button later.
scrollView = UIScrollView()
scrollView.translatesAutoresizingMaskIntoConstraints = false
view.addSubview(scrollView)
let leftConstraintScroll = NSLayoutConstraint(item: scrollView, attribute: .left, relatedBy: .equal, toItem: view, attribute: .left, multiplier: 1, constant: 0)
let rightConstraintScroll = NSLayoutConstraint(item: scrollView, attribute: .right, relatedBy: .equal, toItem: view, attribute: .right, multiplier: 1, constant: 0)
let topConstraintScroll = NSLayoutConstraint(item: scrollView, attribute: .top, relatedBy: .equal, toItem: selectedTabIndicator, attribute: .bottom, multiplier: 1, constant: 10)
let bottomConstraintScroll = NSLayoutConstraint(item: scrollView, attribute: .bottom, relatedBy: .equal, toItem: editButton, attribute: .top, multiplier: 1, constant: 0)
view.addConstraints([leftConstraintScroll, rightConstraintScroll, topConstraintScroll, bottomConstraintScroll])
stackView = UIStackView()
stackView.translatesAutoresizingMaskIntoConstraints = false
stackView.axis = .vertical
stackView.spacing = 10
stackView.isLayoutMarginsRelativeArrangement = true
stackView.directionalLayoutMargins = NSDirectionalEdgeInsets(top: 5, leading: 10, bottom: 5, trailing: 10)
// Several elements are added like this (UITextView):
let textView = UITextView()
textView.translatesAutoresizingMaskIntoConstraints = false
textView.delegate = self
textView.isScrollEnabled = false
textView.font = UIFont.systemFont(ofSize: 15)
textView.backgroundColor = Constants.COLOR_P
textView.textColor = .black
textView.text = "XXX"
stackView.addArrangedSubview(textView)
// Or UILabel:
var label = UILabel()
label.translatesAutoresizingMaskIntoConstraints = false
label.numberOfLines = 0
label.textAlignment = .justified
label.textColor = .black
label.font = UIFont.systemFont(ofSize: 15)
let paragraphStyle = NSMutableParagraphStyle()
paragraphStyle.alignment = .justified
paragraphStyle.hyphenationFactor = 1.0
paragraphStyle.firstLineHeadIndent = 0
paragraphStyle.headIndent = 15
let hyphenAttribute = [NSAttributedString.Key.paragraphStyle: paragraphStyle]
let attributedString = NSMutableAttributedString(string: "XXXXX", attributes: hyphenAttribute)
label.attributedText = attributedString
stackView.addArrangedSubview(label)
scrollView.addSubview(stackView)
let leftConstraint = NSLayoutConstraint(item: stackView, attribute: .left, relatedBy: .equal, toItem: scrollView, attribute: .left, multiplier: 1, constant: 0)
let rightConstraint = NSLayoutConstraint(item: stackView, attribute: .right, relatedBy: .equal, toItem: scrollView, attribute: .right, multiplier: 1, constant: 0)
let topConstraint = NSLayoutConstraint(item: stackView, attribute: .top, relatedBy: .equal, toItem: scrollView, attribute: .top, multiplier: 1, constant: 0)
let bottomConstraint = NSLayoutConstraint(item: stackView, attribute: .bottom, relatedBy: .equal, toItem: scrollView, attribute: .bottom, multiplier: 1, constant: 0)
scrollView.addConstraints([leftConstraint, rightConstraint, topConstraint, bottomConstraint, bottomConstraint])
Note: selectedTabIndicator and editButton are above and below the scroll view respectively.