如何在UITableViewCell内部更新UITableView的高度约束

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了如何在UITableViewCell内部更新UITableView的高度约束相关的知识,希望对你有一定的参考价值。

我有一个UITableView,它显示用户发表的评论。这些单元格内部可能包含对评论的回复,我使用另一个UITableView显示了该评论。我当前正在做的是在设置时将此内部UITableView的高度(回复评论)设置为500,然后在layoutSubviews中计算此内部UITableViewCells的可见答复单元格,然后根据计算结果更改此内部UITableView的高度。我目前遇到的问题是,在加载时,我的布局到处都是(参见图1),但是,uppon在外部UITableView上上下滚动了几次,才得到正确的所需的布局(图2)。请有人可以建议如何更新约束,以便在加载时获得正确的布局吗?

主UItableView

class CommentOnPostTableView: UITableView, UITableViewDataSource, UITableViewDelegate

var items: [Comment]?
var post: ResearchPost?
let cellIDB = "commentCellId"

init(frame: CGRect, style: UITableView.Style, sourceData: [Comment], postContent: ResearchPost) 
    super.init(frame: frame, style: style)

    items = sourceData
    post = postContent
    self.dataSource = self
    self.delegate = self
    self.register(CommentTableViewCell.self, forCellReuseIdentifier: cellIDB)


required init?(coder: NSCoder) 
    fatalError("init(coder:) has not been implemented")





extension CommentOnPostTableView

/***Number of cells*/
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int 
    if let dataSource = items
        return dataSource.count
    else
        return 0
    



/***Create Cell*/
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell 
    guard let dataSource = items elsereturn UITableViewCell.init()
    let cell = tableView.dequeueReusableCell(withIdentifier: cellIDB, for: indexPath) as! CommentTableViewCell
    cell.dataObject = dataSource[indexPath.row - 1]
    return cell

  

主UITableViewCell:

class CommentTableViewCell: UITableViewCell 

var nameLabel: UILabel = 
    let label = UILabel()
    label.font = .boldSystemFont(ofSize: 11)
    label.translatesAutoresizingMaskIntoConstraints = false
    return label
()
var imgView: UIImageView = 
    let view = UIImageView()
    view.backgroundColor = UIColor.black
    view.contentMode = .scaleAspectFit
    view.translatesAutoresizingMaskIntoConstraints = false
    return view
()
var replyLabel: UILabel = 
    let label = UILabel()
    label.text = "Reply"
    label.textColor = UIColor.appGrayForButtonTitles
    label.font = UIFont.systemFont(ofSize: 11)
    label.translatesAutoresizingMaskIntoConstraints = false
    return label
()

var numRepliesLabel: UILabel = 
    let label = UILabel()
    label.font = .boldSystemFont(ofSize: 11)
    label.textColor = UIColor.app0946BF
    label.textAlignment = .right
    label.translatesAutoresizingMaskIntoConstraints = false
    return label
()
var repliesTextLabel: UILabel = 
    let label = UILabel()
    label.text = "Replies"
    label.font = .boldSystemFont(ofSize: 11)
    label.textColor = UIColor.app0946BF
    label.translatesAutoresizingMaskIntoConstraints = false
    return label
()
var timeReplyContainer: UIView = 
    let view = UIView()
    view.translatesAutoresizingMaskIntoConstraints = false
    return view
()
var timeAgoLabel: UILabel = 
    let label = UILabel()
    label.text = "1 hr"
    label.textColor = UIColor.appGrayLight
    label.font = UIFont.systemFont(ofSize: 11)
    label.translatesAutoresizingMaskIntoConstraints = false
    return label
()
var timeTextLabel: UILabel = 
    let label = UILabel()
    label.textColor = UIColor.appGrayLight
    label.text = "ago"
    label.font = UIFont.systemFont(ofSize: 11)
    label.translatesAutoresizingMaskIntoConstraints = false
    return label
()
var repliesContainer: UIView = 
    let view = UIView()
    view.backgroundColor = UIColor.yellow
    view.translatesAutoresizingMaskIntoConstraints = false
    return view
()
var cellIndexPath: IndexPath?
var commentLabel: LabelWithPadding!
var repliesTableView: RepliesToCommentsTableView!
var replyToCommentItems = [Comment]()
let repliesID = "repliesToCommentsID"
var numberOfRepliesToComment: Int = 0
fileprivate var oldConstraints = [NSLayoutConstraint]()
fileprivate var oldReplyTableHeightConstraints = [NSLayoutConstraint]()
fileprivate var totalCellHeight: CGFloat?

