'How to make a dynamic change in the height of the ScrollView on which the TableView is added? Swift

Friends, I need help, I spent 2 days on solving this issue. I need to make my ScrollView dynamically change its height based on the amount of text I add to the tableView. The problem is that if I don't strictly set the scroll.contentSize.height height, then the ability to scroll the screen is disabled.

    private let scrollView: UIScrollView = {
        let scroll = UIScrollView()
        scroll.contentSize.height = 4000
        scroll.backgroundColor = UIColor.white
        scroll.translatesAutoresizingMaskIntoConstraints = false
        return scroll
    }()
func setConstraints() {
        
        NSLayoutConstraint.activate([
            scrollView.topAnchor.constraint(equalTo: view.safeAreaLayoutGuide.topAnchor),
            scrollView.bottomAnchor.constraint(equalTo: view.bottomAnchor),
            scrollView.leadingAnchor.constraint(equalTo: view.leadingAnchor),
            scrollView.trailingAnchor.constraint(equalTo: view.trailingAnchor)
        ])
        
        NSLayoutConstraint.activate([
            headLabel.centerXAnchor.constraint(equalTo: scrollView.centerXAnchor),
            headLabel.topAnchor.constraint(equalTo: scrollView.bottomAnchor, constant: 45)
        ])
        
        NSLayoutConstraint.activate([
            ellipseBabyImage.topAnchor.constraint(equalTo: stackViewName.bottomAnchor, constant: 75),
            ellipseBabyImage.centerXAnchor.constraint(equalTo: scrollView.centerXAnchor),
            ellipseBabyImage.heightAnchor.constraint(equalToConstant: 131.3),
            ellipseBabyImage.widthAnchor.constraint(equalToConstant: 145)
        ])
        
        NSLayoutConstraint.activate([
            goButton.centerXAnchor.constraint(equalTo: view.centerXAnchor),
            goButton.bottomAnchor.constraint(equalTo: view.bottomAnchor, constant: -40),
            goButton.leadingAnchor.constraint(equalTo: view.leadingAnchor,constant: 20),
            goButton.trailingAnchor.constraint(equalTo: view.trailingAnchor,constant: -20),
            goButton.heightAnchor.constraint(equalToConstant: 48)
        ])
        
        NSLayoutConstraint.activate([
            characterLabel.topAnchor.constraint(equalTo: ellipseBabyImage.bottomAnchor, constant: 68.35),
            characterLabel.centerXAnchor.constraint(equalTo: scrollView.centerXAnchor)
        ])
        
        NSLayoutConstraint.activate([
            stackViewName.centerXAnchor.constraint(equalTo: scrollView.centerXAnchor),
            stackViewName.topAnchor.constraint(equalTo: headLabel.topAnchor,constant: 44),
        ])
        
        NSLayoutConstraint.activate([
            leftBlockStack.topAnchor.constraint(equalTo: fullNameLabel.topAnchor, constant: 60),
            leftBlockStack.leftAnchor.constraint(equalTo: view.leftAnchor,constant: 28),
            leftBlockStack.rightAnchor.constraint(equalTo: ellipseBabyImage.leftAnchor,constant: -10)
        ])
        
        NSLayoutConstraint.activate([
            rightBlockStack.topAnchor.constraint(equalTo: fullNameLabel.topAnchor, constant: 60),
            rightBlockStack.rightAnchor.constraint(equalTo: view.rightAnchor, constant: -28),
            rightBlockStack.leftAnchor.constraint(equalTo: ellipseBabyImage.rightAnchor,constant: 10)
        ])
        
        NSLayoutConstraint.activate([
            arrayStackCharacteristicOne.topAnchor.constraint(equalTo: characterLabel.bottomAnchor,constant: 16),
            arrayStackCharacteristicOne.centerXAnchor.constraint(equalTo: view.centerXAnchor),
            arrayStackCharacteristicOne.leftAnchor.constraint(equalTo: scrollView.leftAnchor,constant: 22),
            healthProgressView.heightAnchor.constraint(equalToConstant: 5),
            healthProgressView.widthAnchor.constraint(equalToConstant: 90),
            willpowerProgressView.heightAnchor.constraint(equalToConstant: 5),
            willpowerProgressView.widthAnchor.constraint(equalToConstant: 90),
            luckProgressView.heightAnchor.constraint(equalToConstant: 5),
            luckProgressView.widthAnchor.constraint(equalToConstant: 90),
        ])
        
        NSLayoutConstraint.activate([
            arrayStackCharacteristicTwo.topAnchor.constraint(equalTo: arrayStackCharacteristicOne.bottomAnchor,constant: 16),
            arrayStackCharacteristicTwo.centerXAnchor.constraint(equalTo: view.centerXAnchor),
            arrayStackCharacteristicTwo.leftAnchor.constraint(equalTo: scrollView.leftAnchor,constant: 22),
            talentProgressView.heightAnchor.constraint(equalToConstant: 5),
            talentProgressView.widthAnchor.constraint(equalToConstant: 90),
            successProgressView.heightAnchor.constraint(equalToConstant: 5),
            successProgressView.widthAnchor.constraint(equalToConstant: 90),
            creationProgressView.heightAnchor.constraint(equalToConstant: 5),
            creationProgressView.widthAnchor.constraint(equalToConstant: 90),
        ])
        
        NSLayoutConstraint.activate([
            descriptionView.topAnchor.constraint(equalTo: arrayStackCharacteristicTwo.topAnchor, constant: 50),
            descriptionView.leadingAnchor.constraint(equalTo: view.leadingAnchor, constant: 10),
            descriptionView.trailingAnchor.constraint(equalTo: view.trailingAnchor, constant: -10),
            descriptionView.bottomAnchor.constraint(equalTo: view.bottomAnchor,constant: 0),
        ])
class DescriptionView: UIView {
    
    private let characteristicModel = CharacteristicModel()
    
    private let descriptionIdentifier = "CELL"
    
    private let tableView: UITableView = {
        let tableView = UITableView(frame: .zero, style: .grouped)
        tableView.backgroundColor = .none
        tableView.bounces = false
        tableView.separatorStyle = .none
        tableView.showsVerticalScrollIndicator = false
        tableView.isScrollEnabled = false
        tableView.translatesAutoresizingMaskIntoConstraints = false
        return tableView
    }()
    
    override init(frame: CGRect) {
        super.init(frame: frame)
        
        setDelegates()
        setupViews()
        setupConstraints()
        
        tableView.sizeToFit()
        tableView.register(DescriptionTableViewCell.self, forCellReuseIdentifier: "CELL")
    }
    
    required init?(coder: NSCoder) {
        fatalError()
    }
    
    private func setDelegates() {
        
        tableView.delegate = self
        tableView.dataSource = self
    }
    
    private func setupViews() {
        
        addSubview(tableView)
        translatesAutoresizingMaskIntoConstraints = false
    }
    
}

//MARK: - UI TableViewDataSource

extension DescriptionView: UITableViewDataSource {
    
    func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        characteristicModel.title.count
        
    }
    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        let cell = tableView.dequeueReusableCell(withIdentifier: "CELL",for: indexPath) as! DescriptionTableViewCell
        
        let descriptionTitle = characteristicModel.title[indexPath.row]
        let descriptionText = characteristicModel.description[indexPath.row]
        
        var content = cell.defaultContentConfiguration()
        content.textProperties.color = UIColor(red: 0.729, green: 0.443, blue: 0.443, alpha: 1)
        content.textProperties.alignment = .center
        content.textProperties.font = UIFont(name: "Lato-SemiBold", size: 22) ?? .systemFont(ofSize: 22)
        content.text = descriptionTitle

        content.secondaryText = descriptionText
        content.secondaryTextProperties.font = UIFont(name: "Lato-SemiBold", size: 16) ?? .systemFont(ofSize: 16)
        content.secondaryTextProperties.alignment = .justified
        
        cell.contentConfiguration = content
        return cell
    }
}

