Swift 5 table 带有 UIImage 的视图单元格显得非常高并且图像极度缩放
Swift 5 table view cell with UIImage appears very tall and image extremely zoomed
我正在开发一个聊天应用程序,因此行高各不相同。我将单独的单元格用于纯 txt 消息和带有图像(可能还有文本)的消息。我允许用户 select 来自 phone 的图像。我在单独的 VC 中显示该图像,如果他选择并发送文本,他可以在其中输入文本。我有一个 msg 模型,这意味着我在 base64 和图像格式之间进行转换。我试图最大程度地简化我的单元格 class 以理解以下问题:图像视图中的图像看起来超出了正常 phone 缩放所允许的范围;细胞的高度是巨大的。在我需要使用的单元格 class 上,我有更多的项目和约束,但这里感兴趣的基本逻辑如下:
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
}
这些是我用于 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!
}
这是单元格 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)
}
}
我花了一些时间认为这是一个自动布局问题;或者 table 行高是自动的。这就是为什么我只使用图像视图构建此测试单元 class 的原因。但我认为这个问题具有不同的性质。我确实阅读了很多关于我在这个网站上能找到的相关内容的答案,但我无法确定问题出在哪里,控制台也没有打印出任何内容。
问题是,如果您不给 UIImageView
宽度和高度,它的 intrinsicContentSize
就会变成分配给它的图像的大小。
按原样使用您的代码,您通过约束其前导和尾随锚点为图像视图提供了 宽度,但您没有为它提供 height -- 本身或单元格的高度(因为你想要自动调整单元格大小)。
所以,如果我们使用这四张图片:
生成的 table 视图如下所示:
这是 iPhone 13 上发生的事情(注意:所有尺寸都是四舍五入的)...
对于 100x200 图片:
- 您的 Leading/Trailing 约束使图像视图框架宽 345 磅
- 未设置高度,因此自动布局使用图像大小(200 磅),将图像视图框架设置为 200 磅高
- 图像视图设置为
.scaleAspectFill
,因此缩放后的尺寸为345 x 690
对于 100x300 图片:
- 您的 Leading/Trailing 约束使图像视图框架宽 345 磅
- 未设置高度,因此自动布局使用图像大小(300 磅),将图像视图框架设置为 300 磅高
- 图像视图设置为
.scaleAspectFill
,因此缩放后的尺寸为345 x 1035
对于 600x200 图片:
- 您的 Leading/Trailing 约束使图像视图框架宽 345 磅
- 未设置高度,因此自动布局使用图像大小(200 磅),将图像视图框架设置为 200 磅高
- 图像视图设置为
.scaleAspectFill
,因此缩放后的尺寸为600 x 200
对于 800x600 图片:
- 您的 Leading/Trailing 约束使图像视图框架宽 345 磅
- 未设置高度,因此自动布局使用图像大小(600 磅),将图像视图框架设置为 600 磅高
- 图像视图设置为
.scaleAspectFill
,因此缩放后的尺寸为800 x 600
如果我们将图像视图设置为 .scaleAspectFit
(红色背景以便我们可以看到框架),可能会更清楚:
作为一般规则,通常给图像视图一个固定大小(或比例大小),并使用 .scaleAspectFit
来显示完整的图像。或者,也很常见,使用预处理器为 table 视图单元格生成“缩略图”大小的图像。
我正在开发一个聊天应用程序,因此行高各不相同。我将单独的单元格用于纯 txt 消息和带有图像(可能还有文本)的消息。我允许用户 select 来自 phone 的图像。我在单独的 VC 中显示该图像,如果他选择并发送文本,他可以在其中输入文本。我有一个 msg 模型,这意味着我在 base64 和图像格式之间进行转换。我试图最大程度地简化我的单元格 class 以理解以下问题:图像视图中的图像看起来超出了正常 phone 缩放所允许的范围;细胞的高度是巨大的。在我需要使用的单元格 class 上,我有更多的项目和约束,但这里感兴趣的基本逻辑如下:
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
}
这些是我用于 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!
}
这是单元格 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)
}
} 我花了一些时间认为这是一个自动布局问题;或者 table 行高是自动的。这就是为什么我只使用图像视图构建此测试单元 class 的原因。但我认为这个问题具有不同的性质。我确实阅读了很多关于我在这个网站上能找到的相关内容的答案,但我无法确定问题出在哪里,控制台也没有打印出任何内容。
问题是,如果您不给 UIImageView
宽度和高度,它的 intrinsicContentSize
就会变成分配给它的图像的大小。
按原样使用您的代码,您通过约束其前导和尾随锚点为图像视图提供了 宽度,但您没有为它提供 height -- 本身或单元格的高度(因为你想要自动调整单元格大小)。
所以,如果我们使用这四张图片:
生成的 table 视图如下所示:
这是 iPhone 13 上发生的事情(注意:所有尺寸都是四舍五入的)...
对于 100x200 图片:
- 您的 Leading/Trailing 约束使图像视图框架宽 345 磅
- 未设置高度,因此自动布局使用图像大小(200 磅),将图像视图框架设置为 200 磅高
- 图像视图设置为
.scaleAspectFill
,因此缩放后的尺寸为345 x 690
对于 100x300 图片:
- 您的 Leading/Trailing 约束使图像视图框架宽 345 磅
- 未设置高度,因此自动布局使用图像大小(300 磅),将图像视图框架设置为 300 磅高
- 图像视图设置为
.scaleAspectFill
,因此缩放后的尺寸为345 x 1035
对于 600x200 图片:
- 您的 Leading/Trailing 约束使图像视图框架宽 345 磅
- 未设置高度,因此自动布局使用图像大小(200 磅),将图像视图框架设置为 200 磅高
- 图像视图设置为
.scaleAspectFill
,因此缩放后的尺寸为600 x 200
对于 800x600 图片:
- 您的 Leading/Trailing 约束使图像视图框架宽 345 磅
- 未设置高度,因此自动布局使用图像大小(600 磅),将图像视图框架设置为 600 磅高
- 图像视图设置为
.scaleAspectFill
,因此缩放后的尺寸为800 x 600
如果我们将图像视图设置为 .scaleAspectFit
(红色背景以便我们可以看到框架),可能会更清楚:
作为一般规则,通常给图像视图一个固定大小(或比例大小),并使用 .scaleAspectFit
来显示完整的图像。或者,也很常见,使用预处理器为 table 视图单元格生成“缩略图”大小的图像。