swift UITableViewCell内的动态UIImageView基于来自URL的图像的纵横比

fcg9iug3  于 2022-10-31  发布在  Swift
关注(0)|答案(1)|浏览(143)

我想有一个包含文本和图像的UITableViewCell(如果有的话),其中基于来自API响应的图像的高宽比来调整图像的大小。一个简单的表视图单元格,用于任何社交媒体帖子,就像Twitter或Facebook一样。为了实现这个功能,我在故事板中创建了一个表视图单元格,并为用户名添加了一个标签,一个标签,用于粘贴的文本(动态标签高度)和一个具有固定高度约束的图像视图,并将其高度约束附加到单元格类,稍后我将通过计算纵横比来更改该单元格类。
下面是UITableViewCell类的代码:

class PostsTableViewCell: UITableViewCell {

    @IBOutlet weak var ivProfilePic: UIImageView!
    @IBOutlet weak var ivPost: UIImageView!

    @IBOutlet weak var lblName: UILabel!
    @IBOutlet weak var lblPostContent: UILabel!

    @IBOutlet weak var viewPost: UIView!

    @IBOutlet weak var heighIvPost: NSLayoutConstraint!

    var postImage: UIImage? {
        didSet {
            if let image = postImage {
                configureCellWhenPostImageIsAvailable(image: image)
            }
            viewPost.isHidden = postImage == nil
            layoutIfNeeded()
        }
    }

    override func awakeFromNib() {
        super.awakeFromNib()
        // Initialization code
        ivProfilePic.layer.cornerRadius = 17.5

        viewPost.layer.cornerRadius = 5

        lblPostContent.frame = CGRect(x:0,y:0,width:lblPostContent.intrinsicContentSize.width,height:lblPostContent.intrinsicContentSize.height)

        lblPostContent.isHidden = true

        viewPost.isHidden = true
    }

    override func setSelected(_ selected: Bool, animated: Bool) {
        super.setSelected(selected, animated: animated)

        // Configure the view for the selected state
    }

    override func prepareForReuse() {
        super.prepareForReuse()

        lblName.text = ""
        ivProfilePic.image = UIImage(named: "ProfilePicture")

        lblPostContent.isHidden = true

        viewPost.isHidden = true

        heighIvPost.constant = 162
        ivPost.image = nil
        ivPost.layoutIfNeeded()

    }

    func configureCellWhenPostImageIsAvailable(image: UIImage) {
        let hRatio = image.size.height / image.size.width
        let newImageHeight = hRatio * viewPost.bounds.width
        heighIvPost.constant = newImageHeight
        ivPost.image = image
        ivPost.layoutIfNeeded()
    }

}

在这里,我将ivPost嵌入到UIView中,当加载单元格时,我将所有内容隐藏起来,只有在API响应中有任何图像时,才会显示viewPost包含图像。
这是我在主UIViewController中的cellForRowAt函数:

func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
    let cell = tableView.dequeueReusableCell(withIdentifier: "PostsTableViewCell", for: indexPath) as! PostsTableViewCell

    let data = posts[indexPath.row]

    if let userImage = data.memberProfilePic {
        cell.ivProfilePic.kf.setImage(with: userImage)
    }

    cell.lblName.text = data.memberName

    if let postText = data.postContent {
        cell.lblPostContent.isHidden = false
        cell.lblPostContent.text = postText
    }

    if let postImage = data.postImages {
        cell.viewPost.isHidden = false
        cell.ivPost.kf.setImage(with: postImage)
        if let image = cell.ivPost.image {
            cell.configureCellWhenPostImageIsAvailable(image: image)
            cell.layoutIfNeeded()
        }
    }

    return cell
}

当我运行这段代码并加载页面时,它将显示具有所需纵横比的图像。然而,当我向下滚动时,它将显示具有相同纵横比的所有图像,可能height = 162,但当我再次向上滚动时,所有内容都将再次调整,所有单元格都显示具有适当纵横比的图像。
我想知道出了什么问题,为什么它不计算纵横比时,我只向下滚动。
我看到了一些计算整个表行高的代码,但这些代码只包含一个图像视图,而我有一个标签和一个图像视图,可能会在以后添加按钮,所以我坚持使用上述方法,只是为了计算图像的纵横比,并更改UIImageView的高度。

rsaldnfx

rsaldnfx1#

问题是......
当表格视图调用cellForRowAt时,行高被设置--通常是对单元格内容的约束。如果您在单元格显示后*更改高度将负责通知表格视图需要重新计算行高。
因此,您可以向单元格类添加闭包,如下所示:

class PostsTableViewCell: UITableViewCell {

    // closure
    var layoutChange: ((PostsTableViewCell) -> ())?

    // the rest of your cell code...

    func configureCellWhenPostImageIsAvailable(image: UIImage) {
        let hRatio = image.size.height / image.size.width
        let newImageHeight = hRatio * viewPost.bounds.width
        heighIvPost.constant = newImageHeight
        ivPost.image = image
        // not needed
        //ivPost.layoutIfNeeded()

        // use the closure to inform the table view the row height has changed
        self.layoutChange?(self)
    }
}

然后,在控制器的cellForRowAt

cell.layoutChange = { [weak self] theCell in
        guard let self = self,
              let cellIndexPath = tableView.indexPath(for: theCell)
        else { return }

        // you probably want to update something in your data
        //  maybe:
        var data = self.posts[cellIndexPath.row]
        data.profilePicDownloaded = true
        self.posts[cellIndexPath.row] = data

        // tell the table view to re-cacluclate the row heights
        self.tableView.performBatchUpdates(nil, completion: nil)
    }

    return cell

相关问题