如何使用 UIImageView 和单元格中的多个标签正确设置约束?
How do I make my constraints properly with a UIImageView and multiple labels in a cell?
我目前正在尝试实现动态单元格功能。事实上,我已经实现了它,但只使用了 dateLabel、nameLabel 和 detailLabel。我想在左侧添加一张图片 (authorProfileImg)。我已经为我的 4 个元素尝试了多次迭代和约束组合,但我还没有成功。
class BookTableViewCell: UITableViewCell {
let nameLabel = UILabel(frame: .zero)
let detailLabel = UILabel(frame: .zero)
let dateLabel = UILabel(frame: .zero)
let authorProfileImg = UIImageView(frame: .zero)
// MARK: Initalizers
override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) {
super.init(style: style, reuseIdentifier: reuseIdentifier)
let marginGuide = contentView.layoutMarginsGuide
// configure titleLabel //the upper element
contentView.addSubview(nameLabel)
nameLabel.translatesAutoresizingMaskIntoConstraints = false
nameLabel.leadingAnchor.constraint(equalTo: marginGuide.leadingAnchor, constant: 60).isActive = true
nameLabel.topAnchor.constraint(equalTo: marginGuide.topAnchor).isActive = true
nameLabel.trailingAnchor.constraint(equalTo: marginGuide.trailingAnchor).isActive = true
nameLabel.numberOfLines = 0
nameLabel.font = UIFont(name: "Arial", size: 16)
// configure authorLabel //the lower element
contentView.addSubview(detailLabel)
detailLabel.translatesAutoresizingMaskIntoConstraints = false
detailLabel.leadingAnchor.constraint(equalTo: marginGuide.leadingAnchor, constant: 60).isActive = true
// detailLabel.bottomAnchor.constraint(equalTo: marginGuide.bottomAnchor).isActive = true
detailLabel.trailingAnchor.constraint(equalTo: marginGuide.trailingAnchor, constant: -20).isActive = true
detailLabel.topAnchor.constraint(equalTo: nameLabel.bottomAnchor, constant: 5).isActive = true
detailLabel.numberOfLines = 0
detailLabel.font = UIFont(name: "Arial", size: 13)
detailLabel.textColor = UIColor.lightGray
// configure dateLabel
contentView.addSubview(dateLabel)
dateLabel.translatesAutoresizingMaskIntoConstraints = false
dateLabel.leadingAnchor.constraint(equalTo: marginGuide.leadingAnchor, constant: 60).isActive = true
dateLabel.bottomAnchor.constraint(equalTo: marginGuide.bottomAnchor).isActive = true
dateLabel.trailingAnchor.constraint(equalTo: marginGuide.trailingAnchor).isActive = true
dateLabel.topAnchor.constraint(equalTo: detailLabel.bottomAnchor, constant: 5).isActive = true
dateLabel.numberOfLines = 0
dateLabel.font = UIFont(name: "Arial", size: 12)
dateLabel.textColor = UIColor.red
dateLabel.text = "Jun 5"
// configure author image
contentView.addSubview(authorProfileImg)
authorProfileImg.translatesAutoresizingMaskIntoConstraints = false
authorProfileImg.widthAnchor.constraint(equalToConstant: 50).isActive = true
authorProfileImg.heightAnchor.constraint(equalToConstant: 50).isActive = true
authorProfileImg.layer.cornerRadius = 50
authorProfileImg.leadingAnchor.constraint(equalTo: marginGuide.leadingAnchor).isActive = true
authorProfileImg.topAnchor.constraint(equalTo: marginGuide.bottomAnchor).isActive = true
authorProfileImg.bottomAnchor.constraint(equalTo: marginGuide.bottomAnchor).isActive = true
// authorProfileImg.trailingAnchor.constraint(equalTo: detailLabel.leadingAnchor).isActive = true
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
}
我做错了什么?
这应该适合你:
let marginGuide = contentView.layoutMarginsGuide
// configure author image
contentView.addSubview(authorProfileImg)
authorProfileImg.translatesAutoresizingMaskIntoConstraints = false
authorProfileImg.widthAnchor.constraint(equalToConstant: 50).isActive = true
authorProfileImg.heightAnchor.constraint(equalToConstant: 50).isActive = true
authorProfileImg.leadingAnchor.constraint(equalTo: marginGuide.leadingAnchor).isActive = true
authorProfileImg.topAnchor.constraint(equalTo: marginGuide.topAnchor).isActive = true
// configure titleLabel //the upper element
contentView.addSubview(nameLabel)
nameLabel.translatesAutoresizingMaskIntoConstraints = false
nameLabel.leadingAnchor.constraint(equalTo: authorProfileImg.trailingAnchor, constant: 10).isActive = true
nameLabel.topAnchor.constraint(equalTo: marginGuide.topAnchor).isActive = true
nameLabel.numberOfLines = 1
nameLabel.font = UIFont(name: "Arial", size: 16)
nameLabel.text = "name here"
nameLabel.sizeToFit()
// configure authorLabel //the lower element
contentView.addSubview(detailLabel)
detailLabel.translatesAutoresizingMaskIntoConstraints = false
detailLabel.leadingAnchor.constraint(equalTo: nameLabel.leadingAnchor).isActive = true
detailLabel.topAnchor.constraint(equalTo: nameLabel.bottomAnchor, constant: 5).isActive = true
detailLabel.sizeToFit()
detailLabel.numberOfLines = 1
detailLabel.font = UIFont(name: "Arial", size: 13)
detailLabel.textColor = UIColor.lightGray
detailLabel.text = "detail here"
// configure dateLabel
contentView.addSubview(dateLabel)
dateLabel.translatesAutoresizingMaskIntoConstraints = false
dateLabel.leadingAnchor.constraint(equalTo: detailLabel.leadingAnchor).isActive = true
dateLabel.topAnchor.constraint(equalTo: detailLabel.bottomAnchor, constant: 5).isActive = true
dateLabel.sizeToFit()
dateLabel.numberOfLines = 1
dateLabel.font = UIFont(name: "Arial", size: 12)
dateLabel.textColor = UIColor.red
dateLabel.text = "Jun 5"
self.sizeToFit()
你离得不远。
我发现将相关代码行分组非常有帮助 - 特别是在定义约束时。对我来说,跟踪正在发生的事情要容易得多。
所以,在下面的代码中,我分组了:
- 添加子视图
- 设置元素属性
- 定义约束
您会在评论中看到我对 vertically-centering authorProfileImg
有一个限制,对 top-aligning 它有另一个限制。
class BookTableViewCell: UITableViewCell {
let nameLabel = UILabel(frame: .zero)
let detailLabel = UILabel(frame: .zero)
let dateLabel = UILabel(frame: .zero)
let authorProfileImg = UIImageView(frame: .zero)
// MARK: Initalizers
override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) {
super.init(style: style, reuseIdentifier: reuseIdentifier)
let marginGuide = contentView.layoutMarginsGuide
// add the subviews
contentView.addSubview(nameLabel)
contentView.addSubview(detailLabel)
contentView.addSubview(dateLabel)
contentView.addSubview(authorProfileImg)
// we will use auto-layout constraints
nameLabel.translatesAutoresizingMaskIntoConstraints = false
detailLabel.translatesAutoresizingMaskIntoConstraints = false
dateLabel.translatesAutoresizingMaskIntoConstraints = false
authorProfileImg.translatesAutoresizingMaskIntoConstraints = false
// configure labels and image view properties
nameLabel.numberOfLines = 0
nameLabel.font = UIFont(name: "Arial", size: 16)
detailLabel.numberOfLines = 0
detailLabel.font = UIFont(name: "Arial", size: 13)
detailLabel.textColor = UIColor.lightGray
dateLabel.numberOfLines = 0
dateLabel.font = UIFont(name: "Arial", size: 12)
dateLabel.textColor = UIColor.red
dateLabel.text = "Jun 5"
authorProfileImg.layer.cornerRadius = 25
authorProfileImg.backgroundColor = .blue
// set the constraints
NSLayoutConstraint.activate([
// image view leading is marginGuide leading
authorProfileImg.leadingAnchor.constraint(equalTo: marginGuide.leadingAnchor, constant: 0.0),
// image view centered vertically in cell
authorProfileImg.centerYAnchor.constraint(equalTo: marginGuide.centerYAnchor, constant: 0.0),
// if we want image view constrained to top of marginGuide (aligned to top of cell),
// comment the above line (the centerYAnchor line) and un-comment this next line
//authorProfileImg.topAnchor.constraint(equalTo: marginGuide.topAnchor, constant: 0.0),
// image view is 50x50
authorProfileImg.widthAnchor.constraint(equalToConstant: 50.0),
authorProfileImg.heightAnchor.constraint(equalTo: authorProfileImg.widthAnchor),
// name label constrained to top
// leading is 10-pts from image view trailing
// trailing is marginGuide trailing
nameLabel.topAnchor.constraint(equalTo: marginGuide.topAnchor, constant: 0.0),
nameLabel.leadingAnchor.constraint(equalTo: authorProfileImg.trailingAnchor, constant: 10.0),
nameLabel.trailingAnchor.constraint(equalTo: marginGuide.trailingAnchor, constant: 0.0),
// detail label top constrained 5-pts from bottom of name label
// leading is equal to name label leading
// trailing is marginGuide trailing -20 pts
detailLabel.topAnchor.constraint(equalTo: nameLabel.bottomAnchor, constant: 5.0),
detailLabel.leadingAnchor.constraint(equalTo: nameLabel.leadingAnchor, constant: 0.0),
detailLabel.trailingAnchor.constraint(equalTo: marginGuide.trailingAnchor, constant: -20.0),
// date label top constrained 5-pts from bottom of detail label
// leading is equal to name label leading
// trailing is marginGuide trailing
dateLabel.topAnchor.constraint(equalTo: detailLabel.bottomAnchor, constant: 5.0),
dateLabel.leadingAnchor.constraint(equalTo: nameLabel.leadingAnchor, constant: 0.0),
dateLabel.trailingAnchor.constraint(equalTo: marginGuide.trailingAnchor, constant: 0.0),
// date label bottom constrained to marginGuide bottom
dateLabel.bottomAnchor.constraint(equalTo: marginGuide.bottomAnchor, constant: 0.0),
])
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
}
class BookTableViewController: UITableViewController {
override func viewDidLoad() {
super.viewDidLoad()
tableView.register(BookTableViewCell.self, forCellReuseIdentifier: "BookCell")
// use a larger value if we expect rows to usually have multiple lines of text
tableView.estimatedRowHeight = 60
}
override func numberOfSections(in tableView: UITableView) -> Int {
return 1
}
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return 10
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "BookCell", for: indexPath) as! BookTableViewCell
if indexPath.row % 2 == 0 {
cell.nameLabel.text = "Row: \(indexPath.row) Name"
cell.detailLabel.text = "Row: \(indexPath.row) Detail"
cell.dateLabel.text = "Row: \(indexPath.row) Date"
} else {
cell.nameLabel.text = "Row: \(indexPath.row) Name with\nembedded new-line character."
cell.detailLabel.text = "Row: \(indexPath.row) Detail label with enough text that it will need to word-wrap. Height of label will expand as needed."
cell.dateLabel.text = "Row: \(indexPath.row) Date"
}
return cell
}
}
结果是 (vertically-centered imageView):
top-aligned 图片视图:
我目前正在尝试实现动态单元格功能。事实上,我已经实现了它,但只使用了 dateLabel、nameLabel 和 detailLabel。我想在左侧添加一张图片 (authorProfileImg)。我已经为我的 4 个元素尝试了多次迭代和约束组合,但我还没有成功。
class BookTableViewCell: UITableViewCell {
let nameLabel = UILabel(frame: .zero)
let detailLabel = UILabel(frame: .zero)
let dateLabel = UILabel(frame: .zero)
let authorProfileImg = UIImageView(frame: .zero)
// MARK: Initalizers
override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) {
super.init(style: style, reuseIdentifier: reuseIdentifier)
let marginGuide = contentView.layoutMarginsGuide
// configure titleLabel //the upper element
contentView.addSubview(nameLabel)
nameLabel.translatesAutoresizingMaskIntoConstraints = false
nameLabel.leadingAnchor.constraint(equalTo: marginGuide.leadingAnchor, constant: 60).isActive = true
nameLabel.topAnchor.constraint(equalTo: marginGuide.topAnchor).isActive = true
nameLabel.trailingAnchor.constraint(equalTo: marginGuide.trailingAnchor).isActive = true
nameLabel.numberOfLines = 0
nameLabel.font = UIFont(name: "Arial", size: 16)
// configure authorLabel //the lower element
contentView.addSubview(detailLabel)
detailLabel.translatesAutoresizingMaskIntoConstraints = false
detailLabel.leadingAnchor.constraint(equalTo: marginGuide.leadingAnchor, constant: 60).isActive = true
// detailLabel.bottomAnchor.constraint(equalTo: marginGuide.bottomAnchor).isActive = true
detailLabel.trailingAnchor.constraint(equalTo: marginGuide.trailingAnchor, constant: -20).isActive = true
detailLabel.topAnchor.constraint(equalTo: nameLabel.bottomAnchor, constant: 5).isActive = true
detailLabel.numberOfLines = 0
detailLabel.font = UIFont(name: "Arial", size: 13)
detailLabel.textColor = UIColor.lightGray
// configure dateLabel
contentView.addSubview(dateLabel)
dateLabel.translatesAutoresizingMaskIntoConstraints = false
dateLabel.leadingAnchor.constraint(equalTo: marginGuide.leadingAnchor, constant: 60).isActive = true
dateLabel.bottomAnchor.constraint(equalTo: marginGuide.bottomAnchor).isActive = true
dateLabel.trailingAnchor.constraint(equalTo: marginGuide.trailingAnchor).isActive = true
dateLabel.topAnchor.constraint(equalTo: detailLabel.bottomAnchor, constant: 5).isActive = true
dateLabel.numberOfLines = 0
dateLabel.font = UIFont(name: "Arial", size: 12)
dateLabel.textColor = UIColor.red
dateLabel.text = "Jun 5"
// configure author image
contentView.addSubview(authorProfileImg)
authorProfileImg.translatesAutoresizingMaskIntoConstraints = false
authorProfileImg.widthAnchor.constraint(equalToConstant: 50).isActive = true
authorProfileImg.heightAnchor.constraint(equalToConstant: 50).isActive = true
authorProfileImg.layer.cornerRadius = 50
authorProfileImg.leadingAnchor.constraint(equalTo: marginGuide.leadingAnchor).isActive = true
authorProfileImg.topAnchor.constraint(equalTo: marginGuide.bottomAnchor).isActive = true
authorProfileImg.bottomAnchor.constraint(equalTo: marginGuide.bottomAnchor).isActive = true
// authorProfileImg.trailingAnchor.constraint(equalTo: detailLabel.leadingAnchor).isActive = true
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
}
我做错了什么?
这应该适合你:
let marginGuide = contentView.layoutMarginsGuide
// configure author image
contentView.addSubview(authorProfileImg)
authorProfileImg.translatesAutoresizingMaskIntoConstraints = false
authorProfileImg.widthAnchor.constraint(equalToConstant: 50).isActive = true
authorProfileImg.heightAnchor.constraint(equalToConstant: 50).isActive = true
authorProfileImg.leadingAnchor.constraint(equalTo: marginGuide.leadingAnchor).isActive = true
authorProfileImg.topAnchor.constraint(equalTo: marginGuide.topAnchor).isActive = true
// configure titleLabel //the upper element
contentView.addSubview(nameLabel)
nameLabel.translatesAutoresizingMaskIntoConstraints = false
nameLabel.leadingAnchor.constraint(equalTo: authorProfileImg.trailingAnchor, constant: 10).isActive = true
nameLabel.topAnchor.constraint(equalTo: marginGuide.topAnchor).isActive = true
nameLabel.numberOfLines = 1
nameLabel.font = UIFont(name: "Arial", size: 16)
nameLabel.text = "name here"
nameLabel.sizeToFit()
// configure authorLabel //the lower element
contentView.addSubview(detailLabel)
detailLabel.translatesAutoresizingMaskIntoConstraints = false
detailLabel.leadingAnchor.constraint(equalTo: nameLabel.leadingAnchor).isActive = true
detailLabel.topAnchor.constraint(equalTo: nameLabel.bottomAnchor, constant: 5).isActive = true
detailLabel.sizeToFit()
detailLabel.numberOfLines = 1
detailLabel.font = UIFont(name: "Arial", size: 13)
detailLabel.textColor = UIColor.lightGray
detailLabel.text = "detail here"
// configure dateLabel
contentView.addSubview(dateLabel)
dateLabel.translatesAutoresizingMaskIntoConstraints = false
dateLabel.leadingAnchor.constraint(equalTo: detailLabel.leadingAnchor).isActive = true
dateLabel.topAnchor.constraint(equalTo: detailLabel.bottomAnchor, constant: 5).isActive = true
dateLabel.sizeToFit()
dateLabel.numberOfLines = 1
dateLabel.font = UIFont(name: "Arial", size: 12)
dateLabel.textColor = UIColor.red
dateLabel.text = "Jun 5"
self.sizeToFit()
你离得不远。
我发现将相关代码行分组非常有帮助 - 特别是在定义约束时。对我来说,跟踪正在发生的事情要容易得多。
所以,在下面的代码中,我分组了:
- 添加子视图
- 设置元素属性
- 定义约束
您会在评论中看到我对 vertically-centering authorProfileImg
有一个限制,对 top-aligning 它有另一个限制。
class BookTableViewCell: UITableViewCell {
let nameLabel = UILabel(frame: .zero)
let detailLabel = UILabel(frame: .zero)
let dateLabel = UILabel(frame: .zero)
let authorProfileImg = UIImageView(frame: .zero)
// MARK: Initalizers
override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) {
super.init(style: style, reuseIdentifier: reuseIdentifier)
let marginGuide = contentView.layoutMarginsGuide
// add the subviews
contentView.addSubview(nameLabel)
contentView.addSubview(detailLabel)
contentView.addSubview(dateLabel)
contentView.addSubview(authorProfileImg)
// we will use auto-layout constraints
nameLabel.translatesAutoresizingMaskIntoConstraints = false
detailLabel.translatesAutoresizingMaskIntoConstraints = false
dateLabel.translatesAutoresizingMaskIntoConstraints = false
authorProfileImg.translatesAutoresizingMaskIntoConstraints = false
// configure labels and image view properties
nameLabel.numberOfLines = 0
nameLabel.font = UIFont(name: "Arial", size: 16)
detailLabel.numberOfLines = 0
detailLabel.font = UIFont(name: "Arial", size: 13)
detailLabel.textColor = UIColor.lightGray
dateLabel.numberOfLines = 0
dateLabel.font = UIFont(name: "Arial", size: 12)
dateLabel.textColor = UIColor.red
dateLabel.text = "Jun 5"
authorProfileImg.layer.cornerRadius = 25
authorProfileImg.backgroundColor = .blue
// set the constraints
NSLayoutConstraint.activate([
// image view leading is marginGuide leading
authorProfileImg.leadingAnchor.constraint(equalTo: marginGuide.leadingAnchor, constant: 0.0),
// image view centered vertically in cell
authorProfileImg.centerYAnchor.constraint(equalTo: marginGuide.centerYAnchor, constant: 0.0),
// if we want image view constrained to top of marginGuide (aligned to top of cell),
// comment the above line (the centerYAnchor line) and un-comment this next line
//authorProfileImg.topAnchor.constraint(equalTo: marginGuide.topAnchor, constant: 0.0),
// image view is 50x50
authorProfileImg.widthAnchor.constraint(equalToConstant: 50.0),
authorProfileImg.heightAnchor.constraint(equalTo: authorProfileImg.widthAnchor),
// name label constrained to top
// leading is 10-pts from image view trailing
// trailing is marginGuide trailing
nameLabel.topAnchor.constraint(equalTo: marginGuide.topAnchor, constant: 0.0),
nameLabel.leadingAnchor.constraint(equalTo: authorProfileImg.trailingAnchor, constant: 10.0),
nameLabel.trailingAnchor.constraint(equalTo: marginGuide.trailingAnchor, constant: 0.0),
// detail label top constrained 5-pts from bottom of name label
// leading is equal to name label leading
// trailing is marginGuide trailing -20 pts
detailLabel.topAnchor.constraint(equalTo: nameLabel.bottomAnchor, constant: 5.0),
detailLabel.leadingAnchor.constraint(equalTo: nameLabel.leadingAnchor, constant: 0.0),
detailLabel.trailingAnchor.constraint(equalTo: marginGuide.trailingAnchor, constant: -20.0),
// date label top constrained 5-pts from bottom of detail label
// leading is equal to name label leading
// trailing is marginGuide trailing
dateLabel.topAnchor.constraint(equalTo: detailLabel.bottomAnchor, constant: 5.0),
dateLabel.leadingAnchor.constraint(equalTo: nameLabel.leadingAnchor, constant: 0.0),
dateLabel.trailingAnchor.constraint(equalTo: marginGuide.trailingAnchor, constant: 0.0),
// date label bottom constrained to marginGuide bottom
dateLabel.bottomAnchor.constraint(equalTo: marginGuide.bottomAnchor, constant: 0.0),
])
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
}
class BookTableViewController: UITableViewController {
override func viewDidLoad() {
super.viewDidLoad()
tableView.register(BookTableViewCell.self, forCellReuseIdentifier: "BookCell")
// use a larger value if we expect rows to usually have multiple lines of text
tableView.estimatedRowHeight = 60
}
override func numberOfSections(in tableView: UITableView) -> Int {
return 1
}
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return 10
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "BookCell", for: indexPath) as! BookTableViewCell
if indexPath.row % 2 == 0 {
cell.nameLabel.text = "Row: \(indexPath.row) Name"
cell.detailLabel.text = "Row: \(indexPath.row) Detail"
cell.dateLabel.text = "Row: \(indexPath.row) Date"
} else {
cell.nameLabel.text = "Row: \(indexPath.row) Name with\nembedded new-line character."
cell.detailLabel.text = "Row: \(indexPath.row) Detail label with enough text that it will need to word-wrap. Height of label will expand as needed."
cell.dateLabel.text = "Row: \(indexPath.row) Date"
}
return cell
}
}
结果是 (vertically-centered imageView):
top-aligned 图片视图: