I have a weird requirement for UI, and need to scroll a table view in a page view using the scroll view I embed the page view in. For example:
import UIKit
class TableVC: UIViewController {
let tableView = UITableView()
var observer: NSKeyValueObservation?
override func viewDidLoad() {
super.viewDidLoad()
setupTableView()
}
func setupTableView() {
view.addSubview(tableView)
tableView.translatesAutoresizingMaskIntoConstraints = false
NSLayoutConstraint.activate([
tableView.leadingAnchor.constraint(equalTo: view.leadingAnchor),
tableView.trailingAnchor.constraint(equalTo: view.trailingAnchor),
tableView.topAnchor.constraint(equalTo: view.topAnchor),
tableView.heightAnchor.constraint(equalToConstant: 2000)
])
tableView.dataSource = self
tableView.delegate = self
tableView.isScrollEnabled = false
tableView.backgroundColor = .blue
let handler = { (tableView: UITableView, change: NSKeyValueObservedChange<CGSize>) in
if let contentSize = change.newValue {
print("contentSize:", contentSize)
}
}
observer = tableView.observe(\UITableView.contentSize, options: [NSKeyValueObservingOptions.new], changeHandler: handler)
}
}
extension TableVC: UITableViewDelegate {
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
50.0
}
}
extension TableVC: UITableViewDataSource {
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return 40
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = UITableViewCell()
cell.backgroundColor = .green
return cell
}
}
And the main view controller:
import UIKit
class ViewController: UIViewController {
private enum Constants {
static let pageViewControllerOptions: [UIPageViewController.OptionsKey: Any] = [
.interPageSpacing: CGFloat(8.0)
]
}
private let pageVC: UIPageViewController = UIPageViewController(
transitionStyle: .scroll,
navigationOrientation: .horizontal,
options: Constants.pageViewControllerOptions
)
let scrollView: UIScrollView = UIScrollView()
override func viewDidLoad() {
super.viewDidLoad()
view.addSubview(scrollView)
scrollView.pin(to: view)
let stackView = UIStackView()
stackView.axis = .vertical
stackView.frame = view.bounds
stackView.autoresizingMask = [.flexibleWidth, .flexibleHeight]
scrollView.addSubview(stackView)
let blueView = UIView()
blueView.backgroundColor = .blue
stackView.addArrangedSubview(blueView)
blueView.translatesAutoresizingMaskIntoConstraints = false
blueView.heightAnchor.constraint(equalToConstant: 100.0).isActive = true
addChild(pageVC)
pageVC.didMove(toParent: self)
let pageView = pageVC.view!
stackView.addArrangedSubview(pageView)
pageVC.setViewControllers([TableVC()], direction: .forward, animated: false, completion: nil)
// 50 height with 20 cells works fine
// 50 height with 40 cells won't work beacuse it doesn't seem to load them all
scrollView.contentSize = CGSize(width: view.bounds.width, height: 2000 + 100)
}
}
With 40 cells I am expecting a content size of 2000, I set this above (allowing for the height of the blue view also). The scrolling works but it seems like at some point it has stopped generating the cells:
In the gif above you can see there are less than 40 cells. I have tried using a larger table view height, calling layoutIfNeeded but the result is the same. Is there anything I can do to fix this? I imagine the cells are not loading because I am not using the table view's own scroll view so cellForRow isn't triggered. Is there another way to load the cells?
Related
Hello what I have is a UITableViewController which displays various sliding out menu options. The idea I have is instead of the menu options to be displayed right below the navigation bar but rather include an image and have these items displayed below the image. I tried to anchor the UITable view to the bottom anchor of the image but it does not work.
Below are some images:
class MenuViewController: UITableViewController {
public var delegate: MenuControllerDelagate?
private let menuItems: [MenuOptions]
let darkColour = UIColor(displayP3Red: 33/255.0, green: 33/255.0, blue: 33/255.0, alpha: 1)
private let profileImageView: UIImageView = {
let iv = UIImageView()
iv.contentMode = .scaleAspectFill
iv.clipsToBounds = true
iv.isUserInteractionEnabled = true
iv.image = #imageLiteral(resourceName: "venom-7")
return iv
}()
init(with menuItems: [MenuOptions]) {
self.menuItems = menuItems
super.init(nibName: nil, bundle: nil)
tableView.register(UITableViewCell.self, forCellReuseIdentifier: "cell")
}
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
override func viewDidLoad() {
super.viewDidLoad()
view.addSubview(profileImageView)
profileImageView.anchor(top: view.topAnchor)
profileImageView.setDimensions(height: 130, width: 130)
profileImageView.layer.cornerRadius = 130/2
profileImageView.centerX(inView: view)
tableView.backgroundColor = darkColour
tableView.register(UITableViewCell.self, forCellReuseIdentifier: "cell")
}
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return menuItems.count
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath)
cell.textLabel?.textColor = .white
cell.textLabel?.text = menuItems[indexPath.row].rawValue
cell.backgroundColor = darkColour
cell.imageView?.image = UIImage(systemName: MenuOptions.allCases[indexPath.row].imageName)
cell.imageView?.tintColor = .white
return cell
}
override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
tableView.deselectRow(at: indexPath, animated: true )
let selectedItem = menuItems[indexPath.row]
delegate?.didSelectMenuItem(named: selectedItem)
}
}
Any advice how I could properly anchor the list items to be below the image would be greatly appreciated!
It seems like you're using UITableViewController and it doesn't explicitly add subviews as UIViewCroller. Your must conform ViewController to UIViewController.
After that initialize your UITableView
lazy var tableView: UITableView {
let tableView = UITableView()
tableView.translatesAutoresizingMaskIntoConstraints = false
return tableView
}
and in viewDidLoad() write
view.addSubview(tableView)
then create a function
func setupViews() {
NSLayoutConstraint.activate([
profileImageView.topAnchor.constraint(equalTo: view.topAnchor, constant: 50),
profileImageView.heightAnchor.constraint(equalToConstant: 100),
profileImageView.widthAnchor.constraint(equalTo: profileImageView.heightAnchor, multiplier: 1.0),
profileImageView.centerYAnchor.constraint(equalTo: view.centerYAnchor),
tableView.topAnchor.constraint(equalTo: profileImageView.bottomAnchor, constant: 20),
tableView.leadingAnchor.constraint(equalTo: self.view.leadingAnchor),
tableView.trailingAnchor.constraint(equalTo: self.view.trailingAnchor),
tableView.bottomAnchor.constraint(equalTo: self.view.bottomAnchor)
])
}
and call the setupViews() in viewDidLoad
From what I understand, instead of using UITableviewController you should use a UIViewController and add a UITableView in it then set the constraints.
class MenuViewController: UITableViewController
Instead use
class MenuViewController: UIViewController {
private lazy var tableView: UITableView = {
...
}
}
Set the constraints now and subview. I think that would solve the issue
UPD Resolved - see edited question below
Trying to add a custom view (button, to be more specific) to a custom subclass of UITableViewCell but unable to see any layout results on iOS 10.1 on the device. Did not see any changes on the layout, and tried to just fill the cell with a custom view with the red background but failed to achieve this result as well.
import UIKit
class Save: UITableViewCell {
let containerView: UIView = {
let view = UIView()
view.translatesAutoresizingMaskIntoConstraints = false
view.backgroundColor = .red
return view
}()
override init(style: UITableViewCellStyle, reuseIdentifier: String?) {
super.init(style: style, reuseIdentifier: reuseIdentifier)
setupViews()
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
func setupViews() {
self.translatesAutoresizingMaskIntoConstraints = false
addSubview(containerView)
containerView.leadingAnchor.constraint(equalTo: leadingAnchor).isActive = true
containerView.trailingAnchor.constraint(equalTo: trailingAnchor).isActive = true
containerView.topAnchor.constraint(equalTo: topAnchor).isActive = true
containerView.bottomAnchor.constraint(equalTo: bottomAnchor).isActive = true
}
}
What I tried besides that: using plain addSubiew and constraint to the self anchors of the cell, and add to contentView in tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) but both approaches did nothing, the cell appears but it is empty.
UPD
attaching the TableView initiation code for the reference
class SettingsViewController: UIViewController, UITableViewDataSource, UITableViewDelegate {
let settings = [
"setting1",
"setting2",
"setting3",
"setting4",
"setting5",
"setting6",
"setting7"
]
let overlay: UIView = {
var view = UIView()
view.translatesAutoresizingMaskIntoConstraints = false
view.backgroundColor = .gray
view.alpha = 0.3
view.isHidden = true
return view
}()
let tableView: UITableView = {
let tableView = UITableView(frame: .zero, style: .grouped)
tableView.translatesAutoresizingMaskIntoConstraints = false
tableView.register(UITableViewCell.self, forCellReuseIdentifier: "commonCell")
tableView.register(Save.self, forCellReuseIdentifier: "btnCell")
tableView.register(Switcher.self, forCellReuseIdentifier: "switcherCell")
tableView.headerView(forSection: 0)?.textLabel?.text = "settings of app"
tableView.tableFooterView = UIView()
tableView.rowHeight = UITableViewAutomaticDimension
tableView.estimatedRowHeight = UITableViewAutomaticDimension
tableView.allowsSelection = false
return tableView
}()
override func viewDidLoad() {
super.viewDidLoad()
setupViews()
}
func setupViews() {
view.backgroundColor = .white
view.addSubview(tableView)
tableView.dataSource = self
tableView.delegate = self
tableView.topAnchor.constraint(equalTo: view.topAnchor).isActive = true
tableView.bottomAnchor.constraint(equalTo: view.bottomAnchor).isActive = true
tableView.leadingAnchor.constraint(equalTo: view.leadingAnchor).isActive = true
tableView.trailingAnchor.constraint(equalTo: view.trailingAnchor).isActive = true
}
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(true)
tabBarController?.navigationItem.rightBarButtonItems = []
tabBarController?.navigationItem.title = "settings"
}
func numberOfSections(in tableView: UITableView) -> Int {
return 1
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return settings.count
}
func tableView(_ tableView: UITableView, titleForHeaderInSection section: Int) -> String? {
return "settings"
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
var cell = tableView.dequeueReusableCell(withIdentifier: "commonCell", for: indexPath)
cell.textLabel?.text = settings[indexPath.row]
if(indexPath.row == 6) {
cell.textLabel?.text = ""
cell = tableView.dequeueReusableCell(withIdentifier: "btnCell", for: indexPath)
}
return cell
}
}
RESOLVED
in addition to Sh_Khan answer, it was required to set
tableView.rowHeight = UITableViewAutomaticDimension
tableView.estimatedRowHeight = 65
on the table
It doesn't look like it's anything wrong with the code in your cell class in my eyes. Can you please add your tableviewcode?
You should either implement
heightForRowAt
Or add
containerView.heightAnchor.constraint(equalToConstant:200).isActive = true
Also add any subview to contentView
contentView.addSubview(containerView)
NSLayoutConstraint.activate([
containerView.leadingAnchor.constraint(equalTo: contentView.leadingAnchor),
containerView.trailingAnchor.constraint(equalTo: contentView.trailingAnchor),
containerView.topAnchor.constraint(equalTo: contentView.topAnchor),
containerView.bottomAnchor.constraint(equalTo: contentView.bottomAnchor),
containerView.heightAnchor.constraint(equalToConstant:200)
])
I've configured a test playground with a UITableView and an instance of UIStackView as its header.
The stackView contains 10 UILabels.
The problem is that after calling stackView.sizeToFit() the stackView doesn't resize itself to fit all the labels and its size is zero.
I have to manually set the size of the UIStackView to fix this issue, which defeats the purpose of the UIStackView.
Here is the code of the test Xcode Playground, so you could reproduce it in your environment:
//: A UIKit based Playground for presenting user interface
import UIKit
import PlaygroundSupport
class TestTableViewController: UITableViewController {
private lazy var searchController = UISearchController(searchResultsController: nil)
private lazy var stackView: UIStackView = {
let s = UIStackView()
s.axis = .vertical
for i in 0...10 {
let l = UILabel()
l.text = "text \(i)"
s.addArrangedSubview(l)
}
return s
}()
override func viewDidLoad() {
super.viewDidLoad()
tableView.register(UITableViewCell.self, forCellReuseIdentifier: "reuseIdentifier")
configureTableView()
configureSearchController()
}
private func configureTableView() {
tableView.tableHeaderView = stackView
stackView.sizeToFit()
tableView.tableHeaderView?.sizeToFit() // Doesn't work!!!!!!!
tableView.tableHeaderView?.frame.size = CGSize(width: 9, height: 100)
}
private func configureSearchController() {
// searchController.searchResultsUpdater = self
searchController.dimsBackgroundDuringPresentation = false
searchController.searchBar.placeholder = NSLocalizedString("Choose template",
comment: "Choose template")
}
// MARK: - Table view data source
override func numberOfSections(in tableView: UITableView) -> Int {
// #warning Incomplete implementation, return the number of sections
return 2
}
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
// #warning Incomplete implementation, return the number of rows
return 7
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "reuseIdentifier", for: indexPath)
cell.textLabel?.text = "\(indexPath.row)"
return cell
}
}
let nc = UINavigationController(rootViewController: TestTableViewController())
// Present the view controller in the Live View window
PlaygroundPage.current.liveView = nc
Setting size manually achieves the desired result:
private func configureTableView() {
tableView.tableHeaderView = stackView
tableView.tableHeaderView?.frame.size = CGSize(width: 0, height: 400)
}
Table header views need a little extra help... This may work for you.
private func configureTableView() {
tableView.tableHeaderView = stackView
sizeHeaderToFit(tableView: tableView)
}
private func sizeHeaderToFit(tableView: UITableView) {
if let headerView = tableView.tableHeaderView {
let height = headerView.systemLayoutSizeFitting(UIView.layoutFittingCompressedSize).height
var frame = headerView.frame
frame.size.height = height
headerView.frame = frame
tableView.tableHeaderView = headerView
headerView.setNeedsLayout()
headerView.layoutIfNeeded()
}
}
I have a UIViewController with a navigation bar and a tab bar. Other than that, the whole screen is made up of a UITableView.
I have a large tableHeaderView that has the same background color as the navbar.
When I drag the content up (scrolling down) everything looks fine.
But if I drag it up, there is an ugly disconnection between the navigation bar and the header view.
Is there any way I could anchor it to the top when dragging down, while allowing it to scroll when dragging up?
You can try creating a view and placing it behind the tableView, as the table view scrolls, the height of the view is updated.
import UIKit
class ViewController: UIViewController, UITableViewDataSource, UITableViewDelegate {
lazy var tableView : UITableView = {
let tableView = UITableView(frame: .zero, style: .plain)
tableView.dataSource = self
tableView.delegate = self
return tableView
}()
let backView : UIView = {
let view = UIView()
view.backgroundColor = .red
return view
}()
var backViewHeight : NSLayoutConstraint?
override func viewDidLoad() {
super.viewDidLoad()
self.title = "ViewController"
self.view.addSubview(backView)
backView.translatesAutoresizingMaskIntoConstraints = false
backView.topAnchor.constraint(equalTo: self.view.safeAreaLayoutGuide.topAnchor).isActive = true
backView.leadingAnchor.constraint(equalTo: self.view.leadingAnchor).isActive = true
backView.trailingAnchor.constraint(equalTo: self.view.trailingAnchor).isActive = true
backViewHeight = backView.heightAnchor.constraint(equalToConstant: 0)
backViewHeight?.isActive = true
self.view.addSubview(tableView)
tableView.translatesAutoresizingMaskIntoConstraints = false
tableView.topAnchor.constraint(equalTo: self.view.safeAreaLayoutGuide.topAnchor).isActive = true
tableView.leadingAnchor.constraint(equalTo: self.view.leadingAnchor).isActive = true
tableView.bottomAnchor.constraint(equalTo: self.view.bottomAnchor).isActive = true
tableView.trailingAnchor.constraint(equalTo: self.view.trailingAnchor).isActive = true
tableView.register(Cell.self, forCellReuseIdentifier: "cell")
tableView.register(Header.self, forHeaderFooterViewReuseIdentifier: "header")
tableView.backgroundColor = .clear
self.navigationController?.navigationBar.barTintColor = .red
self.navigationController?.navigationBar.isTranslucent = false
self.navigationController?.navigationBar.setValue(true, forKey: "hidesShadow")
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return 3
}
func scrollViewDidScroll(_ scrollView: UIScrollView) {
if scrollView.contentOffset.y < 0 {
backViewHeight?.constant = -scrollView.contentOffset.y
}
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath)
return cell
}
func tableView(_ tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? {
let header = tableView.dequeueReusableHeaderFooterView(withIdentifier: "header")
header?.contentView.backgroundColor = .red
let headerLabel = UILabel(frame: CGRect(x: 0, y: 0, width: tableView.bounds.size.width, height: 100))
headerLabel.textAlignment = .center
headerLabel.text = "Header"
header?.addSubview(headerLabel)
return header
}
func tableView(_ tableView: UITableView, heightForHeaderInSection section: Int) -> CGFloat {
return 100
}
func tableView(_ tableView: UITableView, viewForFooterInSection section: Int) -> UIView? {
let view = UIView()
view.backgroundColor = .white
return view
}
}
class Cell: UITableViewCell {
let label : UILabel = {
let label = UILabel()
label.text = "One Label"
return label
}()
override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) {
super.init(style: style, reuseIdentifier: reuseIdentifier)
self.backgroundColor = .clear
setupViews()
}
func setupViews() {
self.backgroundColor = .white
self.addSubview(label)
label.frame = self.frame
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
}
class Header : UITableViewHeaderFooterView {
override init(reuseIdentifier: String?) {
super.init(reuseIdentifier: reuseIdentifier)
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
}
If you copy paste this code in an empty project you can have a look at the behavior. Don't forget to embed the ViewController in a NavigationController. Hope it helps
1) If an unwanted white space on the top of tableview is permanent and the constraints are correct this is the solution.
the scroll view insets adjusted automatically if you disable it should remove it
if #available(iOS 11.0, *) {
tableView.contentInsetAdjustmentBehavior = .never
} else {
automaticallyAdjustsScrollViewInsets = false
}
2) if u just have it when u pull down and it goes back to its normal state. It means is that the tableview bouncing is enabled and that is normal behaviour according to iOS documentation:
If the value of this property is true, the scroll view bounces when it encounters a boundary of the content. Bouncing visually indicates that scrolling has reached an edge of the content. If the value is false, scrolling stops immediately at the content boundary without bouncing. The default value is true.
you can uncheck the bouncing from the tableview in your storyboard or xib file. Or u can use this snippet:
tableView.bounces = false
tableView.alwaysBounceVertical = false
Note: that is not recommended to disable the scroll bouncing since it would make things feel very unnatural for iOS.
and also if you want to use pull to refresh it will not work.
So finally if u choose to not disable it you will have to change the background color of the parent of your tableview and it will solve it.
I hope that makes sense!
I'm creating a scrollable view that is the checkout section of a shopping cart.
This is the view layout
It's a scrollable view that has a UIView inside, whose content size should adjust itself depending on the size of each table view within, each table view inside the UIView should adjust it's height to it's content size which would vary depending on the number of baskets and products. (Please note that what I want is to adjust the size of the entire tableView not just one of it's cells).
I checked this answer Change UITableViewHeight Dynamically and it offers some suggestions on how to make my UITableViews auto-sizable, but I need both the UIView and the TableViews inside to be dynamically sizeable.
Any help is greatly appreciated.
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
}
}