Oscar
Oscar

Reputation: 33

Dynamic height for UITableViewCell not working correctly

I'm having some height problems with my dynamic UITableViewCell (sew picture below). Some cells have the correct height and some not, and when I drag the tableView some of the cells become correct and some don't.

I'm using this code to get the cell's height to be dynamic and reloading it in viewDidAppear and viewDidLoad.

tableView.rowHeight = UITableViewAutomaticDimension
tableView.estimatedRowHeight = tableView.rowHeight

As mentioned the cells are sometimes correct and sometimes not. Is there another way to do it or am I doing something wrong? I have tried many different solutions, all mentioned here as well as other suggestions both here at StackOverflow and other sites.

enter image description here

enter image description here

I appreciate all help!

Edit!

TableView

extension ChatVC: UITableViewDelegate, UITableViewDataSource {
    func numberOfSections(in tableView: UITableView) -> Int {
        return 1
    }

    func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        return groupMessages.count
    }

    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        guard let cell = tableView.dequeueReusableCell(withIdentifier: "groupFeedCell", for: indexPath) as? GroupFeedCell else { return UITableViewCell() }

        let message = groupMessages[indexPath.row]

            DataService.instance.getUsername(forUID: message.senderId, handler: { (name) in
                cell.configureCell(name: name, content: message.content)
            })

        cell.layoutSubviews()
        cell.layoutIfNeeded()

        return cell
    }

    func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {

        return UITableViewAutomaticDimension
    }

    func tableView(_ tableView: UITableView, estimatedHeightForRowAt indexPath: IndexPath) -> CGFloat {
        return 66
    }
}

Cell

@IBOutlet weak var nameLbl: UILabel!
@IBOutlet weak var contentLbl: UILabel!

func configureCell(name: String, content: String) {
    self.nameLbl.text = name //email
    self.contentLbl.text = content
}

enter image description here

Upvotes: 1

Views: 2776

Answers (3)

Kien Tran
Kien Tran

Reputation: 101

I guess the problem is asynchronous function. So Should you try

Step 1: Create names array

var names: [String?] = Array<String>.init(repeating: nil, count: groupMessages.count)

Step 2: Replace

 DataService.instance.getUsername(forUID: message.senderId, handler: { (name) in
                cell.configureCell(name: name, content: message.content)
            })

By

 if names[indexPath.row] == nil {
            DataService.instance.getUsername(forUID: message.senderId, handler: { (name) in
                names[indexPath.row] = name

                tableView.reloadRows(at: [indexPath], with: .automatic)
            })
        } else {
            cell.configureCell(name: name, content: message.content)

        }

Upvotes: 0

Scriptable
Scriptable

Reputation: 19758

Your are facing this issue because the content of your label comes from an async function.

The cell uses its content to work out its height dynamically. When your async request returns it has already done its work and will not recalculate and resize.

You need to make these requests, cache/store the results and reload the cells as needed. Usually in chat there would only be a couple of users to load usernames for anyway. You could also try pre-loading this data before the chat is displayed.

You can quickly confirm this by creating an array of random usernames and messages (sample data) and adding that to the cell straight away.

Upvotes: 1

Shehata Gamal
Shehata Gamal

Reputation: 100541

For dynamic tableViewCell

1- Setup this 2 lines with an inital value for the row height to help autolayout drawing it (take it from current cell height in the nib file)

tableView.rowHeight = UITableViewAutomaticDimension;
tableView.estimatedRowHeight = number;

2- don't implement this function heightForRowAtIndexPath . or implement it and return this

return UITableViewDynamicHeight;

3- make sure all constraints in the cell nib file or in storyboard are hooked correctly from top to bottom.

4- in cellForRowAtIndexPath before the line retrun cell insert that

[cell layoutSubviews];
[cell layoutIfneeded];

5- Test in simulator some versions like ios 8 it's a bug also in the viewController call

[tableView LayouSubviews];

in viewdidLayoutSubViews function to re relayout again correctly

6- Make lines property of any UILabel that you want to wrap = 0 and hook it's leading and trailing constarints to superView

Upvotes: 3

Related Questions