我正在从URL下载图像,然后在下载图像时将图像设置为我的imageView(请参阅下面的代码)。我使用自定义UITableViewCell
,UIImageView
设置为NSAutoLayoutConstraints
。约束条件正确设置了单元格的大小,但如果单元格不在屏幕上,或者用户滚动重新加载该单元格,则单元格仅显示图像。
以下是代码:
final class ImageTableViewCell: UITableViewCell {
static let reuseIdentifier = "Image Cell"
@IBOutlet var postImageView: UIImageView!
internal var aspectConstraint : NSLayoutConstraint? {
didSet {
if oldValue != nil {
postImageView.removeConstraint(oldValue!)
}
if aspectConstraint != nil {
postImageView.addConstraint(aspectConstraint!)
}
}
}
override func prepareForReuse() {
super.prepareForReuse()
aspectConstraint = nil
}
func setCustomImage(image : UIImage) {
let aspect = image.size.width / image.size.height
let constraint = NSLayoutConstraint(item: postImageView, attribute: NSLayoutAttribute.width, relatedBy: NSLayoutRelation.equal, toItem: postImageView, attribute: NSLayoutAttribute.height, multiplier: aspect, constant: 0.0)
constraint.priority = UILayoutPriority(rawValue: 999)
aspectConstraint = constraint
postImageView.image = image
}}
基本上,一旦下载了图像,就会在主线程上调用方法。然而,细胞实际上并没有调整自身的大小。单元格与表格最初加载时的高度相同。在我的情况下,由于图像视图为零,由于图像视图上方/下方的边距,高度仅为30点高。如果我设置了一个占位符,那么它被替换,但图像仍未被替换。如果单元格大小不在屏幕上或者用户滚动,则单元格大小只能正确显示。我已经看到了一些关于这个的线索,但很多都很老了。这仍然是苹果公司的一个错误,还是有解决方案?我已尝试setNeedsLayout()
以及其他方法尝试强制更新约束但没有任何效果。任何人的想法/解决方案?
编辑:
调用setCustomImage的代码如下:
The code that calls setCustomImage is the following:
Network.shared.downloadImage(url: post.postURL) { image, error in
if let image = image {
cell.setCustomImage(image: image)
// reload row
self.tableView.reloadRows(at: [cell.indexPathForCell!], with: .fade)
} else if let error = error {
print(error.localizedDescription)
}
}
我添加了代码以在设置现在有效的图像时重新加载行。 layoutIfNeeded()
没有做任何事情。下载图像的网络调用返回主线程上的图像,因此不是问题。一旦设置了单元格,我尝试调用layoutIfNeeded()
无效。特别是重新加载行是治愈它的唯一方法。我只是不知道这是否效率低下。
答案 0 :(得分:0)
您需要调用layoutIfNeeded
来布局子视图。在你的情况下调用setNeedsLayout
应该是多余的,因为添加约束本身应该已经在内部调用它。
在这种情况下没有错误,您不能指望整个窗口层次结构重新定位并重新绘制,因为正在下载您的某个图像。
说“但是如果单元格不在屏幕上,则单元格仅显示图像”是测试人员所做的事情。您需要分析您的问题并确定:
根据您的描述,我看到了一些最可能的候选人:
layoutIfNeeded
)beginUpdates
+ endUpdates
)setCustomImage
时遇到问题(表视图单元格和异步数据加载比您似乎构建的要复杂得多)尝试这些要点,希望首先解决您的问题。如果没有,请确保通过显示如何调用这些方法来更新您的问题。
虽然有很多工具可以实现这一点,但在表视图单元格中设置远程图像应该如下所示:
class MyCell: UITableViewCell {
@IBOutlet private var modelImageView: UIImageView?
var model: MyModel? {
didSet {
refresh()
}
}
private var currentImageURL: URL? // Track what the current image URL is
func refresh() {
if model?.imageURL != currentImageURL { // Only do changes if another URL is being set
let url = model?.imageURL // We need to save this to check it in block
modelImageView?.image = nil // Clear the current image for cases of dequeuing
ImageTools.fetchImage(url, completion: { image in
if url == model?.imageURL { // Due to asynchronousy we need to check if this is really the image we need to show
self.currentImageURL = url // Save the new url
self.modelImageView.image = image // Assign the image
}
})
}
// Setup other UI here
}
}
答案 1 :(得分:0)
您实际上需要reload row at specific Index
或Reload TableView
正如您所提到的那样,滚动tableView或Cell正确显示在屏幕外时,一切正常如预期