/** init is called before  dataObject.didSet*/
override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) 
    super.init(style: style, reuseIdentifier: reuseIdentifier)
    print("CommentTableViewCell.INIT")
    self.selectionStyle = .none
    setupViews()



var dataObject: Comment?
    didSet
        if let data = dataObject
            guard
                let image = data.imageOfCommentor,
                let name = data.name,
                let comment = data.comment,
                let replies = data.repliesToComment elsereturn
            print("dataObject.didSet for :\(name)")
            repliesTableView.sourceData = replies
            repliesTableView.reloadData()

            numberOfRepliesToComment = replies.count
            numRepliesLabel.text = "\(replies.count)"
            imgView.image = image
            nameLabel.text = name
            commentLabel.label.text = comment
        
    



override func updateConstraints() 
    print("updateConstraints for : \(nameLabel.text!)")
    super.updateConstraints()


override func layoutSubviews() 
    super.layoutSubviews()
    print("layoutSubviews for \(nameLabel.text!)")

    let repliesVisible = repliesTableView.visibleCells
    if repliesVisible.count > 0

        UIView.animate(withDuration: 0) 
            //self.layoutIfNeeded()
            self.totalCellHeight = 0.0
            for reply in repliesVisible
                self.totalCellHeight! += reply.frame.height
            
           NSLayoutConstraint.deactivate(self.oldReplyTableHeightConstraints)
            let newHeightConstraint = self.repliesTableView.heightAnchor.constraint(equalToConstant: self.totalCellHeight!)
            let newHeightArray: [NSLayoutConstraint] = [newHeightConstraint]
            self.oldReplyTableHeightConstraints = newHeightArray
            NSLayoutConstraint.activate(self.oldReplyTableHeightConstraints)

            self.layoutIfNeeded()
        
    else
        // Do not show repliesTableView
        NSLayoutConstraint.deactivate(self.oldReplyTableHeightConstraints)
        let newHeightConstraint = self.repliesTableView.heightAnchor.constraint(equalToConstant: 0.0)
        let newHeightArray: [NSLayoutConstraint] = [newHeightConstraint]
        self.oldReplyTableHeightConstraints = newHeightArray
        NSLayoutConstraint.activate(self.oldReplyTableHeightConstraints)

        self.layoutIfNeeded()
        self.commentLabel.layoutIfNeeded()
    



required init?(coder: NSCoder) 
    fatalError("init(coder:) has not been implemented")



let borderSpace: CGFloat = 10
let viewSpace: CGFloat = 5

