Reputation: 187
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.
Upvotes: 0
Views: 112
Reputation: 23500
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
}
}
Upvotes: 1