Пользовательская высота ячейки UITableView неправильно управляет динамическими ограничениями c в swift - PullRequest
0 голосов
/ 29 января 2020

Я имею табличное представление и взял пользовательскую ячейку из xib, у меня есть много вещей, которые можно расширить в ячейке, когда есть медиа или большой текст, я управлял высотой программно в методе делегата и ограничении в ячейка, но иногда, когда я открываю приложение и загружаю данные, ячейка перекрывается, но когда я прокручиваю вверх-вниз, это выглядит нормально. Что я могу сделать, чтобы обновить это сразу после перезагрузки при получении данных от API?

enter image description here

Я думаю, что нет проблема в коде, так как он работает после обновления или прокрутки табличного представления. Ниже приведен метод делегата высоты:

func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {

    let newsDict = self.tableDataNewsArray[indexPath.section]
    let newsDataArray = newsDict["news"] as! [NewsBriefModel]
    let newsObject = newsDataArray[indexPath.item]

    if (self.moreExpandableArray.firstIndex(of: newsObject.newsbrief_id) != nil) {
        return 62 + 58 + 4 + 62 //(62:// label minimum height )(46: other than label caponents in cell :: 4: spacing
        // 62: more/less button view height)

    }else if (self.lessExpandableArray.firstIndex(of: newsObject.newsbrief_id) != nil) {

        var baseMoreHeight : CGFloat = newsObject.labelHeightForPostText + 58 + 4 + 62 //(46: other than label caponents in cell :: 4: spacing
        // 62: more/less button view height)

        if newsObject.numberOfImagesInPost > 0 {
            baseMoreHeight = baseMoreHeight + 110
        }
        if newsObject.numberOfDocumentInPost > 0 {
            baseMoreHeight = baseMoreHeight + CGFloat((newsObject.numberOfDocumentInPost * 45))
        }
        if newsObject.numberOfVideosInPost > 0 {
            baseMoreHeight = baseMoreHeight + CGFloat((newsObject.numberOfVideosInPost * 100))
        }

        return baseMoreHeight
    }

}

Методы ячейки, которые я вызываю в cellForRow для изменения пользовательского интерфейса:

 // MARK: CELL METHODS

    func showNormalView() {

        self.postTitleLabel.numberOfLines = 3
        self.postTitleTextView.textContainer.maximumNumberOfLines = 3
        self.postTitleTextView.textContainer.lineBreakMode = .byTruncatingTail

        self.mediaViewHeight.constant = 0
        self.documentTableViewHeight.constant = 0
        self.videoTableViewHeight.constant = 0
        self.multiMediaView.isHidden = true
        self.loadImages(urlString: [])
        self.updateConstraintsIfNeeded()
        self.setNeedsLayout()
        self.layoutIfNeeded()
    }

    func showMoreView() {

        self.postTitleLabel.numberOfLines = 3
        self.postTitleTextView.textContainer.maximumNumberOfLines = 3
        self.postTitleTextView.textContainer.lineBreakMode = .byTruncatingTail

        self.mediaViewHeight.constant = 50
        self.imageGridViewHeight.constant = 0
        self.documentTableViewHeight.constant = 0
        self.videoTableViewHeight.constant = 0
        self.loadImages(urlString: [])
        self.multiMediaView.isHidden = false
        self.updateConstraintsIfNeeded()
        self.setNeedsLayout()
        self.layoutIfNeeded()
    }

Ответы [ 2 ]

0 голосов
/ 29 января 2020

Я думаю, что лучше использовать UITableView.automaticDimension, а также убедиться, что вы установили estimatedRowHeight и, кроме того, убедиться, что последний элемент в ячейке имеет нижнее ограничение с ContentView из Cell

0 голосов
/ 29 января 2020

Я бы рекомендовал использовать UITableView.automaticDimension вместо вычисления высоты вручную и использовать шаблон делегата для обновления высоты ячейки.

Вот что я получил с этим подходом:

и пример кода:

import UIKit

struct Content {
  let author: String
  let date: String
  let views: UInt
  let recs: UInt
  let content: String
}

let longText = """
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.
"""

protocol MyCellDelegate: AnyObject {
  func contentDidChange(cell: UITableViewCell)
}

final class MyCell: UITableViewCell {
  static let reuseIdentifier = "MyCell"

  weak var delegate: MyCellDelegate?

  private var viewsCountLabel: UILabel!
  private var recsLabel: UILabel!
  private var authorLabel: UILabel!
  private var dateLabel: UILabel!
  private var contentLabel: UILabel!
  private var toggleHeightButton: UIButton!

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

  required init?(coder: NSCoder) {
    fatalError("not implemented")
  }

  override func prepareForReuse() {
    super.prepareForReuse()
    viewsCountLabel.text = nil
    recsLabel.text = nil
    authorLabel.text = nil
    dateLabel.text = nil
    contentLabel.text = nil
    contentLabel.numberOfLines = 2
  }

  public func setContent(_ content: Content) {
    viewsCountLabel.text = "Views: \(content.views)"
    recsLabel.text = "Recs: \(content.recs)"
    authorLabel.text = content.author
    dateLabel.text = content.date
    contentLabel.text = content.content
  }

