使用 UIStackView 时,UIImageView 在 UITableViewCell 中被挤压
UIImageView squished inside UITableViewCell when using UIStackView
我在 UIStackView
中使用 UIImageView
时看到了一些奇怪的行为,我怀疑我忽略了一些明显的东西 - 虽然我在这一点上已经尝试了很多东西.
我想做的事情非常简单:从网上下载一张图片,在 UIStackView
中设置 UIImageView
。 UIStackView
还包含一个 UILabel
(而我的实际项目包含相当多的 UILabels
,因此是 UIStackView
的原因)。下图有彩色背景来展示哪里出了问题,我还包含了完整的 Playground 代码,以便于 copied/pasted.
正在下载的图片比屏幕width/height大,我设置了contentMode = .scaleAspectFit
。 UITableView
使用
tableView.rowHeight = UITableViewAutomaticDimension
和 .estimatedRowHeight
。我已经设置了约束,并且还尝试在 UIImageView 上设置拥抱优先级,但无济于事。我提前不知道确切的单元格高度,单元格高度都会不同。
尽管 UIImageView
有 leading/trailing 限制,UIStackView
有限制,.rowHeight
单元格,以及 UIImageView
上的 .scaleAspectFit
。您甚至可以看到一小部分(红色)标签,所以我知道 UIStackView
被固定到 UITableViewCell
.
的 contentView
颜色键
- 橙色:UITableViewCell 背景
- 红色:UILabel 背景
- 绿色:UIImageView 背景
import UIKit
import PlaygroundSupport
class CustomView: UIView, UITableViewDataSource {
var tableView = UITableView()
var tableData = [String]()
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
}
override init(frame: CGRect) {
super.init(frame: frame)
backgroundColor = UIColor.gray
tableView.dataSource = self
tableView.rowHeight = UITableViewAutomaticDimension
tableView.estimatedRowHeight = 300
tableView.tableFooterView = UIView()
tableView.translatesAutoresizingMaskIntoConstraints = false
addSubview(tableView)
tableView.leadingAnchor.constraint(equalTo: self.leadingAnchor).isActive = true
tableView.trailingAnchor.constraint(equalTo: self.trailingAnchor).isActive = true
tableView.topAnchor.constraint(equalTo: self.topAnchor).isActive = true
tableView.bottomAnchor.constraint(equalTo: self.bottomAnchor).isActive = true
tableData = [String](repeating: "https://img.webmd.com/dtmcms/live/webmd/consumer_assets/site_images/article_thumbnails/video/wibbitz/wbz-breakfast-most-important-meal.jpg", count: 2)
tableView.register(CustomCell.self, forCellReuseIdentifier: "cell")
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return tableData.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath) as! CustomCell
let imageURL = tableData[indexPath.row]
if let url = URL.init(string: imageURL) {
cell.cellImageView?.downloadImage(with: url,
completion: {
// ...
})
}
return cell
}
}
class CustomCell: UITableViewCell {
var cellImageView: UIImageView?
required init?(coder aDecoder: NSCoder) {
fatalError() // since we're not using
}
override init(style: UITableViewCellStyle, reuseIdentifier: String?) {
super.init(style: style, reuseIdentifier: reuseIdentifier)
setupCell()
}
func setupCell() {
backgroundColor = UIColor.orange
clipsToBounds = true
let tempLabel = UILabel()
tempLabel.translatesAutoresizingMaskIntoConstraints = false
tempLabel.backgroundColor = UIColor.red
tempLabel.text = "this is some text"
tempLabel.numberOfLines = 0
tempLabel.font = UIFont.systemFont(ofSize: 20, weight: .bold)
cellImageView = UIImageView()
cellImageView?.clipsToBounds = true
cellImageView?.contentMode = .scaleAspectFit
cellImageView?.autoresizingMask = [.flexibleWidth, .flexibleHeight]
cellImageView?.backgroundColor = UIColor.green
cellImageView?.translatesAutoresizingMaskIntoConstraints = false
let stackView = UIStackView(arrangedSubviews: [tempLabel, cellImageView!])
contentView.addSubview(stackView)
stackView.translatesAutoresizingMaskIntoConstraints = false
stackView.axis = .vertical
stackView.distribution = .fillProportionally
stackView.alignment = .leading
stackView.spacing = 10
stackView.topAnchor.constraint(equalTo: contentView.topAnchor).isActive = true
stackView.leadingAnchor.constraint(equalTo: contentView.leadingAnchor).isActive = true
stackView.bottomAnchor.constraint(equalTo: contentView.bottomAnchor).isActive = true
stackView.trailingAnchor.constraint(equalTo: contentView.trailingAnchor).isActive = true
cellImageView?.leadingAnchor.constraint(equalTo: stackView.leadingAnchor).isActive = true
cellImageView?.trailingAnchor.constraint(equalTo: stackView.trailingAnchor).isActive = true
}
}
extension UIImageView {
func downloadImage(with url: URL, completion: @escaping () -> Void) {
let task = URLSession.shared.dataTask(with: url) { [weak weakSelf = self] data, response, error in
guard error == nil else {
print("UIImageView: error downloading image: \(String(describing: error))")
return
}
guard let data = data, let downloadedImage = UIImage.init(data: data) else {
print("UIImageView: issue with data from downloaded image.")
return
}
DispatchQueue.main.async {
weakSelf?.image = downloadedImage
completion()
}
}
task.resume()
}
}
let containerView = CustomView(frame: CGRect(x: 0, y: 0, width: 400, height: 600))
containerView.backgroundColor = UIColor.blue
PlaygroundPage.current.liveView = containerView
PlaygroundPage.current.needsIndefiniteExecution = true
您只需在此方法中提供估计的行高
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat
{
return 300; //Choose your custom row height
}
您似乎认为堆栈视图中的图像视图会以某种方式从内到外调整单元格的高度。它不会。如果您想使用自动单元格高度,请不要使用堆栈视图(或添加约束以显式调整堆栈视图的大小,但我怀疑这会给您想要的结果)。
无论如何,您的代码中堆栈视图的用途是什么?堆栈视图所做的只是在困难的情况下为您制定约束。但这不是一个困难的情况。标签和图像视图一起可以轻松地手动配置。
我在 UIStackView
中使用 UIImageView
时看到了一些奇怪的行为,我怀疑我忽略了一些明显的东西 - 虽然我在这一点上已经尝试了很多东西.
我想做的事情非常简单:从网上下载一张图片,在 UIStackView
中设置 UIImageView
。 UIStackView
还包含一个 UILabel
(而我的实际项目包含相当多的 UILabels
,因此是 UIStackView
的原因)。下图有彩色背景来展示哪里出了问题,我还包含了完整的 Playground 代码,以便于 copied/pasted.
正在下载的图片比屏幕width/height大,我设置了contentMode = .scaleAspectFit
。 UITableView
使用
tableView.rowHeight = UITableViewAutomaticDimension
和 .estimatedRowHeight
。我已经设置了约束,并且还尝试在 UIImageView 上设置拥抱优先级,但无济于事。我提前不知道确切的单元格高度,单元格高度都会不同。
尽管 UIImageView
有 leading/trailing 限制,UIStackView
有限制,.rowHeight
单元格,以及 UIImageView
上的 .scaleAspectFit
。您甚至可以看到一小部分(红色)标签,所以我知道 UIStackView
被固定到 UITableViewCell
.
contentView
颜色键
- 橙色:UITableViewCell 背景
- 红色:UILabel 背景
- 绿色:UIImageView 背景
import UIKit
import PlaygroundSupport
class CustomView: UIView, UITableViewDataSource {
var tableView = UITableView()
var tableData = [String]()
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
}
override init(frame: CGRect) {
super.init(frame: frame)
backgroundColor = UIColor.gray
tableView.dataSource = self
tableView.rowHeight = UITableViewAutomaticDimension
tableView.estimatedRowHeight = 300
tableView.tableFooterView = UIView()
tableView.translatesAutoresizingMaskIntoConstraints = false
addSubview(tableView)
tableView.leadingAnchor.constraint(equalTo: self.leadingAnchor).isActive = true
tableView.trailingAnchor.constraint(equalTo: self.trailingAnchor).isActive = true
tableView.topAnchor.constraint(equalTo: self.topAnchor).isActive = true
tableView.bottomAnchor.constraint(equalTo: self.bottomAnchor).isActive = true
tableData = [String](repeating: "https://img.webmd.com/dtmcms/live/webmd/consumer_assets/site_images/article_thumbnails/video/wibbitz/wbz-breakfast-most-important-meal.jpg", count: 2)
tableView.register(CustomCell.self, forCellReuseIdentifier: "cell")
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return tableData.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath) as! CustomCell
let imageURL = tableData[indexPath.row]
if let url = URL.init(string: imageURL) {
cell.cellImageView?.downloadImage(with: url,
completion: {
// ...
})
}
return cell
}
}
class CustomCell: UITableViewCell {
var cellImageView: UIImageView?
required init?(coder aDecoder: NSCoder) {
fatalError() // since we're not using
}
override init(style: UITableViewCellStyle, reuseIdentifier: String?) {
super.init(style: style, reuseIdentifier: reuseIdentifier)
setupCell()
}
func setupCell() {
backgroundColor = UIColor.orange
clipsToBounds = true
let tempLabel = UILabel()
tempLabel.translatesAutoresizingMaskIntoConstraints = false
tempLabel.backgroundColor = UIColor.red
tempLabel.text = "this is some text"
tempLabel.numberOfLines = 0
tempLabel.font = UIFont.systemFont(ofSize: 20, weight: .bold)
cellImageView = UIImageView()
cellImageView?.clipsToBounds = true
cellImageView?.contentMode = .scaleAspectFit
cellImageView?.autoresizingMask = [.flexibleWidth, .flexibleHeight]
cellImageView?.backgroundColor = UIColor.green
cellImageView?.translatesAutoresizingMaskIntoConstraints = false
let stackView = UIStackView(arrangedSubviews: [tempLabel, cellImageView!])
contentView.addSubview(stackView)
stackView.translatesAutoresizingMaskIntoConstraints = false
stackView.axis = .vertical
stackView.distribution = .fillProportionally
stackView.alignment = .leading
stackView.spacing = 10
stackView.topAnchor.constraint(equalTo: contentView.topAnchor).isActive = true
stackView.leadingAnchor.constraint(equalTo: contentView.leadingAnchor).isActive = true
stackView.bottomAnchor.constraint(equalTo: contentView.bottomAnchor).isActive = true
stackView.trailingAnchor.constraint(equalTo: contentView.trailingAnchor).isActive = true
cellImageView?.leadingAnchor.constraint(equalTo: stackView.leadingAnchor).isActive = true
cellImageView?.trailingAnchor.constraint(equalTo: stackView.trailingAnchor).isActive = true
}
}
extension UIImageView {
func downloadImage(with url: URL, completion: @escaping () -> Void) {
let task = URLSession.shared.dataTask(with: url) { [weak weakSelf = self] data, response, error in
guard error == nil else {
print("UIImageView: error downloading image: \(String(describing: error))")
return
}
guard let data = data, let downloadedImage = UIImage.init(data: data) else {
print("UIImageView: issue with data from downloaded image.")
return
}
DispatchQueue.main.async {
weakSelf?.image = downloadedImage
completion()
}
}
task.resume()
}
}
let containerView = CustomView(frame: CGRect(x: 0, y: 0, width: 400, height: 600))
containerView.backgroundColor = UIColor.blue
PlaygroundPage.current.liveView = containerView
PlaygroundPage.current.needsIndefiniteExecution = true
您只需在此方法中提供估计的行高
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat
{
return 300; //Choose your custom row height
}
您似乎认为堆栈视图中的图像视图会以某种方式从内到外调整单元格的高度。它不会。如果您想使用自动单元格高度,请不要使用堆栈视图(或添加约束以显式调整堆栈视图的大小,但我怀疑这会给您想要的结果)。
无论如何,您的代码中堆栈视图的用途是什么?堆栈视图所做的只是在困难的情况下为您制定约束。但这不是一个困难的情况。标签和图像视图一起可以轻松地手动配置。