Using ScrollView Programmatically in Swift 3 Using ScrollView Programmatically in Swift 3 ios ios

Using ScrollView Programmatically in Swift 3


It is easy to use constraints to define the scroll content size - so you don't have to do any manual calculations.

Just remember:

  1. The content elements of your scroll view must have left / top / width / height values. In the case of objects such as labels, they have intrinsic sizes, so you only have to define the left & top.
  2. The content elements of your scroll view also define the bounds of the scrollable area - the contentSize - but they do so with the bottom & right constraints.
  3. Combining those two concepts, you see that you need a "continuous chain" with at least one element defining the top / left / bottom / right extents.

Here is a simple example, that will run directly in a Playground page:

import UIKitimport PlaygroundSupportclass TestViewController : UIViewController {    let labelOne: UILabel = {        let label = UILabel()        label.text = "Scroll Top"        label.backgroundColor = .red        label.translatesAutoresizingMaskIntoConstraints = false        return label    }()    let labelTwo: UILabel = {        let label = UILabel()        label.text = "Scroll Bottom"        label.backgroundColor = .green        label.translatesAutoresizingMaskIntoConstraints = false        return label    }()    let scrollView: UIScrollView = {        let v = UIScrollView()        v.translatesAutoresizingMaskIntoConstraints = false        v.backgroundColor = .cyan        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 labelOne to the scroll view        scrollView.addSubview(labelOne)        // constrain labelOne to left & top with 16-pts padding        // this also defines the left & top of the scroll content        labelOne.leadingAnchor.constraint(equalTo: scrollView.leadingAnchor, constant: 16.0).isActive = true        labelOne.topAnchor.constraint(equalTo: scrollView.topAnchor, constant: 16.0).isActive = true        // add labelTwo to the scroll view        scrollView.addSubview(labelTwo)        // constrain labelTwo at 400-pts from the left        labelTwo.leadingAnchor.constraint(equalTo: scrollView.leadingAnchor, constant: 400.0).isActive = true        // constrain labelTwo at 1000-pts from the top        labelTwo.topAnchor.constraint(equalTo: scrollView.topAnchor, constant: 1000).isActive = true        // constrain labelTwo to right & bottom with 16-pts padding        labelTwo.rightAnchor.constraint(equalTo: scrollView.rightAnchor, constant: -16.0).isActive = true        labelTwo.bottomAnchor.constraint(equalTo: scrollView.bottomAnchor, constant: -16.0).isActive = true    }}let vc = TestViewController()vc.view.backgroundColor = .yellowPlaygroundPage.current.liveView = vc


Two things.

1. Add the labels to scroll view, not your view

You want your label to scroll with scroll view, then you should not add it on your view. When running your code, you can scroll but the fixed label there is pinned to your view, not on your scroll view

2. Make sure you added your constraints correctly

Try it on your storyboard about what combination of constraint is enough for a view. At least 4 constraints are needed for a label.

Bottom line

Here is a modified version of your code. For constraint I added padding left, padding top, width and height and it works. My code is

let labelOne: UILabel = {    let label = UILabel()    label.text = "Scroll Top"    label.backgroundColor = .red    label.translatesAutoresizingMaskIntoConstraints = false    return label}()let labelTwo: UILabel = {    let label = UILabel()    label.text = "Scroll Bottom"    label.backgroundColor = .green    label.translatesAutoresizingMaskIntoConstraints = false    return label}()override func viewDidLoad() {    super.viewDidLoad()    let screensize: CGRect = UIScreen.main.bounds    let screenWidth = screensize.width    let screenHeight = screensize.height    var scrollView: UIScrollView!    scrollView = UIScrollView(frame: CGRect(x: 0, y: 120, width: screenWidth, height: screenHeight))    scrollView.addSubview(labelTwo)    NSLayoutConstraint(item: labelTwo, attribute: .leading, relatedBy: .equal, toItem: scrollView, attribute: .leadingMargin, multiplier: 1, constant: 10).isActive = true    NSLayoutConstraint(item: labelTwo, attribute: .width, relatedBy: .equal, toItem: nil, attribute: .notAnAttribute, multiplier: 1, constant: 200).isActive = true    NSLayoutConstraint(item: labelTwo, attribute: .top, relatedBy: .equal, toItem: scrollView, attribute: .topMargin, multiplier: 1, constant: 10).isActive = true    NSLayoutConstraint(item: labelTwo, attribute: .height, relatedBy: .equal, toItem: nil, attribute: .notAnAttribute, multiplier: 1, constant: 30).isActive = true    scrollView.contentSize = CGSize(width: screenWidth, height: 2000)    view.addSubview(scrollView)}

And the scroll view looks like this

enter image description here


For me this work like charm

class WithDrawConfirmationViewController: UIViewController, WithDrawConfirmationViewProtocol {    var presenter: WithDrawConfirmationPresenterProtocol?    private let viewbackgroundColor = UIColor(hexString: "#F5F5F8")    // MARK:- View properties    lazy var scrollView: UIScrollView = {        let scrollView = UIScrollView()        //view.backgroundColor = .red        scrollView.translatesAutoresizingMaskIntoConstraints = false        return scrollView    }()        lazy var contentView: UIView = {        let view = UIView()        //view.backgroundColor = .green        view.translatesAutoresizingMaskIntoConstraints = false        return view    }()        lazy var headerView: UIView = {        let view = UIView()        view.translatesAutoresizingMaskIntoConstraints = false        return view    }()        private lazy var titleLabel:UILabel = {        let label = UILabel()        label.translatesAutoresizingMaskIntoConstraints = false        label.textColor = UIColor.themeBlack        label.text = "Withdraw Confirmation"//"Loading.."        label.textAlignment = .center        label.font = UIFont(name: "AvenirNext-DemiBold", size: 20)        label.numberOfLines = 0        label.lineBreakMode = .byWordWrapping        return label    }()            private lazy var descriptionLabel:UILabel = {        let label = UILabel()        label.translatesAutoresizingMaskIntoConstraints = false        label.textColor = UIColor.themeGray        label.text = "Please confirm your fixed deposit details before withdrawing your deposit"// "Loading.."        label.textAlignment = .center        label.font = UIFont(name: "AvenirNext-Medium", size: 14)        label.numberOfLines = 0        label.lineBreakMode = .byWordWrapping        label.setContentHuggingPriority(1000, for: .vertical)        return label    }()        private lazy var instructionLabel: UILabel = {        let label = UILabel()        label.translatesAutoresizingMaskIntoConstraints = false        label.textColor = UIColor.themeGray        label.text = "Complete fixed deposit will be withdrawn and the money will be debited to your account within 1-2 working days."//"Loading.."        label.textAlignment = .left        label.font = UIFont(name: "AvenirNext-Medium", size: 14)        label.numberOfLines = 0        label.lineBreakMode = .byWordWrapping        return label    }()        private lazy var warningLabel: UILabel = {        let label = UILabel()        label.translatesAutoresizingMaskIntoConstraints = false        label.textColor = UIColor.themeBlue        label.text = "Axis bank will levy a penalty of 1% - 2% for premature withdrawal"//"Loading.."        label.textAlignment = .left        label.font = UIFont(name: "AvenirNext-DemiBold", size: 13)        label.numberOfLines = 0        label.lineBreakMode = .byWordWrapping        return label    }()        private lazy var warningView: UIView = {        let view = UIView()        view.cornerradius = 5        view.backgroundColor = UIColor(hexFromString: "#E8F4FD")        view.translatesAutoresizingMaskIntoConstraints = false        return view    }()    private lazy var fdInformationDetailView: FDPurchaseDetailView = {        let view = FDPurchaseDetailView(isPoweredByViewVisible: false)        //view.backgroundColor = .red        view.translatesAutoresizingMaskIntoConstraints = false        return view    }()        private lazy var footerCTAView: FooterButtonViewView = {        let view = FooterButtonViewView()        view.translatesAutoresizingMaskIntoConstraints = false        return view    }()        // MARK:- Life cycle    override func viewDidLoad() {        super.viewDidLoad()        contentView.backgroundColor = viewbackgroundColor        scrollView.backgroundColor = viewbackgroundColor        setUpUI()        presenter?.viewDidLoadTriggered()    }    override func viewDidLayoutSubviews() {        super.viewDidLayoutSubviews()    }        private func setUpUI() {        view.addSubview(scrollView)        scrollView.addSubview(contentView)        view.backgroundColor = viewbackgroundColor        addFooter()        setUpHeaderView()        setUpFDDetailView()        setUpInformationAndWarningView()        //scrollView.backgroundColor = .lightGray        scrollView.leadingAnchor.constraint(equalTo: view.leadingAnchor).isActive = true        scrollView.trailingAnchor.constraint(equalTo: view.trailingAnchor).isActive = true        scrollView.topAnchor.constraint(equalTo: view.safeAreaLayoutGuide.topAnchor).isActive = true        scrollView.bottomAnchor.constraint(equalTo: footerCTAView.topAnchor).isActive = true        scrollView.contentInset = UIEdgeInsets(top: 0, left: 0, bottom: 100, right: 0)                contentView.leadingAnchor.constraint(equalTo: scrollView.leadingAnchor).isActive = true        contentView.trailingAnchor.constraint(equalTo: scrollView.trailingAnchor).isActive = true        contentView.topAnchor.constraint(equalTo: scrollView.topAnchor).isActive = true        contentView.bottomAnchor.constraint(equalTo: scrollView.bottomAnchor).isActive = true        contentView.widthAnchor.constraint(equalTo: view.widthAnchor).isActive = true        //contentView.bottomAnchor.constraint(equalTo: footerCTAView.topAnchor).isActive = true    }        private func setUpHeaderView() {        contentView.addSubview(headerView)        headerView.addSubviews([titleLabel, descriptionLabel])                headerView.leadingAnchor.constraint(equalTo: contentView.leadingAnchor, constant: 20).isActive = true        headerView.trailingAnchor.constraint(equalTo: contentView.trailingAnchor, constant: -20).isActive = true        headerView.topAnchor.constraint(equalTo: contentView.topAnchor, constant: 4).isActive = true               titleLabel.leadingAnchor.constraint(equalTo: headerView.leadingAnchor, constant: 8).isActive = true        titleLabel.trailingAnchor.constraint(equalTo: headerView.trailingAnchor).isActive = true        titleLabel.topAnchor.constraint(equalTo: headerView.topAnchor, constant: 8).isActive = true                descriptionLabel.topAnchor.constraint(equalTo: titleLabel.bottomAnchor, constant:  20).isActive = true        descriptionLabel.leadingAnchor.constraint(equalTo: headerView.leadingAnchor, constant: 8).isActive = true        descriptionLabel.trailingAnchor.constraint(equalTo: headerView.trailingAnchor).isActive = true        descriptionLabel.bottomAnchor.constraint(equalTo: headerView.bottomAnchor, constant: -20).isActive = true    }            private func setUpFDDetailView() {        contentView.addSubview(fdInformationDetailView)        fdInformationDetailView.topAnchor.constraint(equalTo: headerView.bottomAnchor).isActive = true        fdInformationDetailView.leadingAnchor.constraint(equalTo: contentView.leadingAnchor, constant: 20).isActive = true        fdInformationDetailView.trailingAnchor.constraint(equalTo: contentView.trailingAnchor, constant: -20).isActive = true           }        private func setUpInformationAndWarningView() {        contentView.addSubview(instructionLabel)                instructionLabel.topAnchor.constraint(equalTo: fdInformationDetailView.bottomAnchor, constant: 20).isActive = true        instructionLabel.leadingAnchor.constraint(equalTo: contentView.leadingAnchor, constant: 20).isActive = true        instructionLabel.trailingAnchor.constraint(equalTo: contentView.trailingAnchor, constant: -20).isActive = true                warningView.addSubview(warningLabel)        warningLabel.topAnchor.constraint(equalTo: warningView.topAnchor, constant: 8).isActive = true        warningLabel.leadingAnchor.constraint(equalTo: warningView.leadingAnchor, constant: 20).isActive = true        warningLabel.trailingAnchor.constraint(equalTo: warningView.trailingAnchor, constant: -20).isActive = true        warningLabel.bottomAnchor.constraint(equalTo: warningView.bottomAnchor, constant: -8).isActive = true                contentView.addSubview(warningView)                warningView.topAnchor.constraint(equalTo: instructionLabel.bottomAnchor, constant: 8).isActive = true        warningView.leadingAnchor.constraint(equalTo: contentView.leadingAnchor, constant: 20).isActive = true        warningView.trailingAnchor.constraint(equalTo: contentView.trailingAnchor, constant: -20).isActive = true       //warningView.centerXAnchor.constraint(equalTo: contentView.centerXAnchor).isActive = true        warningView.bottomAnchor.constraint(greaterThanOrEqualTo: contentView.bottomAnchor, constant: -20).isActive = true            }        private func addFooter() {        view.addSubview(footerCTAView)        footerCTAView.delegate = self        footerCTAView.leadingAnchor.constraint(equalTo: view.leadingAnchor).isActive = true        footerCTAView.trailingAnchor.constraint(equalTo: view.trailingAnchor).isActive = true        footerCTAView.bottomAnchor.constraint(equalTo: view.safeAreaLayoutGuide.bottomAnchor).isActive = true    }}