0

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)
        ])
    }
}

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.

General Grievance
  • 4,555
  • 31
  • 31
  • 45
Dyadichev
  • 1
  • 1
  • The problem seems to be the fact that you have a UITableView inside a UIScrollView. When you disable the scroll of the UITableView, you're not able to get to the end of it, and then you can't get to the end of the UIScrollView either. Also, instead of screen captures from your code, you should paste the code itself in the question. Do you have a preview of how this view should behave? – reisdev Mar 30 '22 at 14:19
  • Sorry for the screenshots, I've added both code and screenshots. I did not add all the code from the main controller since there are more than 600 lines of code. I edited my post and added a screenshot of how the application should look for understanding. – Dyadichev Mar 31 '22 at 09:59
  • Adding to the comment that I made about the UITableView inside the UIScrollView, this answer may help you: https://stackoverflow.com/a/46133883/9036322 – reisdev Mar 31 '22 at 20:44

1 Answers1

0

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()
            }
        }
    }
}