private func setupViews()
    let c = contentView.safeAreaLayoutGuide

    /**Create commentLabel*/
    let padding = UIEdgeInsets.init(top: 3, left: 5, bottom: 3, right: 5)
    commentLabel = LabelWithPadding.init(frame: .zero, with: padding)
    commentLabel.translatesAutoresizingMaskIntoConstraints = false

    /**Create reply to comments tableView*/
    repliesTableView = RepliesToCommentsTableView.init(frame: .zero, style: .plain, sourceData: replyToCommentItems, cellid: repliesID)
    repliesTableView.translatesAutoresizingMaskIntoConstraints = false
    repliesTableView.isScrollEnabled = false
    repliesTableView.backgroundColor = UIColor.green


    timeReplyContainer.addSubview(timeAgoLabel)
    timeReplyContainer.addSubview(timeTextLabel)
    timeReplyContainer.addSubview(replyLabel)
    timeReplyContainer.addSubview(numRepliesLabel)
    timeReplyContainer.addSubview(repliesTextLabel)

    contentView.addSubview(imgView)
    contentView.addSubview(nameLabel)
    contentView.addSubview(commentLabel)
    contentView.addSubview(timeReplyContainer)
    contentView.addSubview(repliesTableView)

    commentLabel.label.font = UIFont.systemFont(ofSize: 12)
    commentLabel.label.numberOfLines = 0
    commentLabel.label.lineBreakMode = .byWordWrapping
    commentLabel.layer.cornerRadius = 7
    commentLabel.layer.masksToBounds = true
    commentLabel.backgroundColor = UIColor.appGrayExtraLightGray


    /**Layout constraints*/
    NSLayoutConstraint.deactivate(oldConstraints)
    NSLayoutConstraint.deactivate(oldReplyTableHeightConstraints)

    let newConstraints = [
        imgView.topAnchor.constraint(equalTo: c.topAnchor, constant: borderSpace),
        imgView.leadingAnchor.constraint(equalTo: c.leadingAnchor, constant: borderSpace),
        imgView.widthAnchor.constraint(equalTo: c.widthAnchor, multiplier: 0.08),
        imgView.heightAnchor.constraint(equalTo: c.widthAnchor, multiplier: 0.08),

        nameLabel.topAnchor.constraint(equalTo: c.topAnchor, constant: borderSpace),
        nameLabel.leadingAnchor.constraint(equalTo: imgView.trailingAnchor, constant: 10),
        nameLabel.trailingAnchor.constraint(equalTo: c.trailingAnchor, constant: -borderSpace),


        commentLabel.topAnchor.constraint(equalTo: nameLabel.bottomAnchor, constant: viewSpace),
        commentLabel.widthAnchor.constraint(equalTo: nameLabel.widthAnchor),
        commentLabel.trailingAnchor.constraint(equalTo: c.trailingAnchor, constant: -borderSpace),

        timeReplyContainer.topAnchor.constraint(equalTo: commentLabel.bottomAnchor, constant: borderSpace),
        timeReplyContainer.heightAnchor.constraint(equalToConstant: 30),
        timeReplyContainer.widthAnchor.constraint(equalTo: nameLabel.widthAnchor),
        timeReplyContainer.trailingAnchor.constraint(equalTo: c.trailingAnchor, constant: -borderSpace),
        timeReplyContainer.bottomAnchor.constraint(equalTo: repliesTableView.topAnchor, constant: -10),

        timeAgoLabel.leadingAnchor.constraint(equalTo: timeReplyContainer.leadingAnchor, constant: 5),
        timeAgoLabel.topAnchor.constraint(equalTo: timeReplyContainer.topAnchor),
        timeAgoLabel.trailingAnchor.constraint(equalTo: timeTextLabel.leadingAnchor, constant: -5),
        timeAgoLabel.topAnchor.constraint(equalTo: timeTextLabel.topAnchor),

        timeTextLabel.topAnchor.constraint(equalTo: timeReplyContainer.topAnchor),
        timeTextLabel.trailingAnchor.constraint(equalTo: replyLabel.leadingAnchor, constant: -10),
        replyLabel.topAnchor.constraint(equalTo: timeReplyContainer.topAnchor),

        numRepliesLabel.topAnchor.constraint(equalTo: timeReplyContainer.topAnchor),
        numRepliesLabel.trailingAnchor.constraint(equalTo: repliesTextLabel.leadingAnchor, constant: -5),
        repliesTextLabel.topAnchor.constraint(equalTo: timeReplyContainer.topAnchor),
        repliesTextLabel.trailingAnchor.constraint(equalTo: timeReplyContainer.trailingAnchor),

        repliesTableView.widthAnchor.constraint(equalTo: nameLabel.widthAnchor),
        repliesTableView.trailingAnchor.constraint(equalTo: c.trailingAnchor, constant: -borderSpace),
        repliesTableView.bottomAnchor.constraint(equalTo: c.bottomAnchor, constant: -borderSpace)

    ]

    NSLayoutConstraint.activate([repliesTableView.heightAnchor.constraint(equalToConstant: 500)])
    NSLayoutConstraint.activate(newConstraints)
    oldConstraints = newConstraints
    oldReplyTableHeightConstraints = [repliesTableView.heightAnchor.constraint(equalToConstant: 500)]



图1:

enter image description here

图2:

enter image description here

答案

在外部表视图的cellForRowAt功能期间设置内部表视图的高度。另外,我将覆盖updateConstraints,在其中设置约束,然后在init / setup函数中为每个单元格调用setNeedsUpdateConstraints

以上是关于如何在UITableViewCell内部更新UITableView的高度约束的主要内容,如果未能解决你的问题,请参考以下文章

仅为 UITableViewCell 的一部分调用 didSelectRowAtIndexPath

滚动后 UITableViewCell 标签发生变化[重复]

保存 UITableviewcell accessoryView 的状态

dequeueReusableCellWithIdentifier、自定义 UITableViewCell 的问题

在 UITableViewCell ios 中制作动态 UILabel 高度/宽度?

从 uitableviewcell 获取文本输入