extension DescriptionView {
    
    private func setupConstraints() {
        NSLayoutConstraint.activate([
            tableView.topAnchor.constraint(equalTo: topAnchor,constant: 5),
            tableView.leadingAnchor.constraint(equalTo: leadingAnchor,constant: 5),
            tableView.trailingAnchor.constraint(equalTo: trailingAnchor,constant: -5),
            tableView.bottomAnchor.constraint(equalTo: bottomAnchor,constant: -5)
        ])
    }
}

enter image description here

enter image description here

enter image description here

enter image description here

enter image description here

I tried to use different approaches that I found on the Internet, but unfortunately I could not solve it. Either scroll is disabled for me, or the scroll width does not change automatically.

The screenshot shows that I use a tableView for the text that will be automatically added from the API, everything else is uiScrollView. tableView should have scroll disabled and scrollView should scroll to the end of the text The application should look like this.



Solution 1:[1]

Set your scrollview and tableview height to 0 and try adding this to your viewcontroller. you can update the height of the scrollview through viewDidLayoutSubviews.

override func viewDidLayoutSubviews() {
    DispatchQueue.main.async {
        self.scrollView.contentSize.height = self.descriptionView.tableView.contentSize.height + otherViews.frame.height
    }
}

you can also add an observer to the tableview whenever it updates its contentsize

override func viewDidLoad() {
    descriptionView.tableView.addObserver(self, forKeyPath: "contentSize", options: .new, context: nil)
}

override func observeValue(forKeyPath keyPath: String?, of object: Any?, change: [NSKeyValueChangeKey : Any]?, context: UnsafeMutableRawPointer?) {
    if let obj = object as? UITableView {
        if obj == descriptionView.tableView && keyPath == "contentSize" {
            if let newSize = change?[.newKey] as? CGSize {
                descriptionView.tableViewHeightConstraint.constant = newSize.height
                view.layoutIfNeeded()
            }
        }
    }
}

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 Nazca Elroux