自调整大小的UITableView Cell中的UILabel随机计算高度

问题描述 投票:0回答:1

我对 Swift、iOS 15 中 UITableView 中的自调整单元格大小有疑问。

我想创建一个像这样的单元格:

Expected cell

当视图渲染 80% 的单元格时,它可以正常工作。 但有时我也会有这样的事情。这就是它在视图调试器中的样子:

Cell with issue in view of debugger

如您所见,在几个单元格中,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)

    }
}

我使用的UILabel:

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

UITableView 设置:

 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
    }
swift uitableview uikit
1个回答
0
投票

相信问题在于标签宽度约束上多次使用

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

© www.soinside.com 2019 - 2024. All rights reserved.