I don't understand why you don't want to combine them into one table..
Anyway.. UIScrollView
doesn't work with Auto-Layout. You have to add a contentView with the same dimensions as the scrollView's parent OR with a fixed size.
Now that is out of the way, you constrain the tableViews to the scrollView's contentView, then override viewDidLayoutSubviews
of the controller. In that function, you need to get the contentSize of each tableView and constrain the height of each one to its content size. This will make the table full size and not scrollable.
Since the scrollView auto sizes based on its contents, you don't have to do anything else.
Alternatively, if you don't want to use AutoLayoutScrollView
, you can set the UIScrollView
contentSize to the sum of the contentSize of the 3 tables in viewDidLayoutSubviews
of the controller.
Note: I do not have any sample dynamic content for the tableViews but if you want them to use dynamic row sizes, you need to do:
table.estimatedRowHeight = 300 //Estimation of the average size of the rows.
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat
return UITableViewAutomaticDimension
}
Now for the actual code with hardcoded row heights (because I don't have dynamic test data):
//
// ViewController.swift
// SO
//
// Created by Brandon T on 2017-01-17.
// Copyright © 2017 XIO. All rights reserved.
//
import UIKit
class AutoLayoutScrollView : UIScrollView {
private(set) weak var contentView: UIView!
private var hConstraint: NSLayoutConstraint!
private var vConstraint: NSLayoutConstraint!
init() {
super.init(frame: .zero)
self.layout()
}
override init(frame: CGRect) {
super.init(frame: frame)
self.layout()
}
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
self.layout()
}
private func layout() {
let view = UIView()
self.contentView = view
self.addSubview(self.contentView)
self.contentView.leftAnchor.constraint(equalTo: self.leftAnchor).isActive = true
self.contentView.rightAnchor.constraint(equalTo: self.rightAnchor).isActive = true
self.contentView.topAnchor.constraint(equalTo: self.topAnchor).isActive = true
self.contentView.bottomAnchor.constraint(equalTo: self.bottomAnchor).isActive = true
self.contentView.translatesAutoresizingMaskIntoConstraints = false
}
override func didMoveToSuperview() {
super.didMoveToSuperview()
if let parent = self.superview {
self.leftAnchor.constraint(equalTo: parent.leftAnchor).isActive = true
self.rightAnchor.constraint(equalTo: parent.rightAnchor).isActive = true
self.topAnchor.constraint(equalTo: parent.topAnchor).isActive = true
self.bottomAnchor.constraint(equalTo: parent.bottomAnchor).isActive = true
self.translatesAutoresizingMaskIntoConstraints = false
self.hConstraint = self.contentView.widthAnchor.constraint(equalTo: parent.widthAnchor)
self.vConstraint = self.contentView.heightAnchor.constraint(equalTo: parent.heightAnchor)
self.hConstraint.isActive = true
self.vConstraint.isActive = true
}
}
func setHorizontalScrollEnabled(enabled: Bool) {
self.hConstraint.isActive = !enabled
}
func setVerticalScrollEnabled(enabled: Bool) {
self.vConstraint.isActive = !enabled
}
}
class ViewController: UIViewController, UITableViewDelegate, UITableViewDataSource {
private var scrollView: AutoLayoutScrollView!
private var topTableView: UITableView!
private var middleTableView: UITableView!
private var bottomTableView: UITableView!
private var topTableHeight: NSLayoutConstraint!
private var middleTableHeight: NSLayoutConstraint!
private var bottomTableHeight: NSLayoutConstraint!
override func viewDidLoad() {
super.viewDidLoad()
self.layout()
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
}
func layout() {
//Init Views
self.scrollView = AutoLayoutScrollView()
self.topTableView = UITableView(frame: .zero, style: .plain)
self.middleTableView = UITableView(frame: .zero, style: .plain)
self.bottomTableView = UITableView(frame: .zero, style: .plain)
self.registerClasses()
//Add Views
self.view.addSubview(self.scrollView)
self.scrollView.contentView.addSubview(self.topTableView)
self.scrollView.contentView.addSubview(self.middleTableView)
self.scrollView.contentView.addSubview(self.bottomTableView)
//Layout Views
self.topTableView.leftAnchor.constraint(equalTo: self.scrollView.contentView.leftAnchor).isActive = true
self.topTableView.rightAnchor.constraint(equalTo: self.scrollView.contentView.rightAnchor).isActive = true
self.topTableView.topAnchor.constraint(equalTo: self.scrollView.contentView.topAnchor).isActive = true
self.topTableView.translatesAutoresizingMaskIntoConstraints = false
self.middleTableView.leftAnchor.constraint(equalTo: self.scrollView.contentView.leftAnchor).isActive = true
self.middleTableView.rightAnchor.constraint(equalTo: self.scrollView.contentView.rightAnchor).isActive = true
self.middleTableView.topAnchor.constraint(equalTo: self.topTableView.bottomAnchor).isActive = true
self.middleTableView.translatesAutoresizingMaskIntoConstraints = false
self.bottomTableView.leftAnchor.constraint(equalTo: self.scrollView.contentView.leftAnchor).isActive = true
self.bottomTableView.rightAnchor.constraint(equalTo: self.scrollView.contentView.rightAnchor).isActive = true
self.bottomTableView.topAnchor.constraint(equalTo: self.middleTableView.bottomAnchor).isActive = true
self.bottomTableView.bottomAnchor.constraint(equalTo: self.scrollView.contentView.bottomAnchor).isActive = true
self.bottomTableView.translatesAutoresizingMaskIntoConstraints = false
self.topTableHeight = self.topTableView.heightAnchor.constraint(equalToConstant: 0)
self.middleTableHeight = self.middleTableView.heightAnchor.constraint(equalToConstant: 0)
self.bottomTableHeight = self.bottomTableView.heightAnchor.constraint(equalToConstant: 0)
//Set Views Properties
self.scrollView.setVerticalScrollEnabled(enabled: true)
self.topTableView.delegate = self
self.topTableView.dataSource = self
self.middleTableView.delegate = self
self.middleTableView.dataSource = self
self.bottomTableView.delegate = self
self.bottomTableView.dataSource = self
//Display Views
self.topTableView.reloadData()
self.middleTableView.reloadData()
self.bottomTableView.reloadData()
}
func registerClasses() {
self.topTableView.register(UITableViewCell.self, forCellReuseIdentifier: "cellID")
self.middleTableView.register(UITableViewCell.self, forCellReuseIdentifier: "cellID")
self.bottomTableView.register(UITableViewCell.self, forCellReuseIdentifier: "cellID")
}
override func viewDidLayoutSubviews() {
super.viewDidLayoutSubviews()
//Update tables constraints to full size.
self.topTableHeight.constant = self.topTableView.contentSize.height
self.middleTableHeight.constant = self.middleTableView.contentSize.height
self.bottomTableHeight.constant = self.bottomTableView.contentSize.height
self.topTableHeight.isActive = true
self.middleTableHeight.isActive = true
self.bottomTableHeight.isActive = true
}
func numberOfSections(in tableView: UITableView) -> Int {
return 1
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
if (tableView == self.topTableView) {
return 10
}
if (tableView == self.middleTableView) {
return 15
}
if (tableView == self.bottomTableView) {
return 3
}
return 0
}
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
if (tableView == self.topTableView) {
return 100
}
if (tableView == self.middleTableView) {
return 250
}
if (tableView == self.bottomTableView) {
return 500
}
return 0.0
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "cellID", for: indexPath)
if (tableView == self.topTableView) {
cell.contentView.backgroundColor = UIColor.red
}
if (tableView == self.middleTableView) {
cell.contentView.backgroundColor = UIColor.green
}
if (tableView == self.bottomTableView) {
cell.contentView.backgroundColor = UIColor.blue
}
return cell
}
}