iOS - 在水平 UIStackView 中获取所有可用的 space
iOS - Take all the available space in a horizontal UIStackView
我有 UITableViewCell
,其中包含水平 UIStackView
。 UIStackView
按以下顺序包含四个视图。
UIImageView UILabel UILabel UIImageView
arrangedSubViews
后有16 points
个间距。我希望第二个 UILabel 占用所有可用的 space。如果没有足够的 space,文本应该换行。
我使用了以下代码。它几乎可以工作。问题是即使 UILabel
之间有足够的 space,正如您在所附的屏幕截图中看到的那样,第二个 UILabel
会中断。但我希望它只有在没有足够的情况下才会中断 space.
class TableViewCell: UITableViewCell {
static let identifier = "TableViewCell"
private let leadingImageView: UIImageView = {
let view = UIImageView(image: UIImage(systemName: "calendar"))
view.setConstraints(heightConstant: 25, widthConstant: 25)
view.tintColor = .text
return view
}()
private let leadingLabel: UILabel = {
let label = UILabel()
label.textColor = .label
label.text = "Start Date"
label.numberOfLines = 0
label.sizeToFit()
return label
}()
let trailingLabel: UILabel = {
let label = UILabel()
label.text = "Friday, 17 July 2020"
label.textColor = .label
label.numberOfLines = 0
label.textAlignment = .right
return label
}()
let trailingImageView: UIImageView = {
let configuration = UIImage.SymbolConfiguration(pointSize: 12, weight: .light)
let image = UIImage(systemName: "arrowtriangle.down", withConfiguration: configuration)
let view = UIImageView(image: image)
return view
}()
private let superStackView: UIStackView = {
let view = UIStackView()
view.distribution = .fillProportionally
view.alignment = .center
view.spacing = 16
return view
}()
private let containerView: UIView = {
let view = UIView()
view.setContentHuggingPriority(.defaultHigh, for: .horizontal)
view.setContentHuggingPriority(.defaultHigh, for: .vertical)
return view
}()
override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) {
super.init(style: style, reuseIdentifier: reuseIdentifier)
setUpSubviews()
}
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
}
}
extension TableViewCell {
private func setUpSubviews(){
containerView.addSubview(trailingImageView)
trailingImageView.alignCenter(centerXAnchor: containerView.centerXAnchor,
centerYAnchor: containerView.centerYAnchor)
superStackView.addArrangedSubview(leadingImageView)
superStackView.addArrangedSubview(leadingLabel)
superStackView.addArrangedSubview(trailingLabel)
superStackView.addArrangedSubview(containerView)
let constant = CGFloat(16)
self.addSubview(superStackView)
self.contentView.addSubview(superStackView)
superStackView.setConstraints(topAnchor: contentView.topAnchor, leadingAnchor: contentView.leadingAnchor,
bottomAnchor: contentView.bottomAnchor, trailingAnchor: contentView.trailingAnchor,
topConstant: constant, leadingConstant: constant, bottomConstant: constant, trailingConstant: constant)
self.contentView.updateConstraints()
}
}
如何解决这个问题,使单元格看起来像下图中的单元格?
尝试Return 1
let trailingLabel: UILabel = {
let label = UILabel()
label.text = "Friday, 17 July 2020"
label.textColor = .label
label.numberOfLines = 1
label.textAlignment = .right
return label
}()
你很接近...
首先,将堆栈视图的分布设置为 Fill Proportionally
是最容易被误解的分布选项,您不想在这里使用它。
其次,在设计时使用对比色背景非常有帮助,可以很容易地看到您的框架在做什么。
这是您的代码,经过修改以达到您的目标。我没有您的“约束助手”,所以我将其更改为标准约束格式。我还添加了一些评论以进行澄清:
class TableViewCell: UITableViewCell {
static let identifier = "TableViewCell"
private let leadingImageView: UIImageView = {
let view = UIImageView(image: UIImage(systemName: "calendar"))
view.translatesAutoresizingMaskIntoConstraints = false
//view.setConstraints(heightConstant: 25, widthConstant: 25)
view.widthAnchor.constraint(equalToConstant: 25).isActive = true
view.heightAnchor.constraint(equalToConstant: 25).isActive = true
view.tintColor = .blue // .text
return view
}()
private let leadingLabel: UILabel = {
let label = UILabel()
label.textColor = .label
label.text = "Start Date"
// only single line for "leading label"
label.numberOfLines = 1
// content hugging
label.setContentHuggingPriority(.required, for: .horizontal)
label.backgroundColor = .cyan
return label
}()
let trailingLabel: UILabel = {
let label = UILabel()
label.text = "Friday, 17 July 2020"
label.textColor = .label
label.numberOfLines = 0
label.textAlignment = .right
label.backgroundColor = .green
return label
}()
let trailingImageView: UIImageView = {
let configuration = UIImage.SymbolConfiguration(pointSize: 12, weight: .light)
let image = UIImage(systemName: "arrowtriangle.down", withConfiguration: configuration)
let view = UIImageView(image: image)
return view
}()
private let superStackView: UIStackView = {
let view = UIStackView()
view.translatesAutoresizingMaskIntoConstraints = false
// do NOT use .fillProportionally
view.distribution = .fill
view.alignment = .center
view.spacing = 16
return view
}()
private let containerView: UIView = {
let view = UIView()
// not needed
//view.setContentHuggingPriority(.defaultHigh, for: .horizontal)
//view.setContentHuggingPriority(.defaultHigh, for: .vertical)
return view
}()
override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) {
super.init(style: style, reuseIdentifier: reuseIdentifier)
setUpSubviews()
}
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
}
}
extension TableViewCell {
private func setUpSubviews(){
containerView.addSubview(trailingImageView)
//trailingImageView.alignCenter(centerXAnchor: containerView.centerXAnchor,
// centerYAnchor: containerView.centerYAnchor)
superStackView.addArrangedSubview(leadingImageView)
superStackView.addArrangedSubview(leadingLabel)
superStackView.addArrangedSubview(trailingLabel)
superStackView.addArrangedSubview(containerView)
let constant = CGFloat(16)
self.addSubview(superStackView)
self.contentView.addSubview(superStackView)
//superStackView.setConstraints(topAnchor: contentView.topAnchor, leadingAnchor: contentView.leadingAnchor,
// bottomAnchor: contentView.bottomAnchor, trailingAnchor: contentView.trailingAnchor,
// topConstant: constant, leadingConstant: constant, bottomConstant: constant, trailingConstant: constant)
NSLayoutConstraint.activate([
trailingImageView.centerXAnchor.constraint(equalTo: containerView.centerXAnchor),
trailingImageView.centerYAnchor.constraint(equalTo: containerView.centerYAnchor),
superStackView.topAnchor.constraint(equalTo: contentView.topAnchor, constant: constant),
superStackView.leadingAnchor.constraint(equalTo: contentView.leadingAnchor, constant: constant),
superStackView.trailingAnchor.constraint(equalTo: contentView.trailingAnchor, constant: -constant),
superStackView.bottomAnchor.constraint(equalTo: contentView.bottomAnchor, constant: -constant),
])
// not needed
//self.contentView.updateConstraints()
}
}
还有一个示例视图控制器:
class MahanTableViewController: UITableViewController {
var myData: [String] = [
"Saturday, 18 July 2020",
"Sunday, 19 July 2020",
"Wednesday, 22 July 2020",
"Saturday, 26 September 2020",
"Sunday, 27 September 2020",
"Wednesday, 30 September 2020",
]
override func viewDidLoad() {
super.viewDidLoad()
tableView.register(TableViewCell.self, forCellReuseIdentifier: TableViewCell.identifier)
}
// MARK: - Table view data source
override func numberOfSections(in tableView: UITableView) -> Int {
return 1
}
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return myData.count
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: TableViewCell.identifier, for: indexPath) as! TableViewCell
cell.trailingLabel.text = myData[indexPath.row]
return cell
}
}
生成此输出:
我有 UITableViewCell
,其中包含水平 UIStackView
。 UIStackView
按以下顺序包含四个视图。
UIImageView UILabel UILabel UIImageView
arrangedSubViews
后有16 points
个间距。我希望第二个 UILabel 占用所有可用的 space。如果没有足够的 space,文本应该换行。
我使用了以下代码。它几乎可以工作。问题是即使 UILabel
之间有足够的 space,正如您在所附的屏幕截图中看到的那样,第二个 UILabel
会中断。但我希望它只有在没有足够的情况下才会中断 space.
class TableViewCell: UITableViewCell {
static let identifier = "TableViewCell"
private let leadingImageView: UIImageView = {
let view = UIImageView(image: UIImage(systemName: "calendar"))
view.setConstraints(heightConstant: 25, widthConstant: 25)
view.tintColor = .text
return view
}()
private let leadingLabel: UILabel = {
let label = UILabel()
label.textColor = .label
label.text = "Start Date"
label.numberOfLines = 0
label.sizeToFit()
return label
}()
let trailingLabel: UILabel = {
let label = UILabel()
label.text = "Friday, 17 July 2020"
label.textColor = .label
label.numberOfLines = 0
label.textAlignment = .right
return label
}()
let trailingImageView: UIImageView = {
let configuration = UIImage.SymbolConfiguration(pointSize: 12, weight: .light)
let image = UIImage(systemName: "arrowtriangle.down", withConfiguration: configuration)
let view = UIImageView(image: image)
return view
}()
private let superStackView: UIStackView = {
let view = UIStackView()
view.distribution = .fillProportionally
view.alignment = .center
view.spacing = 16
return view
}()
private let containerView: UIView = {
let view = UIView()
view.setContentHuggingPriority(.defaultHigh, for: .horizontal)
view.setContentHuggingPriority(.defaultHigh, for: .vertical)
return view
}()
override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) {
super.init(style: style, reuseIdentifier: reuseIdentifier)
setUpSubviews()
}
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
}
}
extension TableViewCell {
private func setUpSubviews(){
containerView.addSubview(trailingImageView)
trailingImageView.alignCenter(centerXAnchor: containerView.centerXAnchor,
centerYAnchor: containerView.centerYAnchor)
superStackView.addArrangedSubview(leadingImageView)
superStackView.addArrangedSubview(leadingLabel)
superStackView.addArrangedSubview(trailingLabel)
superStackView.addArrangedSubview(containerView)
let constant = CGFloat(16)
self.addSubview(superStackView)
self.contentView.addSubview(superStackView)
superStackView.setConstraints(topAnchor: contentView.topAnchor, leadingAnchor: contentView.leadingAnchor,
bottomAnchor: contentView.bottomAnchor, trailingAnchor: contentView.trailingAnchor,
topConstant: constant, leadingConstant: constant, bottomConstant: constant, trailingConstant: constant)
self.contentView.updateConstraints()
}
}
如何解决这个问题,使单元格看起来像下图中的单元格?
尝试Return 1
let trailingLabel: UILabel = {
let label = UILabel()
label.text = "Friday, 17 July 2020"
label.textColor = .label
label.numberOfLines = 1
label.textAlignment = .right
return label
}()
你很接近...
首先,将堆栈视图的分布设置为 Fill Proportionally
是最容易被误解的分布选项,您不想在这里使用它。
其次,在设计时使用对比色背景非常有帮助,可以很容易地看到您的框架在做什么。
这是您的代码,经过修改以达到您的目标。我没有您的“约束助手”,所以我将其更改为标准约束格式。我还添加了一些评论以进行澄清:
class TableViewCell: UITableViewCell {
static let identifier = "TableViewCell"
private let leadingImageView: UIImageView = {
let view = UIImageView(image: UIImage(systemName: "calendar"))
view.translatesAutoresizingMaskIntoConstraints = false
//view.setConstraints(heightConstant: 25, widthConstant: 25)
view.widthAnchor.constraint(equalToConstant: 25).isActive = true
view.heightAnchor.constraint(equalToConstant: 25).isActive = true
view.tintColor = .blue // .text
return view
}()
private let leadingLabel: UILabel = {
let label = UILabel()
label.textColor = .label
label.text = "Start Date"
// only single line for "leading label"
label.numberOfLines = 1
// content hugging
label.setContentHuggingPriority(.required, for: .horizontal)
label.backgroundColor = .cyan
return label
}()
let trailingLabel: UILabel = {
let label = UILabel()
label.text = "Friday, 17 July 2020"
label.textColor = .label
label.numberOfLines = 0
label.textAlignment = .right
label.backgroundColor = .green
return label
}()
let trailingImageView: UIImageView = {
let configuration = UIImage.SymbolConfiguration(pointSize: 12, weight: .light)
let image = UIImage(systemName: "arrowtriangle.down", withConfiguration: configuration)
let view = UIImageView(image: image)
return view
}()
private let superStackView: UIStackView = {
let view = UIStackView()
view.translatesAutoresizingMaskIntoConstraints = false
// do NOT use .fillProportionally
view.distribution = .fill
view.alignment = .center
view.spacing = 16
return view
}()
private let containerView: UIView = {
let view = UIView()
// not needed
//view.setContentHuggingPriority(.defaultHigh, for: .horizontal)
//view.setContentHuggingPriority(.defaultHigh, for: .vertical)
return view
}()
override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) {
super.init(style: style, reuseIdentifier: reuseIdentifier)
setUpSubviews()
}
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
}
}
extension TableViewCell {
private func setUpSubviews(){
containerView.addSubview(trailingImageView)
//trailingImageView.alignCenter(centerXAnchor: containerView.centerXAnchor,
// centerYAnchor: containerView.centerYAnchor)
superStackView.addArrangedSubview(leadingImageView)
superStackView.addArrangedSubview(leadingLabel)
superStackView.addArrangedSubview(trailingLabel)
superStackView.addArrangedSubview(containerView)
let constant = CGFloat(16)
self.addSubview(superStackView)
self.contentView.addSubview(superStackView)
//superStackView.setConstraints(topAnchor: contentView.topAnchor, leadingAnchor: contentView.leadingAnchor,
// bottomAnchor: contentView.bottomAnchor, trailingAnchor: contentView.trailingAnchor,
// topConstant: constant, leadingConstant: constant, bottomConstant: constant, trailingConstant: constant)
NSLayoutConstraint.activate([
trailingImageView.centerXAnchor.constraint(equalTo: containerView.centerXAnchor),
trailingImageView.centerYAnchor.constraint(equalTo: containerView.centerYAnchor),
superStackView.topAnchor.constraint(equalTo: contentView.topAnchor, constant: constant),
superStackView.leadingAnchor.constraint(equalTo: contentView.leadingAnchor, constant: constant),
superStackView.trailingAnchor.constraint(equalTo: contentView.trailingAnchor, constant: -constant),
superStackView.bottomAnchor.constraint(equalTo: contentView.bottomAnchor, constant: -constant),
])
// not needed
//self.contentView.updateConstraints()
}
}
还有一个示例视图控制器:
class MahanTableViewController: UITableViewController {
var myData: [String] = [
"Saturday, 18 July 2020",
"Sunday, 19 July 2020",
"Wednesday, 22 July 2020",
"Saturday, 26 September 2020",
"Sunday, 27 September 2020",
"Wednesday, 30 September 2020",
]
override func viewDidLoad() {
super.viewDidLoad()
tableView.register(TableViewCell.self, forCellReuseIdentifier: TableViewCell.identifier)
}
// MARK: - Table view data source
override func numberOfSections(in tableView: UITableView) -> Int {
return 1
}
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return myData.count
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: TableViewCell.identifier, for: indexPath) as! TableViewCell
cell.trailingLabel.text = myData[indexPath.row]
return cell
}
}
生成此输出: