0

I'm creating a scrollable view that is the checkout section of a shopping cart.

This is the view layout

enter image description here

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.

Community
  • 1
  • 1
Octavio Rojas
  • 187
  • 13
  • 3
    What can't you combine all the data in the three table views into a single table view? – Jeffery Thomas Jan 18 '17 at 02:30
  • Because each one of them holds different data and they have different states. If the array containing Canastas is empty it should send a a nib with an empty cart icon and the "No products" label if Canastas isn't empty it should send a nib with the canastas cell , with Productos is the same , the last tableview is a condensed summary of the products contained in the previous tableViews. Each view has it's own functionality and the size of each one should be the size of the total number of items contained in the arrays, the scrollView size should adjust accordingly. that's why. – Octavio Rojas Jan 18 '17 at 02:34
  • @OctavioRojas; Is each tableView scrollable OR are they going to display FULL size inside of the super scrollView? – Brandon Jan 18 '17 at 02:38
  • They aren't scrollable (That's what the scrollView is for) they should just be able to resize dynamically if there is 1 cell or if there is 10 cells they should adjust their size accordingly and the scrollView should adjust too in order to be able to scroll through them all. – Octavio Rojas Jan 18 '17 at 02:39
  • You can use a single table view and split it to some sections. The `no product` label also is a cell... – t4nhpt Jan 18 '17 at 03:12
  • What if I want to use the three views? The views don't go one after another, there is more content between each one of the, also they are working already, but they are scrollable, and what I want is them to grow in size dynamically depending on their content. – Octavio Rojas Jan 18 '17 at 03:19

1 Answers1

1

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
    }
}
Brandon
  • 22,723
  • 11
  • 93
  • 186
  • Awesome, this was the answer I was looking for, Thank you very much! I don't combine them all in one table because I have the views in different places, (They aren't contiguous), if you know a way of having different sections of a same table view scattered around in different parts of the view please let me know how and I'd do it with a single scrollView instead. – Octavio Rojas Jan 18 '17 at 13:08