-2

My project use SnapKit to setup the constraint, and use tableview in stackview inner the scrollview.

First I set a scrollview for scroll the page, and then add a stackview inside the scrollview for position other view.

Second I set the tableview inside the stackview for the first view, and I set the "view.rowHeight = UITableView.automaticDimension" and "view.estimatedRowHeight = 80" in tableview declared, to automatic tableview height.

Three I use Snap Kit to set up the position, but I don't know how set the constraint for table view height?

My program is as follow:

import UIKit
import SnapKit

class ViewController: UIViewController {
    
    let rows: [[String: String]] = [
        ["avatar": "noavatar", "name": "Mary", "date": "2022-12-02 15:10"],
        ["avatar": "noavatar", "name": "Joe", "date": "2022-11-02 10:10"],
        ["avatar": "noavatar", "name": "Michael", "date": "2022-10-02 15:10"],
        ["avatar": "noavatar", "name": "John", "date": "2022-03-02 15:10"],
        ["avatar": "noavatar", "name": "Annie", "date": "2022-09-02 15:10"],
    ]
    
    var scrollView: UIScrollView = {
        let view = UIScrollView()
        
        return view
    }()
    
    let stackView: UIStackView = {
        let view = UIStackView()
        view.axis = .vertical
        view.spacing = 12
        view.alignment = .top
        return view
    }()
    
    let tableView: UITableView = {
        let view = UITableView()
        view.isScrollEnabled = false
        view.backgroundColor = UIColor.clear
        
        view.rowHeight = UITableView.automaticDimension
        view.estimatedRowHeight = 80
        
        view.register(MyCell.self, forCellReuseIdentifier: "MyCell")
                
        return view
    }()

    override func viewDidLoad() {
        super.viewDidLoad()
        
        initScrollView()
        
        tableView.delegate = self
        tableView.dataSource = self
    }

    private func initScrollView() {
        
        self.view.addSubview(scrollView)
        scrollView.snp.makeConstraints { make in
            make.top.equalToSuperview().offset(200)
            make.left.equalToSuperview().offset(20)
            make.right.equalToSuperview().offset(-20)
            make.bottom.equalToSuperview()
        }
        
        scrollView.addSubview(stackView)
        stackView.snp.makeConstraints { make in
            make.top.bottom.equalToSuperview()
            make.width.equalToSuperview()
        }

        stackView.addArrangedSubview(tableView)
        tableView.snp.makeConstraints { make in
            make.left.right.equalToSuperview()
            **make.height.equalTo(200)**
        }
    }
}

extension ViewController: UITableViewDelegate, UITableViewDataSource {
    
    func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        
        return rows.count
    }

    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {

        let cell: MyCell = tableView.dequeueReusableCell(withIdentifier: "MyCell", for: indexPath) as! MyCell
        
        let row: [String: String] = rows[indexPath.row]
        cell.update(row: row, no: indexPath.row + 1)
        
        return cell
    }
}

class MyCell: UITableViewCell {
        
    let noLbl: UILabel = {
        let view = UILabel()
        return view
    }()
    
    let avatarIV: UIImageView = {
        let view = UIImageView()
        return view
    }()
    
    let dataContainer: UIView = UIView()
    
    let nameLbl: UILabel = {
        let view = UILabel()
        return view
    }()
    
    let createdAtLbl: UILabel = {
        let view = UILabel()
        view.textColor = UIColor.black
        return view
    }()
    
    let separator: UIView = {
        let view = UIView()
        view.backgroundColor = UIColor.black
        return view
    }()
    
    override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) {
        super.init(style: style, reuseIdentifier: reuseIdentifier)
        setupView()
    }
    
    required init?(coder: NSCoder) {
        super.init(coder: coder)
        self.setupView()
    }

    override func awakeFromNib() {
        super.awakeFromNib()
        setupView()
    }
    
    private func setupView() {
        backgroundColor = UIColor.clear
        setAnchor()
    }
    
    func setAnchor() {
        
        self.contentView.addSubview(noLbl)
        noLbl.snp.makeConstraints { make in
            make.top.equalToSuperview().offset(12)
            make.left.equalToSuperview()
            make.height.equalTo(48)
        }
        
        self.contentView.addSubview(avatarIV)
        avatarIV.snp.makeConstraints { make in
            make.top.equalToSuperview().offset(12)
            make.left.equalTo(noLbl.snp.right).offset(12)
            make.width.height.equalTo(48)
            make.centerY.equalToSuperview()
        }

        self.contentView.addSubview(dataContainer)
        dataContainer.snp.makeConstraints { make in
            make.top.equalToSuperview().offset(15)
            make.left.equalTo(avatarIV.snp.right).offset(18)
            make.right.equalToSuperview()

            make.height.equalTo(42)
        }

            self.dataContainer.addSubview(nameLbl)
            nameLbl.snp.makeConstraints { make in
                make.top.equalTo(avatarIV.snp.top).offset(4)
                make.left.equalToSuperview()
            }

            self.dataContainer.addSubview(createdAtLbl)
            createdAtLbl.snp.makeConstraints { make in
                make.left.equalToSuperview()
                make.bottom.equalTo(avatarIV.snp.bottom).offset(-4)
            }

        self.contentView.addSubview(separator)
        separator.snp.makeConstraints { make in
            make.left.right.equalToSuperview()
            make.height.equalTo(1)
            make.top.equalTo(avatarIV.snp.bottom).offset(12)
        }
    }
    
    func update(row: [String: String], no: Int) {

        self.noLbl.text = "\(no)."

        self.avatarIV.image = UIImage(named: row["avatar"]!)

        self.nameLbl.text = row["name"]!
        self.createdAtLbl.text = row["date"]!
    }
}

The result is as follow:

enter image description here

We can see the table heigh is just 200, for show 3 row data, not show the complete data, but if I cancel the height constraint setup as follow:

tableView.snp.makeConstraints { make in
   make.left.right.equalToSuperview()
   //make.height.equalTo(200)
}

It show nothing in screen:

enter image description here

Please how can I set up the tableview can use auto height in scrollview and stackview?

I meet the auto height tableview many times, can't have a complete or easy solution?

General Grievance
  • 4,555
  • 31
  • 31
  • 45
ives
  • 1
  • 2

1 Answers1

0

It seems you wish the table view itself to be as tall as its content. Pin the height of the table view's frame layout guide to the height of the table view's content layout guide. Getting the priority of this constraint right can be tricky; in my app, it is one less than default high priority (aka 749), because we need the self-sizing cells to win the battle and they are sized by the compression resistance of labels and similar which is default high (750).

However, if the table view will always be as tall as its content, so that it can never scroll, then a table view was the wrong choice to begin with. Use a Stack view.

matt
  • 515,959
  • 87
  • 875
  • 1,141