Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/swift/20.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/video/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Ios UITableViewCell的异步高度更改_Ios_Swift_Uitableview_Uikit_Uitableviewautomaticdimension - Fatal编程技术网

Ios UITableViewCell的异步高度更改

Ios UITableViewCell的异步高度更改,ios,swift,uitableview,uikit,uitableviewautomaticdimension,Ios,Swift,Uitableview,Uikit,Uitableviewautomaticdimension,在我的一个项目中,我需要根据图像大小更改UITableViewCell中UIImageView的高度,但问题是,有时我必须在单元格已显示后执行此操作 因此,如果我事先知道所有的图像大小,我当前的解决方案会很有魅力,但是如果我试图延迟计算,它完全崩溃了(尤其是滚动,但即使没有它也会崩溃) 我制作了一个示例项目来说明这一点。没有异步下载,但我正在尝试在延迟(1s)后动态更改UIImageView的高度。高度取决于UIImageView,因此下一个UIImageView应该比上一个略高(10像素)。此

在我的一个项目中,我需要根据图像大小更改UITableViewCell中UIImageView的高度,但问题是,有时我必须在单元格已显示后执行此操作

因此,如果我事先知道所有的图像大小,我当前的解决方案会很有魅力,但是如果我试图延迟计算,它完全崩溃了(尤其是滚动,但即使没有它也会崩溃)

我制作了一个示例项目来说明这一点。没有异步下载,但我正在尝试在延迟(1s)后动态更改UIImageView的高度。高度取决于UIImageView,因此下一个UIImageView应该比上一个略高(10像素)。此外,我还有一个UILabel,它被约束到UIImageView

看起来是这样的(UIImageView是红色的)

如果我尝试异步执行此操作,看起来是这样的,所有UILabel在这里都被破坏了

这是在滚动之后的一个(也是异步的):

我做错了什么?我读过几篇关于动态高度的文章,但没有一个解决方案对我有效

我的代码相当简单:

func addTableView() {
    tableView = UITableView()
    tableView.translatesAutoresizingMaskIntoConstraints = false
    tableView.dataSource = self
    tableView.delegate = self
    tableView.separatorStyle = .none
    tableView.estimatedRowHeight = 100
    tableView.rowHeight = UITableView.automaticDimension
    tableView.backgroundColor = .black
    tableView.register(DynamicCell.self, forCellReuseIdentifier: "dynamicCell")
    view.addSubview(tableView)

    tableView.topAnchor.constraint(equalTo: view.topAnchor, constant: 0).isActive = true
    tableView.leftAnchor.constraint(equalTo: view.leftAnchor, constant: 0).isActive = true
    tableView.rightAnchor.constraint(equalTo: view.rightAnchor, constant: 0).isActive = true
    tableView.bottomAnchor.constraint(equalTo: view.bottomAnchor, constant: 0).isActive = true

}

func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
    let cell = tableView.dequeueReusableCell(withIdentifier: "dynamicCell", for: indexPath) as! DynamicCell
        cell.message = messageArray[indexPath.row]
        cell.backgroundColor = .clear
        cell.selectionStyle = .none
        cell.buildCell()
    return cell
}
DynamicCell.swift(代理当前未执行任何操作):


以此作为答案


我注意到一件事,当你在玩cell时,最好使用contentView,而不是直接使用self。ie self.contentView.addSubview()。refreshcell函数做什么?您是否尝试过将其标记为需要显示,以便在下一个绘制周期中进行更新?你试过打电话给layoutifneed吗

为了进一步解释,当您想要更改视图的高度/宽度时,您的视图已经被“渲染”,您需要通知它有更新。当您将视图标记为
setNeedsDisplay
并在下一个渲染周期中对其进行更新时,会发生这种情况

更多关于苹果文档的信息

可以使用此方法或setNeedsDisplay(:)通知系统需要重新绘制视图的内容。此方法记录请求并立即返回。在下一个绘图周期之前,不会实际重新绘制视图,此时所有无效视图都将更新


