具有多个堆栈视图的自调整单元格
Self sizing cell with multiple Stack Views
我浏览了整个论坛并尝试了所有解决方案,但到目前为止没有任何效果。我注意到我的 UIImageView 覆盖了多个单元格,这意味着单元格不会自动调整其高度。这是我在它抱怨的控制台中发现的约束。
""
在我的 tableViewController 中,我有以下内容
tableView.rowHeight = UITableView.automaticDimension
tableView.estimatedRowHeight = 300
这是我的整个单元格,应该自动调整大小。
import UIKit
class UserConnectionCell: UITableViewCell {
fileprivate let leftImageView: UIImageView = {
let uiImageView = UIImageView()
uiImageView.translatesAutoresizingMaskIntoConstraints = false
return uiImageView
}()
fileprivate let leftLabel: UILabel = {
let label = UILabel()
label.translatesAutoresizingMaskIntoConstraints = false
return label
}()
fileprivate let middleLabel: UILabel = {
let label = UILabel()
label.numberOfLines = 0
label.font = UIFont(name: "Ariel", size: 10)
label.textAlignment = .center
label.translatesAutoresizingMaskIntoConstraints = false
return label
}()
fileprivate let rightImageView: UIImageView = {
let uiImageView = UIImageView()
uiImageView.translatesAutoresizingMaskIntoConstraints = false
return uiImageView
}()
fileprivate let rightLabel: UILabel = {
let label = UILabel()
label.translatesAutoresizingMaskIntoConstraints = false
return label
}()
fileprivate let stackViewLeft: UIStackView = {
let stackView = UIStackView()
stackView.axis = .vertical
stackView.translatesAutoresizingMaskIntoConstraints = false
return stackView
}()
fileprivate let stackViewRight: UIStackView = {
let stackView = UIStackView()
stackView.axis = .vertical
stackView.translatesAutoresizingMaskIntoConstraints = false
return stackView
}()
fileprivate let stackViewMain: UIStackView = {
let stackView = UIStackView()
stackView.axis = .horizontal
stackView.alignment = .fill
stackView.spacing = 0
stackView.translatesAutoresizingMaskIntoConstraints = false
return stackView
}()
//
override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) {
super.init(style: style, reuseIdentifier:reuseIdentifier)
stackViewLeft.addArrangedSubview(leftImageView)
stackViewLeft.addArrangedSubview(leftLabel)
stackViewRight.addArrangedSubview(rightImageView)
stackViewRight.addArrangedSubview(rightLabel)
stackViewMain.addArrangedSubview(stackViewLeft)
stackViewMain.addArrangedSubview(middleLabel)
stackViewMain.addArrangedSubview(stackViewRight)
contentView.addSubview(stackViewMain)
}
// called when trying to layout subviews.
override func layoutSubviews() {
super.layoutSubviews()
stackViewLeft.addConstraint(NSLayoutConstraint(item: leftImageView, attribute: .width, relatedBy: .equal, toItem: nil, attribute: .width, multiplier: 1, constant: 100))
stackViewLeft.addConstraint(NSLayoutConstraint(item: leftImageView, attribute: .height, relatedBy: .equal, toItem: nil, attribute: .height, multiplier: 1, constant: 100))
stackViewRight.addConstraint(NSLayoutConstraint(item: rightImageView, attribute: .height, relatedBy: .equal, toItem: nil, attribute: .height, multiplier: 1, constant: 100))
stackViewRight.addConstraint(NSLayoutConstraint(item: rightImageView, attribute: .width, relatedBy: .equal, toItem: nil, attribute: .width, multiplier: 1, constant: 100))
NSLayoutConstraint.activate(
[stackViewMain.topAnchor.constraint(equalTo: contentView.topAnchor,constant: 0),
stackViewMain.leadingAnchor.constraint(equalTo: contentView.leadingAnchor,constant: 0),
stackViewMain.trailingAnchor.constraint(equalTo: contentView.trailingAnchor,constant: 0),
stackViewMain.bottomAnchor.constraint(equalTo: contentView.bottomAnchor, constant: 0)
])
}
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
var viewModel : UserConnectionViewModel? {
didSet {
// move this to the view model
if let profileUrl = viewModel?.leftImageUrl {
leftImageView.loadImageFromURL(url: profileUrl)
} else {
leftImageView.image = UIImage(named: "defaultprofile")
}
if let profileUrl = viewModel?.rightImageUrl {
rightImageView.loadImageFromURL(url: profileUrl)
} else {
rightImageView.image = UIImage(named: "defaultprofile")
}
leftLabel.text = viewModel?.leftLabel
middleLabel.text = viewModel?.middleLabel
rightLabel.text = viewModel?.rightlabel
}
}
override func awakeFromNib() {
super.awakeFromNib()
self.contentView.autoresizingMask = .flexibleHeight
// Initialization code
}
override func setSelected(_ selected: Bool, animated: Bool) {
super.setSelected(selected, animated: animated)
// Configure the view for the selected state
}
}
关于为什么单元格不能自动调整大小的任何想法?
首先,单元格的 contentView
是一个“特殊”视图,具有 table 视图操作不可或缺的属性。
所以,不要这样做:
self.contentView.autoresizingMask = .flexibleHeight
其次,layoutSubviews()
可以(并且通常是)在单元格/视图的生命周期中被多次调用。您的约束设置应在 init
:
中完成
override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) {
super.init(style: style, reuseIdentifier:reuseIdentifier)
stackViewLeft.addArrangedSubview(leftImageView)
stackViewLeft.addArrangedSubview(leftLabel)
stackViewRight.addArrangedSubview(rightImageView)
stackViewRight.addArrangedSubview(rightLabel)
stackViewMain.addArrangedSubview(stackViewLeft)
stackViewMain.addArrangedSubview(middleLabel)
stackViewMain.addArrangedSubview(stackViewRight)
contentView.addSubview(stackViewMain)
NSLayoutConstraint.activate([
// constrain main stack view to all 4 sides of contentView
stackViewMain.topAnchor.constraint(equalTo: contentView.topAnchor,constant: 0),
stackViewMain.leadingAnchor.constraint(equalTo: contentView.leadingAnchor,constant: 0),
stackViewMain.trailingAnchor.constraint(equalTo: contentView.trailingAnchor,constant: 0),
stackViewMain.bottomAnchor.constraint(equalTo: contentView.bottomAnchor, constant: 0),
// constrain left image view Width: 100-pts,
// Height equal to Width (1:1 ratio)
leftImageView.widthAnchor.constraint(equalToConstant: 100.0),
leftImageView.heightAnchor.constraint(equalTo: leftImageView.widthAnchor),
// constrain right image view Width: 100-pts,
// Height equal to Width (1:1 ratio)
rightImageView.widthAnchor.constraint(equalToConstant: 100.0),
rightImageView.heightAnchor.constraint(equalTo: rightImageView.widthAnchor),
])
}
所以...用上面的代码替换你的init
并且完全删除你的awakeFromNib()
和layoutSubviews()
函数。
你应该得到这个:
我浏览了整个论坛并尝试了所有解决方案,但到目前为止没有任何效果。我注意到我的 UIImageView 覆盖了多个单元格,这意味着单元格不会自动调整其高度。这是我在它抱怨的控制台中发现的约束。
"
在我的 tableViewController 中,我有以下内容
tableView.rowHeight = UITableView.automaticDimension
tableView.estimatedRowHeight = 300
这是我的整个单元格,应该自动调整大小。
import UIKit
class UserConnectionCell: UITableViewCell {
fileprivate let leftImageView: UIImageView = {
let uiImageView = UIImageView()
uiImageView.translatesAutoresizingMaskIntoConstraints = false
return uiImageView
}()
fileprivate let leftLabel: UILabel = {
let label = UILabel()
label.translatesAutoresizingMaskIntoConstraints = false
return label
}()
fileprivate let middleLabel: UILabel = {
let label = UILabel()
label.numberOfLines = 0
label.font = UIFont(name: "Ariel", size: 10)
label.textAlignment = .center
label.translatesAutoresizingMaskIntoConstraints = false
return label
}()
fileprivate let rightImageView: UIImageView = {
let uiImageView = UIImageView()
uiImageView.translatesAutoresizingMaskIntoConstraints = false
return uiImageView
}()
fileprivate let rightLabel: UILabel = {
let label = UILabel()
label.translatesAutoresizingMaskIntoConstraints = false
return label
}()
fileprivate let stackViewLeft: UIStackView = {
let stackView = UIStackView()
stackView.axis = .vertical
stackView.translatesAutoresizingMaskIntoConstraints = false
return stackView
}()
fileprivate let stackViewRight: UIStackView = {
let stackView = UIStackView()
stackView.axis = .vertical
stackView.translatesAutoresizingMaskIntoConstraints = false
return stackView
}()
fileprivate let stackViewMain: UIStackView = {
let stackView = UIStackView()
stackView.axis = .horizontal
stackView.alignment = .fill
stackView.spacing = 0
stackView.translatesAutoresizingMaskIntoConstraints = false
return stackView
}()
//
override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) {
super.init(style: style, reuseIdentifier:reuseIdentifier)
stackViewLeft.addArrangedSubview(leftImageView)
stackViewLeft.addArrangedSubview(leftLabel)
stackViewRight.addArrangedSubview(rightImageView)
stackViewRight.addArrangedSubview(rightLabel)
stackViewMain.addArrangedSubview(stackViewLeft)
stackViewMain.addArrangedSubview(middleLabel)
stackViewMain.addArrangedSubview(stackViewRight)
contentView.addSubview(stackViewMain)
}
// called when trying to layout subviews.
override func layoutSubviews() {
super.layoutSubviews()
stackViewLeft.addConstraint(NSLayoutConstraint(item: leftImageView, attribute: .width, relatedBy: .equal, toItem: nil, attribute: .width, multiplier: 1, constant: 100))
stackViewLeft.addConstraint(NSLayoutConstraint(item: leftImageView, attribute: .height, relatedBy: .equal, toItem: nil, attribute: .height, multiplier: 1, constant: 100))
stackViewRight.addConstraint(NSLayoutConstraint(item: rightImageView, attribute: .height, relatedBy: .equal, toItem: nil, attribute: .height, multiplier: 1, constant: 100))
stackViewRight.addConstraint(NSLayoutConstraint(item: rightImageView, attribute: .width, relatedBy: .equal, toItem: nil, attribute: .width, multiplier: 1, constant: 100))
NSLayoutConstraint.activate(
[stackViewMain.topAnchor.constraint(equalTo: contentView.topAnchor,constant: 0),
stackViewMain.leadingAnchor.constraint(equalTo: contentView.leadingAnchor,constant: 0),
stackViewMain.trailingAnchor.constraint(equalTo: contentView.trailingAnchor,constant: 0),
stackViewMain.bottomAnchor.constraint(equalTo: contentView.bottomAnchor, constant: 0)
])
}
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
var viewModel : UserConnectionViewModel? {
didSet {
// move this to the view model
if let profileUrl = viewModel?.leftImageUrl {
leftImageView.loadImageFromURL(url: profileUrl)
} else {
leftImageView.image = UIImage(named: "defaultprofile")
}
if let profileUrl = viewModel?.rightImageUrl {
rightImageView.loadImageFromURL(url: profileUrl)
} else {
rightImageView.image = UIImage(named: "defaultprofile")
}
leftLabel.text = viewModel?.leftLabel
middleLabel.text = viewModel?.middleLabel
rightLabel.text = viewModel?.rightlabel
}
}
override func awakeFromNib() {
super.awakeFromNib()
self.contentView.autoresizingMask = .flexibleHeight
// Initialization code
}
override func setSelected(_ selected: Bool, animated: Bool) {
super.setSelected(selected, animated: animated)
// Configure the view for the selected state
}
}
关于为什么单元格不能自动调整大小的任何想法?
首先,单元格的 contentView
是一个“特殊”视图,具有 table 视图操作不可或缺的属性。
所以,不要这样做:
self.contentView.autoresizingMask = .flexibleHeight
其次,layoutSubviews()
可以(并且通常是)在单元格/视图的生命周期中被多次调用。您的约束设置应在 init
:
override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) {
super.init(style: style, reuseIdentifier:reuseIdentifier)
stackViewLeft.addArrangedSubview(leftImageView)
stackViewLeft.addArrangedSubview(leftLabel)
stackViewRight.addArrangedSubview(rightImageView)
stackViewRight.addArrangedSubview(rightLabel)
stackViewMain.addArrangedSubview(stackViewLeft)
stackViewMain.addArrangedSubview(middleLabel)
stackViewMain.addArrangedSubview(stackViewRight)
contentView.addSubview(stackViewMain)
NSLayoutConstraint.activate([
// constrain main stack view to all 4 sides of contentView
stackViewMain.topAnchor.constraint(equalTo: contentView.topAnchor,constant: 0),
stackViewMain.leadingAnchor.constraint(equalTo: contentView.leadingAnchor,constant: 0),
stackViewMain.trailingAnchor.constraint(equalTo: contentView.trailingAnchor,constant: 0),
stackViewMain.bottomAnchor.constraint(equalTo: contentView.bottomAnchor, constant: 0),
// constrain left image view Width: 100-pts,
// Height equal to Width (1:1 ratio)
leftImageView.widthAnchor.constraint(equalToConstant: 100.0),
leftImageView.heightAnchor.constraint(equalTo: leftImageView.widthAnchor),
// constrain right image view Width: 100-pts,
// Height equal to Width (1:1 ratio)
rightImageView.widthAnchor.constraint(equalToConstant: 100.0),
rightImageView.heightAnchor.constraint(equalTo: rightImageView.widthAnchor),
])
}
所以...用上面的代码替换你的init
并且完全删除你的awakeFromNib()
和layoutSubviews()
函数。
你应该得到这个: