我对 Swift、iOS 15 中 UITableView 中的自调整单元格大小有疑问。
当视图渲染 80% 的单元格时,它可以正常工作。 但有时我也会有这样的事情。这就是它在视图调试器中的样子:
如您所见,在几个单元格中,UILabel(我的代码中的nameLabel,如下)的高度正是视图所需要的。我想使用自动调整大小的单元格来支持可访问性,但在这种情况下,某些单元格占用的空间超出了其所需的空间。 更重要的是,当我向下滚动并返回顶部时,当单元格由 UI 重新渲染时,某些单元格得到修复。
此外,视图调试器向我显示错误“UITableView 的可滚动内容大小不明确”。
我尝试将下面的代码转移到UIStackView,我的意思是nameLabel和teamLabel,但是teamLabel高度的问题仍然出现。我不知道如何解决这个问题。我尝试使用 .setContentHuggingPriority,但没有太大效果。
我使用的数据是在打开视图之前下载到内存中的,因此肯定不存在视图无法计算其应该大小的情况。
当我删除 teamLabel 时,nameLabel 的高度看起来是正确的。尽管如此,调试器中仍然出现“紫色”错误。我检查了所有视图约束,单元格的每一侧都有对元素的引用。一般来说,如果我更改可访问性,单元格会正确显示,并且字体也会更大,但我不知道如何解决这个 UILabel 的问题。
如果有任何提示,我将非常感激。我完全不知道如何让它正常工作。 重要的是,有关连字符的代码不会改变任何东西 - 没有它我仍然有问题。我尝试添加“tableview.estimatedHeightRow”但没有达到预期效果
import UIKit
class RaceResultCell: UITableViewCell {
static let identifier = "RaceResultDetailsCell"
private let flagImage = FlagImageView(frame: .zero)
private let positionLabel = CellTextLabel(fontStyle: .subheadline, fontWeight: .regular, textColor: .UI.secondaryText, textAlignment: .center)
private let nameLabel = CellTextLabel(fontStyle: .body, fontWeight: .semibold, textColor: .UI.primaryText)
private let teamLabel = CellTextLabel(fontStyle: .subheadline, fontWeight: .light, textColor: .UI.secondaryText)
private let statusLabel = CellTextLabel(fontStyle: .subheadline, fontWeight: .regular, textColor: .UI.primaryText, textAlignment: .right)
private let pointsLabel = CellTextLabel(fontStyle: .subheadline, fontWeight: .regular, textColor: .UI.secondaryText, textAlignment: .center)
override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) {
super.init(style: style, reuseIdentifier: reuseIdentifier)
setupUI()
}
@available(*, unavailable)
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
func configure(with model: RaceResultDataModel) {
positionLabel.text = model.position
nameLabel.text = "\(model.driver.name) \(model.driver.surname)"
pointsLabel.text = model.points
teamLabel.text = model.constructor.name
statusLabel.text = model.time?.time ?? model.status
flagImage.image = CountryFlagProvider.shared.nationalityFlag(for: model.driver.nationality)
setupHyphenation(for: nameLabel)
setupHyphenation(for: teamLabel)
setupHyphenation(for: statusLabel)
}
private func setupHyphenation(for label: UILabel) {
label.numberOfLines = 0
label.lineBreakMode = .byWordWrapping
label.adjustsFontSizeToFitWidth = false
label.allowsDefaultTighteningForTruncation = true
if let text = label.text {
let paragraphStyle = NSMutableParagraphStyle()
paragraphStyle.hyphenationFactor = 1
let attributedString = NSAttributedString(string: text,
attributes: [.paragraphStyle: paragraphStyle])
label.attributedText = attributedString
}
}
private func setupUI() {
contentView.addSubview(positionLabel)
contentView.addSubview(flagImage)
contentView.addSubview(nameLabel)
contentView.addSubview(teamLabel)
contentView.addSubview(statusLabel)
contentView.addSubview(pointsLabel)
positionLabel.snp.makeConstraints { make in
make.leading.equalToSuperview().offset(6)
make.centerY.equalToSuperview()
make.width.greaterThanOrEqualTo(28)
}
flagImage.snp.makeConstraints { make in
make.leading.equalTo(positionLabel.snp.trailing).offset(12)
make.centerY.equalToSuperview()
make.size.equalTo(CGSize(width: 28, height: 24))
}
nameLabel.snp.makeConstraints { make in
make.top.equalToSuperview().offset(12)
make.leading.equalTo(flagImage.snp.trailing).offset(12)
make.trailing.lessThanOrEqualTo(statusLabel.snp.leading).offset(-12)
}
teamLabel.snp.makeConstraints { make in
make.top.equalTo(nameLabel.snp.bottom).offset(6)
make.leading.equalTo(flagImage.snp.trailing).offset(12)
make.trailing.lessThanOrEqualTo(statusLabel.snp.leading).offset(-12)
make.bottom.equalToSuperview().offset(-12)
}
statusLabel.snp.makeConstraints { make in
make.centerY.equalToSuperview()
make.trailing.equalTo(pointsLabel.snp.leading).offset(-12)
make.top.equalTo(nameLabel.snp.top)
make.bottom.equalTo(teamLabel.snp.bottom)
make.width.greaterThanOrEqualTo(50)
}
pointsLabel.snp.makeConstraints { make in
make.trailing.equalToSuperview().offset(-6)
make.centerY.equalToSuperview()
make.width.greaterThanOrEqualTo(28)
}
//
//
// nameLabel.setContentHuggingPriority(.defaultHigh + 1, for: .vertical)
// teamLabel.setContentHuggingPriority(.defaultHigh + 2, for: .vertical)
//
// nameLabel.setContentCompressionResistancePriority(.defaultHigh + 1, for: .vertical)
}
}
import UIKit
class CellTextLabel: UILabel {
override init(frame: CGRect) {
super.init(frame: frame)
configure()
}
@available(*, unavailable)
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
convenience init(fontStyle: UIFont.TextStyle, fontWeight: UIFont.Weight, textColor: UIColor!, textAlignment: NSTextAlignment? = nil) {
self.init(frame: .zero)
self.font = UIFont.systemFont(ofSize: UIFont.preferredFont(forTextStyle: fontStyle).pointSize, weight: fontWeight)
self.textColor = textColor
self.textAlignment = textAlignment ?? .natural
}
private func configure() {
adjustsFontForContentSizeCategory = true
minimumScaleFactor = 0.5
lineBreakMode = .byWordWrapping
numberOfLines = 0
sizeToFit()
}
}
private func setupTableView() {
view.addSubview(tableView)
tableView.delegate = self
tableView.dataSource = self
tableView.backgroundColor = UIColor.UI.background
tableView.allowsSelection = false
tableView.register(RaceResultCell.self, forCellReuseIdentifier: RaceResultCell.identifier)
tableView.isHidden = false
tableView.showsVerticalScrollIndicator = false
tableView.addSubview(tableViewHeader)
tableViewHeader.frame = CGRect(x: 0, y: 0, width: tableView.bounds.width, height: 50)
tableViewHeader.backgroundColor = UIColor.UI.background
tableView.tableHeaderView = tableViewHeader
tableViewHeader.snp.makeConstraints { make in
make.centerX.equalToSuperview()
make.left.equalToSuperview().offset(10)
make.right.equalToSuperview().offset(-10)
make.height.equalTo(50)
}
tableView.snp.makeConstraints { make in
make.top.equalTo(view.safeAreaLayoutGuide.snp.top)
make.left.right.bottom.equalToSuperview()
}
}
/// HEIGHT & CELL SETUP IN EXTENSION:
extension ResultsDetailsVC: UITableViewDelegate, UITableViewDataSource {
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
// count setup...
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
guard let cell = tableView.dequeueReusableCell(withIdentifier: RaceResultCell.identifier, for: indexPath) as? RaceResultCell else {
fatalError("Custom cell error")
}
let resultData = raceResult.results[indexPath.row]
cell.configure(with: resultData)
return cell
}
func tableView(_: UITableView, heightForRowAt _: IndexPath) -> CGFloat {
return UITableView.automaticDimension
}
我相信问题在于标签宽度约束上多次使用
greaterThanOrEqualTo
,并且自动布局在评估多行标签的高度时遇到困难,因为它们的宽度随着布局开始评估而发生变化.
试试这个:
positionLabel.snp.makeConstraints { make in
make.leading.equalToSuperview().offset(6)
make.centerY.equalToSuperview()
make.width.greaterThanOrEqualTo(28)
}
flagImage.snp.makeConstraints { make in
make.leading.equalTo(positionLabel.snp.trailing).offset(12)
make.centerY.equalToSuperview()
make.size.equalTo(CGSize(width: 28, height: 24))
}
nameLabel.snp.makeConstraints { make in
make.top.equalToSuperview().offset(12)
make.leading.equalTo(flagImage.snp.trailing).offset(12)
make.trailing.equalTo(statusLabel.snp.leading).offset(-12)
}
teamLabel.snp.makeConstraints { make in
make.top.equalTo(nameLabel.snp.bottom).offset(6)
make.leading.equalTo(flagImage.snp.trailing).offset(12)
make.trailing.equalTo(statusLabel.snp.leading).offset(-12)
make.bottom.equalToSuperview().offset(-12)
}
statusLabel.snp.makeConstraints { make in
make.centerY.equalToSuperview()
make.trailing.equalTo(pointsLabel.snp.leading).offset(-12)
make.top.equalTo(nameLabel.snp.top)
make.bottom.equalTo(teamLabel.snp.bottom)
make.width.greaterThanOrEqualTo(50)
}
pointsLabel.snp.makeConstraints { make in
make.trailing.equalToSuperview().offset(-6)
make.centerY.equalToSuperview()
make.width.greaterThanOrEqualTo(28)
}
// add these constraints to help auto-layout manage the labels
var c: NSLayoutConstraint!
c = positionLabel.widthAnchor.constraint(equalToConstant: 28.0)
c.priority = .defaultHigh
c.isActive = true
c = statusLabel.widthAnchor.constraint(equalToConstant: 50.0)
c.priority = .defaultHigh
c.isActive = true
c = pointsLabel.widthAnchor.constraint(equalToConstant: 28.0)
c.priority = .defaultHigh
c.isActive = true
我们有效地在可变宽度positionLabel
和
statusLabel
和pointsLabel
标签上提供自动布局提示。
我们还将
nameLabel
和 teamLabel
尾随约束从 lessThanOrEqualTo
更改为 equalTo
。