【问题标题】:Can't reset UILabel attributedText when a UITableViewCell is reused重用 UITableViewCell 时无法重置 UILabel 属性文本
【发布时间】:2020-02-25 21:52:30
【问题描述】:

问题

我正在使用UITableView 来显示信用卡的交易列表。如果交易是拒付,我将在标签中添加删除线样式:

当该特定单元被重复使用时,就会出现问题。即使重置标签的textattributedText 属性,删除线装饰仍然存在。

下面我添加了我的代码的相关部分:

表格视图

class TimelineViewController: UIViewController {

    private lazy var tableView: UITableView = {
        let tableView = UITableView.init(frame: view.frame, style: .plain)
        tableView.translatesAutoresizingMaskIntoConstraints = false
        tableView.register(TimelineTableViewCell.self, forCellReuseIdentifier: TimelineTableViewCell.reuseIdentifier)
        tableView.dataSource = self
        tableView.delegate = self
        return tableView
    }()

    override func viewDidLoad() {
        super.viewDidLoad()
        addTableViewOnView()
        getTimeline()
    }

}

extension TimelineViewController: UITableViewDataSource {

    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        guard let cell = tableView.dequeueReusableCell(withIdentifier: TimelineTableViewCell.reuseIdentifier,
                                                       for: indexPath) as? TimelineTableViewCell else { fatalError() }
        cell.transactionData = viewModel.timeline[indexPath.row]
        return cell
    }

}

表格视图单元格

class TimelineTableViewCell: UITableViewCell {

    static let reuseIdentifier = "TimelineTableViewCell"

    var transactionData: TimelineResponseModel! {
        didSet {
            // Reset the labels
            transactionDescriptionLabel.text = nil
            transactionDescriptionLabel.attributedText = nil
            transactionValueLabel.text = nil
            transactionValueLabel.attributedText = nil

            // Fill in the values
            transactionDescriptionLabel.text = transactionData.description
            transactionValueLabel.text = Formatter.currency.string(for: transactionData.balance)

            if transactionData.isChargeback {
                let value = Formatter.currency.string(for: transactionData.balance) ?? ""
                transactionDescriptionLabel.attributedText = transactionData.description.strikedThrough()
                transactionValueLabel.attributedText = value.strikedThrough()
            }
        }
    }

    private lazy var transactionDescriptionLabel: UILabel = {
        let transactionDescriptionLabel = UILabel()
        transactionDescriptionLabel.translatesAutoresizingMaskIntoConstraints = false
        transactionDescriptionLabel.font = UIFont.preferredFont(forTextStyle: .footnote)
        transactionDescriptionLabel.adjustsFontForContentSizeCategory = true
        transactionDescriptionLabel.textColor = UIColor.activeText()
        transactionDescriptionLabel.numberOfLines = 0
        return transactionDescriptionLabel
    }()

    private lazy var transactionValueLabel: UILabel = {
        let transactionValueLabel = UILabel()
        transactionValueLabel.translatesAutoresizingMaskIntoConstraints = false
        transactionValueLabel.font = UIFont.preferredFont(forTextStyle: .caption1).bold()
        transactionValueLabel.adjustsFontForContentSizeCategory = true
        transactionValueLabel.textColor = UIColor.activeText()
        return transactionValueLabel
    }()

    override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) {
        super.init(style: style, reuseIdentifier: reuseIdentifier)
        addTransactionDescriptionLabel()
        addTransactionValueLabel()
    }

}

删除线样式

extension String {

    func strikedThrough() -> NSAttributedString {
        let strikethroughStyle = [NSAttributedString.Key.strikethroughStyle: NSUnderlineStyle.single.rawValue]
        return NSAttributedString(string: self, attributes: strikethroughStyle)
    }

}

我尝试过的

我尝试了一些方法,但没有成功:

  • 覆盖prepareForReuse 并在此处重置标签的textattributedText
  • if transactionData.isChargeback 之后创建else 以设置不带装饰的transactionDescriptionLabeltransactionValueLabel 属性文本

那么,当单元格被重复使用时,如何重置它的标签以删除我之前添加的删除线样式?