  private func setupSubviews() {
    let leftStackView = createLeftStack()
    let rightStackView = createRightStack()

    let stackView = UIStackView(arrangedSubviews: [leftStackView, rightStackView])
    stackView.axis = .horizontal
    stackView.spacing = 5
    stackView.alignment = .top

    contentView.addSubview(stackView)
    stackView.translatesAutoresizingMaskIntoConstraints = false
    NSLayoutConstraint.activate([
      stackView.leadingAnchor.constraint(equalTo: contentView.leadingAnchor, constant: 10),
      stackView.trailingAnchor.constraint(equalTo: contentView.trailingAnchor, constant: -10),
      stackView.topAnchor.constraint(equalTo: contentView.topAnchor, constant: 3),
      stackView.bottomAnchor.constraint(equalTo: contentView.bottomAnchor, constant: -3)
    ])
  }

  private func createLeftStack() -> UIStackView {
    let iconView = createIconView()
    viewsCountLabel = createLabel()
    recsLabel = createLabel()
    let stackView = UIStackView(arrangedSubviews: [iconView, viewsCountLabel, recsLabel])
    stackView.axis = .vertical
    stackView.setCustomSpacing(4, after: iconView)
    stackView.alignment = .leading
    return stackView
  }

  private func createRightStack() -> UIStackView {
    authorLabel = createLabel()
    dateLabel = createLabel()
    contentLabel = UILabel()
    contentLabel.font = UIFont.systemFont(ofSize: 13, weight: .bold)
    contentLabel.contentMode = .topLeft

    toggleHeightButton = UIButton(type: .system)
    toggleHeightButton.setTitle("Toggle", for: .normal)
    toggleHeightButton.addTarget(self, action: #selector(expandDidTap), for: .touchUpInside)
    toggleHeightButton.heightAnchor.constraint(equalToConstant: 30).isActive = true

    let stackView = UIStackView(arrangedSubviews: [authorLabel, dateLabel, contentLabel, toggleHeightButton])
    stackView.axis = .vertical
    stackView.alignment = .leading
    return stackView
  }

  private func createIconView() -> UIView {
    let iconView = UIView()
    iconView.backgroundColor = .blue
    iconView.layer.cornerRadius = 4
    iconView.layer.masksToBounds = true
    let label = UILabel()
    label.font = UIFont.systemFont(ofSize: 8)
    label.numberOfLines = 2
    label.text = "Upload Icon"
    label.textAlignment = .center
    label.textColor = .white
    iconView.addSubview(label)
    label.translatesAutoresizingMaskIntoConstraints = false
    iconView.translatesAutoresizingMaskIntoConstraints = false
    NSLayoutConstraint.activate([
      label.leadingAnchor.constraint(equalTo: iconView.leadingAnchor, constant: 3),
      label.trailingAnchor.constraint(equalTo: iconView.trailingAnchor, constant: -3),
      label.topAnchor.constraint(equalTo: iconView.topAnchor, constant: 3),
      label.bottomAnchor.constraint(equalTo: iconView.bottomAnchor, constant: -3),
      iconView.heightAnchor.constraint(equalToConstant: 40),
      iconView.widthAnchor.constraint(equalToConstant: 40)
    ])
    return iconView
  }

  private func createLabel() -> UILabel {
    let label = UILabel()
    label.font = UIFont.systemFont(ofSize: 8, weight: .light)
    label.numberOfLines = 1
    return label
  }

  @objc func expandDidTap() {
    let isExpand = contentLabel.numberOfLines != 0
    if isExpand {
      contentLabel.numberOfLines = 0
    } else {
      contentLabel.numberOfLines = 2
    }
    delegate?.contentDidChange(cell: self)
  }
}

final class MyViewController: UIViewController, UITableViewDelegate, UITableViewDataSource {
  private var tableView: UITableView {
    view as! UITableView
  }

  private var data: [Content] = [] {
    didSet {
      tableView.reloadData()
    }
  }

  override func loadView() {
    let tableView = UITableView()
    tableView.delegate = self
    tableView.dataSource = self
    tableView.register(MyCell.self, forCellReuseIdentifier: MyCell.reuseIdentifier)
    view = tableView
  }

  override func viewDidLoad() {
    DispatchQueue.main.asyncAfter(deadline: .now() + 1) {
      self.data = [
        Content(author: "Author1", date: "15:07", views: 2, recs: 1, content: longText),
        Content(author: "Author2", date: "15:07", views: 2, recs: 1, content: longText),
        Content(author: "Author3", date: "15:07", views: 2, recs: 1, content: longText),
        Content(author: "Author1", date: "15:07", views: 2, recs: 1, content: longText)
      ]
    }
  }

  func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
    data.count
  }

  func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
    let cell = tableView.dequeueReusableCell(withIdentifier: MyCell.reuseIdentifier, for: indexPath) as! MyCell
    cell.delegate = self
    let content = data[indexPath.row]
    cell.setContent(content)
    return cell
  }

  func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
    tableView.deselectRow(at: indexPath, animated: true)
  }
}

extension MyViewController: MyCellDelegate {
  func contentDidChange(cell: UITableViewCell) {
    UIView.animate(withDuration: 0.2) {
      self.tableView.beginUpdates()
      self.tableView.endUpdates()
    }
  }
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...