通过实施heightForRowAt,我似乎可以解决其中的一些甚至大部分问题,但我只想知道为什么当前的方法在这里似乎不起作用。我注意到,当您使用cell时,最好使用contentView,而不是直接使用self。ie self.contentView.addSubview()。refreshcell函数做什么?您是否尝试过将其标记为需要显示,以便在下一个绘制周期中进行更新?您是否尝试调用layoutIfNeeded?我将假设在refreshCell方法中您正在使用
BeginUpdate
EndUpdate
来确保表视图知道?Joshua感谢您的建议。我还没有试过contentView,可以。现在,
refreshcell
什么都不做,我试着玩
setNeedsLayout
layoutIfNeeded
等等,但是没有用。@Rikh我已经尝试在我的实际项目中使用这种方法,但似乎没有简单的方法来使用
BeginUpdate
EndUpdate
,因为我的
tableView
是动态的,随时都可能有新元素,所以我有很多
索引外的
错误。
var backView: UIView!
var label: UILabel!
var picView: UIImageView!

var message: DMessage?
var picViewHeight: NSLayoutConstraint!

var delegate: RefreshCellDelegate?

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

    backView = UIView()
    backView.translatesAutoresizingMaskIntoConstraints = false
    backView.backgroundColor = .white
    backView.clipsToBounds = true
    backView.layer.cornerRadius = 8.0
    self.addSubview(backView)

    label = UILabel()
    label.translatesAutoresizingMaskIntoConstraints = false
    label.textAlignment = .left
    label.textColor = .black
    label.numberOfLines = 0
    backView.addSubview(label)

    picView = UIImageView()
    picView.translatesAutoresizingMaskIntoConstraints = false
    picView.clipsToBounds = true
    picView.backgroundColor = .red
    backView.addSubview(picView)

    addMainConstraints()

}

func addMainConstraints() {
    backView.leftAnchor.constraint(equalTo: self.leftAnchor, constant: 8).isActive = true
    backView.rightAnchor.constraint(equalTo: self.rightAnchor, constant: -32).isActive = true
    backView.topAnchor.constraint(equalTo: self.topAnchor, constant: 4).isActive = true
    backView.bottomAnchor.constraint(equalTo: self.bottomAnchor, constant: -4).isActive = true

    picView.topAnchor.constraint(equalTo: backView.topAnchor, constant: 0).isActive = true
    picView.leftAnchor.constraint(equalTo: backView.leftAnchor, constant: 0).isActive = true
    picView.rightAnchor.constraint(equalTo: backView.rightAnchor, constant: 0).isActive = true

    label.topAnchor.constraint(equalTo: picView.bottomAnchor, constant: 0).isActive = true
    label.leftAnchor.constraint(equalTo: backView.leftAnchor, constant: 8).isActive = true
    label.rightAnchor.constraint(equalTo: backView.rightAnchor, constant: -8).isActive = true
    label.bottomAnchor.constraint(equalTo: backView.bottomAnchor, constant: -4).isActive = true

    picViewHeight = NSLayoutConstraint(item: picView, attribute: .height, relatedBy: .equal, toItem: nil, attribute: .notAnAttribute, multiplier: 1.0, constant: 100)
    picViewHeight.priority = UILayoutPriority(999)
    picViewHeight.isActive = true

}

override func prepareForReuse() {
    picViewHeight.constant = 0
    //picViewHeight.constant = 0
}

func buildCell() {
    guard let message = message else {return}
    label.attributedText = NSAttributedString(string: message.text)
    changeHeightWithDelay()
    //changeHeightWithoutDelay()
}

func changeHeightWithoutDelay() {
    if let nh = self.message?.imageHeight {
        self.picViewHeight.constant = nh
        self.delegate?.refreshCell(cell: self)
    }
}

func changeHeightWithDelay() {
    DispatchQueue.main.asyncAfter(deadline: .now() + 1) {
        if let nh = self.message?.imageHeight {
            self.picViewHeight.constant = nh
            self.delegate?.refreshCell(cell: self)
        }
    }
}