【问题讨论】:

  • 为什么要在TimelineTableViewCell 中设置表格单元格内容,而不是在TimelineViewController 中设置委托?
  • @ekrenzin 更好地封装单元格内的 UI 元素。由于我已将它们声明为private,因此可以从外部访问的唯一属性是transactionData。当我设置它时,它会更新单元格的 UI 元素。
  • 我建议尝试修改委托中的单元格 UI,看看它是否有所作为。如果不起作用,那么您的模型可能有问题,没有考虑到新的但已经布置好的单元格。好问题:)
  • @ekrenzin 在尝试您的建议时,我偶然发现了解决方案:出于某种奇怪的原因,如果我只重置attributedText,问题就不会再发生了。或者,如果我先重置attributedText,然后再重置text,问题也不会发生。根据文档,为任一属性分配新值会替换另一个属性的值,因此顺序无关紧要...也许这是UILabel 错误????
  • 我很高兴你和 Alex 一起找到了解决方案! :) 是的,这很奇怪......我过去遇到过类似的事情,这就是为什么我提到新的但已经布局的原因,我猜这里发生了类似的事情需要重置属性文本?表格单元格有时很奇怪哈哈~

标签: ios swift uitableview uikit uilabel


【解决方案1】:

Alex 的回答确实解决了我的问题,但我也发现了标签重置不起作用的原因。我会把它留在这里,以防它对某人有用。

出于某种原因,如果我只重置attributedText,它可以工作:

transactionDescriptionLabel.attributedText = nil
transactionValueLabel.attributedText = nil

或者,如果我先重置attributedText,然后重置text,它也可以:

transactionDescriptionLabel.attributedText = nil
transactionValueLabel.attributedText = nil
transactionDescriptionLabel.text = nil
transactionValueLabel.text = nil

根据UILabel 文档,为任一属性分配新值会替换另一个属性的值,因此顺序无关紧要。但显然它确实如此。

https://developer.apple.com/documentation/uikit/uilabel/1620538-text

https://developer.apple.com/documentation/uikit/uilabel/1620542-attributedtext

【讨论】:

  • 这很奇怪,但对我来说也一样!
  • 是的,很奇怪,2020 年仍然发生在我身上 :) 仅在文本解决问题之前重置属性文本。
  • iOS 中还是这样13.5
  • 感谢您的提示 - 您必须将两者都归零是对的,但首先执行属性文本实际上解决了我遇到的问题。
【解决方案2】:

您应该尝试在此处设置.attributedText 而不是使用`.text'。如果它不起作用,我会删除我的答案。

// Fill in the values
transactionDescriptionLabel.text = transactionData.description
transactionValueLabel.text = Formatter.currency.string(for: transactionData.balance)

所以,试试这个

transactionDescriptionLabel.attributedText = //
transactionValueLabel.attributedText = //

还有一件事。其实我不喜欢didSet。 我建议您创建一种方法来配置您的单元格。 这是我想告诉你的一个例子。

func configure(with transactionData: TimelineResponseModel) {
   // Reset the labels
   transactionDescriptionLabel.text = nil
   transactionDescriptionLabel.attributedText = nil
   transactionValueLabel.text = nil
   transactionValueLabel.attributedText = nil

   // Fill in the values
   transactionDescriptionLabel.text = transactionData.description
   transactionValueLabel.text = Formatter.currency.string(for: transactionData.balance)

   if transactionData.isChargeback {
      let value = Formatter.currency.string(for: transactionData.balance) ?? ""
      transactionDescriptionLabel.attributedText = transactionData.description.strikedThrough()
      transactionValueLabel.attributedText = value.strikedThrough()
   }
}

下一步。

func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
    guard let cell = tableView.dequeueReusableCell(withIdentifier: TimelineTableViewCell.reuseIdentifier,
                                                   for: indexPath) as? TimelineTableViewCell else { fatalError() }
    // Thats what I really like
    cell.configure(with: viewModel.timeline[indexPath.row])
    return cell
}

【讨论】:

  • 是的,这样就可以了!起初我没有这样做,因为如果交易不是退款,我不需要任何不同的样式,但我想我会创建一个没有任何属性的NSAttributedString
  • 很高兴为您提供帮助。所以想和大家分享一下我使用didSet的想法。我将编辑我的答案。 )
  • 感谢您的建议!使用didSet 不理想有什么特别的原因吗?我问是因为我曾经完全按照您的建议进行操作,使用 configure 方法,但决定为这个特定项目尝试 didSet 属性观察器。
  • 其实didSet没有什么特别之处,但是didSet存储了值。而不是这个 - configure 方法不存储任何东西,它就像一个 { get set }。希望我能帮助你:)
猜你喜欢
  • 2017-06-05
  • 2013-02-11
  • 2018-09-15
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-11-14
相关资源
最近更新 更多