Reputation: 133
Im working on a chat app, so the height of the rows varies. I am using separate cells for plain txt msg and msg with image (and maybe text). I allow the user to select an image from the phone. I display that image in a separate VC where he can enter text if he chooses and send it. I have a model for the msg which means I do conversion between base64 and image formats. I have tried to simplify to the max my cell class to understand the following problem: the image inside the image view appears zoomed beyond what the normal phone zoom would allow; and the height of the cell is immense. On the cell class that I need to use I have more items and constraints but the basic logic of interest here is below:
fileprivate func configureMsgsTable() {
tableView.contentInsetAdjustmentBehavior = .automatic
tableView.backgroundColor = .clear
tableView.keyboardDismissMode = .interactive
tableView.separatorStyle = .none
tableView.showsVerticalScrollIndicator = false
tableView.rowHeight = UITableView.automaticDimension
tableView.estimatedRowHeight = 100
tableView.sectionFooterHeight = 0.0
}
these are the functions I use for encoding/decoding:
fileprivate func convertImageToBase64String (img: UIImage) -> String {
let imageData:NSData = img.jpegData(compressionQuality: 0.50)! as NSData
let imgString = imageData.base64EncodedString(options: Data.Base64EncodingOptions.lineLength64Characters)
return imgString
}
fileprivate func convertBase64StringToImage (imageBase64String:String) -> UIImage {
let imageData = Data.init(base64Encoded: imageBase64String, options: Data.Base64DecodingOptions.ignoreUnknownCharacters)
let image = UIImage(data: imageData!)
return image!
}
and this is the cell class.
class MsgWithImg: UITableViewCell {
//MARK: - Observer.
internal var valuesToDisplay: NewProjectGrpMsgModel! {
didSet {
imgView.image = convertBase64StringToImage(imageBase64String: valuesToDisplay.msgAttachment)
}
}
//MARK: - Properties.
fileprivate let imgView: UIImageView = {
let imgView = UIImageView(frame: .zero)
imgView.clipsToBounds = true
imgView.translatesAutoresizingMaskIntoConstraints = false
imgView.contentMode = .scaleAspectFill
imgView.layer.cornerRadius = 0
return imgView
}()
//MARK: - Init.
override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) {
super.init(style: style, reuseIdentifier: reuseIdentifier)
backgroundColor = .clear
clipsToBounds = true
selectionStyle = .none
setupViews()
}
required init?(coder: NSCoder) {fatalError("init(coder:) has not been implemented")}
fileprivate func setupViews() {
contentView.addSubview(imgView)
let imgViewConstraints = [
imgView.topAnchor.constraint(equalTo: contentView.topAnchor, constant: 3),
imgView.bottomAnchor.constraint(equalTo: contentView.bottomAnchor, constant: -3),
imgView.leadingAnchor.constraint(equalTo: contentView.leadingAnchor),
imgView.trailingAnchor.constraint(equalTo: contentView.trailingAnchor, constant: -45)
]
NSLayoutConstraint.activate(imgViewConstraints)
}
} I spent some time thinking that this is an auto layout problem; or the fact that the table row height is automatic. that's why I built this test cell class with only the image view. but I think this problem is of a different nature. I did read quite a few answers to what I could find relevant on this website but I cannot determine what the problem is and the console does not print out anything.
Upvotes: 0
Views: 914
Reputation: 77477
The problem is that if you don't give a UIImageView
both a width and a height, its intrinsicContentSize
becomes the size of the image assigned to it.
With your code as-is, you've given the image view a width by constraining its Leading and Trailing anchors, but you haven't given it a height -- either by itself or by the cell's height (since you want auto-sizing cells).
So, if we use these four images:
The resulting table view looks like this:
And here's what's happening on an iPhone 13 (note: all sizes are rounded)...
For the 100x200 image:
.scaleAspectFill
, so the scaled size is 345 x 690
For the 100x300 image:
.scaleAspectFill
, so the scaled size is 345 x 1035
For the 600x200 image:
.scaleAspectFill
, so the scaled size is 600 x 200
For the 800x600 image:
.scaleAspectFill
, so the scaled size is 800 x 600
It may be clearer if we set the image view to .scaleAspectFit
(with a red background so we can see the frame):
As a general rule, it is common to give the image view a fixed size (or proportional size), and use .scaleAspectFit
to show the complete images. Or, also common, to use a pre-processor to generate "thumbnail" sized images for the table view cells.
Upvotes: 1