UITableViewAutomaticDimension works not as expecte

2019-08-20 05:07发布

After reading Ray Wenderlich guide for "Self-sizing Table View Cells" as well as this question and answers to it, I've decided to ask all of you for a help.

Have a programmically created cell:

import UIKit

class NotesCell: UITableViewCell {
lazy private var cellCaption: UILabel = {
    let label = UILabel()

    label.translatesAutoresizingMaskIntoConstraints = false
    label.font = UIFont.systemFont(ofSize: 20, weight: UIFont.Weight.medium)
    label.numberOfLines = 0
    label.lineBreakMode = .byWordWrapping

    return label
}()

func configure(with note: NotesModel) {
    cellCaption.text = note.name

    contentView.addSubview(cellCaption)
}

override func layoutSubviews() {
    super.layoutSubviews()

    NSLayoutConstraint.activate([
        cellCaption.topAnchor.constraint(equalTo: contentView.topAnchor, constant: 8),
        cellCaption.leadingAnchor.constraint(equalTo: contentView.leadingAnchor, constant: 8),
        cellCaption.trailingAnchor.constraint(equalTo: contentView.trailingAnchor, constant: -8),
//            cellCaption.bottomAnchor.constraint(equalTo: contentView.bottomAnchor, constant: -8),
cellCaption.bottomAnchor.constraint(greaterThanOrEqualTo: contentView.bottomAnchor, constant: -8)
            ])

//        cellCaption.sizeToFit()
//        cellCaption.layoutIfNeeded()
}
}

The table view controller uses UITableViewAutomaticDimension in the delegate methods:

extension NotesTableViewController {
override func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
    return UITableViewAutomaticDimension
}

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

}

As a result, the longest caption is indicated fully, but the cell anyway has the same height as all other.

enter image description here

Some update!

I've already tried to put into viewDidLoad() following code:

tableView.rowHeight = 44
tableView.estimatedRowHeight = UITableViewAutomaticDimension

with enabling delegate methods and disabling them as well. The result is the same :(

5条回答
家丑人穷心不美
2楼-- · 2019-08-20 05:24

I would recommend not to use the Delegate-Methods for your needs.

Just try setting this in your viewDidLoad:

self.tableView.rowHeight = UITableViewAutomaticDimension;
// set estimatedRowHeight to whatever is the fallBack rowHeight
self.tableView.estimatedRowHeight = 44.0;

This always works for me. Let me know if it helps :)

查看更多
男人必须洒脱
3楼-- · 2019-08-20 05:26

Update the following line:

cellCaption.bottomAnchor.constraint(greaterThanOrEqualTo: contentView.bottomAnchor, constant: -8)
            ])

to:

cellCaption.bottomAnchor.constraint(equalTo: contentView.bottomAnchor, constant: -8)
            ])

and add following in viewDidLoad:

self.tableView.rowHeight = UITableViewAutomaticDimension;
self.tableView.estimatedRowHeight = 44.0;
查看更多
Rolldiameter
4楼-- · 2019-08-20 05:27

In Swift 5:

func configureTableView() {
        myTableView.rowHeight =  UITableView.automaticDimension
        myTableView.estimatedRowHeight = 44
    }

Keep in mind that if the .estimatedRowHeight is not correct, Swift will do the math for you. Finally, call this method in the viewDidLoad()

查看更多
走好不送
5楼-- · 2019-08-20 05:28

Following steps may solve your problem:

1) set top, bottom, leading and trailing constraints for the UILabel in the cell like below: enter image description here

2) configure tableview:

self.tableView.rowHeight = UITableViewAutomaticDimension;
self.tableView.estimatedRowHeight = 44.0;
查看更多
戒情不戒烟
6楼-- · 2019-08-20 05:43

You're doing a number of things wrong, but the main point is your use of greaterThanOrEqualTo:.

Instead, it should be:

cellCaption.bottomAnchor.constraint(equalTo: contentView.bottomAnchor, constant: -8),

Also, your current code is adding a new label as a subview every time you set the text. Cells are reused, so you only want to add the label when the cell is created.

Next, the correct properties for the table are:

    tableView.rowHeight = UITableViewAutomaticDimension
    tableView.estimatedRowHeight = 44

Put those two lines in viewDidLoad() of your table view controller, and do not implement heightForRowAt or estimatedHeightForRowAt functions. You can delete your extension entirely.

And finally, you only need to set the constraints once. Definitely NOT in layoutSubviews().

Here's a full example:

//
//  NotesTableViewController.swift
//
//  Created by Don Mag on 8/29/18.
//

import UIKit

class NotesModel: NSObject {
    var name: String = ""
}

class NotesCell: UITableViewCell {
    lazy private var cellCaption: UILabel = {
        let label = UILabel()

        label.translatesAutoresizingMaskIntoConstraints = false
        label.font = UIFont.systemFont(ofSize: 20, weight: UIFont.Weight.medium)
        label.numberOfLines = 0
        label.lineBreakMode = .byWordWrapping

        return label
    }()

    func configure(with note: NotesModel) {
        cellCaption.text = note.name
    }

    override init(style: UITableViewCellStyle, reuseIdentifier: String?) {
        super.init(style: style, reuseIdentifier: reuseIdentifier)
        commonInit()
    }

    required init?(coder aDecoder: NSCoder) {
        super.init(coder: aDecoder)
        commonInit()
    }

    func commonInit() -> Void {

        contentView.addSubview(cellCaption)

        NSLayoutConstraint.activate([
            cellCaption.topAnchor.constraint(equalTo: contentView.topAnchor, constant: 8),
            cellCaption.leadingAnchor.constraint(equalTo: contentView.leadingAnchor, constant: 8),
            cellCaption.trailingAnchor.constraint(equalTo: contentView.trailingAnchor, constant: -8),
            cellCaption.bottomAnchor.constraint(equalTo: contentView.bottomAnchor, constant: -8),
            ])

    }

}

class NotesTableViewController: UITableViewController {

    override func viewDidLoad() {
        super.viewDidLoad()

        tableView.rowHeight = UITableViewAutomaticDimension
        tableView.estimatedRowHeight = 44
    }

    // MARK: - Table view data source

    override func numberOfSections(in tableView: UITableView) -> Int {
        return 1
    }

    override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        return 8
    }

    override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        let cell = tableView.dequeueReusableCell(withIdentifier: "NotesCell", for: indexPath) as! NotesCell

        let m = NotesModel()

        if indexPath.row == 3 {
            m.name = "This is a very long caption. It will demonstrate how the cell height is auto-sized when the text is long enough to wrap to multiple lines."
        } else {
            m.name = "Caption \(indexPath.row)"
        }

        cell.configure(with: m)

        return cell
    }

}

Result:

enter image description here

查看更多
登录 后发表回答