Reputation: 846
I have a UITableViewCell with UITableViewAutomaticDimension which consists of Image and title. After I get the data from API, I reload tableView, but only title in UILabel appears and not the image, as in below image
After i scroll the tableView, the images appear and are adjusted according to there size. Like Below
I want this to happen before scrolling.
Things I have tried already
My cellForRowAt Code
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
guard let cell = tableView.dequeueReusableCell(withIdentifier: Constants.custom.rawValue) as? CustomCell else {return UITableViewCell()}
cell.update(model: arrImages[indexPath.row])
return cell
}
My Cell Class Logic
Update Method
func update(model: ImageModel) {
self.presentModel = model
}
UI Changes in cell
var presentModel: ImageModel? {
didSet{
if let url = presentModel?.imgURL {
imgView.kf.indicatorType = .activity
imgView.kf.setImage(with: url)
}
lblTitle.text = presentModel?.title
}
}
Addition info I am using KingFisher third party to download images.
Upvotes: 1
Views: 1219
Reputation: 201
Do following
IBOutlet
of this height constraintUIImageView
with frame using the calculated height and width.imageView
as arrangedsubView
in your stack viewimageView
to stack view
stackView.setNeedsLayout()
stackView.layoutIfNeeded()
sample code
let imageSize = image.size
let width = UIScreen.main.bounds.width - 20
let height = (width * imageSize.height) / imageSize.width
let imageView = UIImageView(frame: CGRect(x: 0, y: 0, width: width, height: height))
imageView.image = image
heightConstraint.constant = height
stackView.addArrangedSubview(imageView)
stackView.setNeedsLayout()
stackView.layoutIfNeeded()
Upvotes: 0
Reputation: 3271
You should reload your table view once image is loaded from the url.
You might have multiple cells with image on each cell. So you should call the tableView's reload method once your image is downloaded from the url asynchronously.
You said that images are appears properly when you scroll down the cells off and on screens, because the tableView's func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) will be called when cell is about to visible on screen.
So you should call tableView.reloadData()
or tableView.reloadRows(at: [imageLoadedCellIndexPath], with: .automatic)
method to trigger the tableview's delegate and data source methods.
As you are using Kingfisher extensions to download images from url, you can try using the below method to know the download status.
imageView.kf.setImage(with: url, completionHandler: {
(image, error, cacheType, imageUrl) in
})
instead of imageView.kf.setImage(with: url).
Example:
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
guard let cell = tableView.dequeueReusableCell(withIdentifier: Constants.custom.rawValue) as? CustomCell else {return UITableViewCell()}
cell.update(model: arrImages[indexPath.row])
let imageModel = arrImages[indexPath.row]
if let url = imageModel?.imgURL {
//Check if image is already downloaded
ImageCache.default.retrieveImage(forKey: url.absoluteString, options: nil) {
image, cacheType in
//Image is already downloaded
if let image = image {
//cell.imgView.image = image
imgView.kf.setImage(with: url) //try this line instead of above one
} else { //Download
imgView.kf.indicatorType = .activity
cell.imgView.kf.setImage(with: url, completionHandler: {
(image, error, cacheType, imageUrl) in
if image != nil{
tableView.reloadRows(at: [indexPath], with: .automatic)
//OR
tableView.reloadData()
}
})
}
}
}
return cell
}
And Comment image download code in cell as like below,
var presentModel: ImageModel? {
didSet{
// if let url = presentModel?.imgURL {
// imgView.kf.indicatorType = .activity
// imgView.kf.setImage(with: url)
// }
lblTitle.text = presentModel?.title
}
}
Upvotes: 0