UITableViewAutomaticDimension的效果与预期不符。Swift

3

阅读了Ray Wenderlich的“自适应表视图单元格”指南以及这个问题和其中的答案后,我决定向大家寻求帮助。

有一个通过编程创建的单元格:

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

表视图控制器在委托方法中使用UITableViewAutomaticDimension:
extension NotesTableViewController {
override func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
    return UITableViewAutomaticDimension
}

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

结果是,虽然最长的标题被完全显示出来,但单元格的高度仍与所有其他单元格的高度相同。

enter image description here

一些更新!

我已经尝试在viewDidLoad()中添加以下代码:

tableView.rowHeight = 44
tableView.estimatedRowHeight = UITableViewAutomaticDimension

开启委托方法和禁用委托方法的结果是一样的 :(


在viewDidLoad()中尝试这个:tableView.estimatedRowHeight = 50 - Ali Moazenzadeh
我觉得附上的截图是来自模拟器,请在真实设备上进行确认。 - guru
不幸的是,在实际设备中,结果也是相同的。 - Yuri Ivashin
5个回答

6
我建议不要使用Delegate方法来满足您的需求。
只需尝试在viewDidLoad中设置此项即可:
self.tableView.rowHeight = UITableViewAutomaticDimension;
// set estimatedRowHeight to whatever is the fallBack rowHeight
self.tableView.estimatedRowHeight = 44.0;

这对我总是有效的。如果有帮助,请告诉我 :)

@YuriIvashin 如果这不起作用,你应该更深入地查看你的约束条件。单元格需要能够毫无疑问地计算出单元格的高度。 - Teetz
限制条件尽可能简单易懂。尝试更改顶部和底部约束的优先级,但结果仍然相同。 - Yuri Ivashin
@YuriIvashin 你看过这里了吗?https://stackoverflow.com/questions/27288507/change-nslayoutconstraint-constant-not-working-in-layoutsubviews - Teetz
如果你想让我帮助进一步展示它,请在你的问题中展示出来。听起来你把它放在了TableViewController中,但我猜你应该把它放在你的TableViewCell中。 - Teetz
@YuriIvashin 对不起,你是对的。无论如何:在添加子视图后,您是否尝试将layoutSubviews中的代码放置在configure中?(我认为layoutSubviews在添加子视图本身之前被触发) - Teetz
显示剩余3条评论

5

你做了一些错误的事情,但主要问题在于你使用了greaterThanOrEqualTo:

相反,应该使用:

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

此外,您当前的代码每次设置文本时都会将一个新标签添加为子视图。由于单元格是可重用的,因此只有在创建单元格时才需要添加标签。
接下来,表格的正确属性为:
    tableView.rowHeight = UITableViewAutomaticDimension
    tableView.estimatedRowHeight = 44

将这两行代码放在您的表视图控制器的viewDidLoad()中,不要实现heightForRowAtestimatedHeightForRowAt函数。您可以完全删除您的extension
最后,您只需要设置一次约束。绝对不是layoutSubviews()中。
以下是完整示例:
//
//  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
    }

}

结果:

这里输入图片描述


该内容展示了一张图片,暂无更多说明。

非常感谢您! - Yuri Ivashin
据我所知,我出错的主要原因是使用了layoutSubviews()方法? - Yuri Ivashin
1
不,其实没有主要的错误...你的约束条件是错的,你添加子视图的方式也是错的,而且你对.rowHeight.estimatedRowHeight的理解也是错的。(抱歉,不是故意说错、错、错的...) - DonMag
没问题!所以...只是有很多错误导致了这样意料之外的结果。 - Yuri Ivashin

0

请更新以下行:

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

至:

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

在viewDidLoad中添加以下内容:
self.tableView.rowHeight = UITableViewAutomaticDimension;
self.tableView.estimatedRowHeight = 44.0;

0

以下步骤可能会解决您的问题:

1)为单元格中的UILabel设置顶部、底部、前导和尾随约束,如下所示: enter image description here

2)配置tableview:

self.tableView.rowHeight = UITableViewAutomaticDimension;
self.tableView.estimatedRowHeight = 44.0;

单元格是通过编程创建的。 - Yuri Ivashin
@YuriIvashin 你是否也通过编程方式添加了所有单元格标签的约束条件? - Dogan Altinbas

0
在Swift 5中:
func configureTableView() {
        myTableView.rowHeight =  UITableView.automaticDimension
        myTableView.estimatedRowHeight = 44
    }

请注意,如果.estimatedRowHeight不正确,Swift会为您计算。最后,在viewDidLoad()中调用此方法。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接