我正在努力解决一些基本的 UIStackView 分布和对齐问题。
我有一个 UICollectionViewCell,它在 contentView subview 上有一个水平的 UIStackView。这个 UIStackView 有一个用于三个标签本身的垂直 UIStackView,当然还有 UIImageView。
这是下面截图的代码片段:
func createSubViews() {
// contains the UIStackview with the 3 labels and the UIImageView
containerStackView = UIStackView()
containerStackView.axis = .horizontal
containerStackView.distribution = .fill
containerStackView.alignment = .top
contentView.addSubview(containerStackView)
// the UIStackView for the labels
verticalStackView = UIStackView()
verticalStackView.axis = .vertical
verticalStackView.distribution = .fill
verticalStackView.spacing = 10.0
containerStackView.addArrangedSubview(verticalStackView)
categoryLabel = UILabel()
categoryLabel.font = UIFont.preferredFont(forTextStyle: .caption1)
categoryLabel.textColor = UIColor.lightGray
verticalStackView.addArrangedSubview(categoryLabel)
titleLabel = UILabel()
titleLabel.numberOfLines = 3
titleLabel.lineBreakMode = .byWordWrapping
verticalStackView.addArrangedSubview(titleLabel)
timeLabel = UILabel()
timeLabel.font = UIFont.preferredFont(forTextStyle: .caption1)
timeLabel.textColor = UIColor.lightGray
verticalStackView.addArrangedSubview(timeLabel)
// UIImageView
imageView = UIImageView()
imageView.contentMode = .scaleAspectFill
imageView.clipsToBounds = true
imageView.layer.cornerRadius = 5
layer.masksToBounds = true
containerStackView.addArrangedSubview(imageView)
}
我想要实现的是,“时间标签”(“3 天前”)始终位于每个 UICollectionViewCell 的底部(与 UIImageView 的底部对齐),而不管不同的标题标签行。
我玩过各种 UIStackView 分布,限制“时间标签”和“标题标签”的拥抱优先级。
但无论如何我做对不了。有什么提示吗?
最佳答案
更新
由于您正在设置 titleLabel.numberOfLines = 3
,因此一种方法是在标题文本中添加三个换行符。这将强制 titleLabel
始终占据其三行的完整高度,从而迫使 timeLabel
位于底部。
也就是说,当你设置titleLabel.text
时,这样做:
titleLabel.text = theTitle + "\n\n\n"
原创
如果让其中一个标签垂直拉伸(stretch),拉伸(stretch)标签的文本将在拉伸(stretch)标签的边界内垂直居中,这不是您想要的。所以我们不能让标签垂直拉伸(stretch)。因此,我们需要引入一个可以拉伸(stretch)但不可见的填充 View 。
如果 padding view 被压缩到零高度,stack view 仍然会在它前后放置间距,导致 titleLabel
和 timeLabel
之间的双倍间距,你也不想要。
因此我们需要使用填充 View 来实现所有间距。将 verticalStackView.spacing
更改为 0。
在 categoryLabel
之后,titleLabel
之前,将一个名为 padding1
的通用 UIView
添加到 verticalStackView
>。将其高度限制为 10。
在 titleLabel
之后,timeLabel
之前,将一个名为 padding2
的通用 UIView
添加到 verticalStackView
>。将其高度限制为大于或等于 10,以便它可以拉伸(stretch)。
将categoryLabel
、titleLabel
和timeLabel
的垂直拥抱优先级设置为required,使其不会垂直拉伸(stretch)。
将 verticalStackView
的高度限制为 containerStackView
的高度,以便它在需要时拉伸(stretch)一个或多个已排列的 subview 以填充可用的垂直空间。唯一可以拉伸(stretch)的排列 subview 是 padding2
,因此它会拉伸(stretch),将标题文本保持在顶部附近,将时间文本保持在底部。
此外,将您的 containerStackView
限制在 contentView
的范围内并设置 containerStackView.translatesAutoresizingMaskIntoConstraints = false
。
结果:
这是我的 Playground :
import UIKit
import PlaygroundSupport
class MyCell: UICollectionViewCell {
var containerStackView: UIStackView!
var verticalStackView: UIStackView!
var categoryLabel: UILabel!
var titleLabel: UILabel!
var timeLabel: UILabel!
var imageView: UIImageView!
func createSubViews() {
// contains the UIStackview with the 3 labels and the UIImageView
containerStackView = UIStackView()
containerStackView.axis = .horizontal
containerStackView.distribution = .fill
containerStackView.alignment = .top
contentView.addSubview(containerStackView)
// the UIStackView for the labels
verticalStackView = UIStackView()
verticalStackView.axis = .vertical
verticalStackView.distribution = .fill
verticalStackView.spacing = 0
containerStackView.addArrangedSubview(verticalStackView)
categoryLabel = UILabel()
categoryLabel.font = UIFont.preferredFont(forTextStyle: .caption1)
categoryLabel.textColor = UIColor.lightGray
verticalStackView.addArrangedSubview(categoryLabel)
let padding1 = UIView()
verticalStackView.addArrangedSubview(padding1)
titleLabel = UILabel()
titleLabel.numberOfLines = 3
titleLabel.lineBreakMode = .byWordWrapping
verticalStackView.addArrangedSubview(titleLabel)
let padding2 = UIView()
verticalStackView.addArrangedSubview(padding2)
timeLabel = UILabel()
timeLabel.font = UIFont.preferredFont(forTextStyle: .caption1)
timeLabel.textColor = UIColor.lightGray
verticalStackView.addArrangedSubview(timeLabel)
// UIImageView
imageView = UIImageView()
imageView.contentMode = .scaleAspectFill
imageView.clipsToBounds = true
imageView.layer.cornerRadius = 5
layer.masksToBounds = true
containerStackView.addArrangedSubview(imageView)
categoryLabel.setContentHuggingPriority(.required, for: .vertical)
titleLabel.setContentHuggingPriority(.required, for: .vertical)
timeLabel.setContentHuggingPriority(.required, for: .vertical)
imageView.setContentHuggingPriority(.defaultHigh, for: .horizontal)
containerStackView.translatesAutoresizingMaskIntoConstraints = false
NSLayoutConstraint.activate([
contentView.leadingAnchor.constraint(equalTo: containerStackView.leadingAnchor),
contentView.trailingAnchor.constraint(equalTo: containerStackView.trailingAnchor),
contentView.topAnchor.constraint(equalTo: containerStackView.topAnchor),
contentView.bottomAnchor.constraint(equalTo: containerStackView.bottomAnchor),
verticalStackView.heightAnchor.constraint(equalTo: containerStackView.heightAnchor),
padding1.heightAnchor.constraint(equalToConstant: 10),
padding2.heightAnchor.constraint(greaterThanOrEqualToConstant: 10),
])
}
}
let cell = MyCell(frame: CGRect(x: 0, y: 0, width: 320, height: 110))
cell.backgroundColor = .white
cell.createSubViews()
cell.categoryLabel.text = "MY CUSTOM LABEL"
cell.titleLabel.text = "This is my title"
cell.timeLabel.text = "3 days ago"
cell.imageView.image = UIGraphicsImageRenderer(size: CGSize(width: 110, height:110)).image { (context) in
UIColor.blue.set()
UIRectFill(.infinite)
}
PlaygroundPage.current.liveView = cell
关于ios - 多行 UILabel 的 UIStackView 分布和对齐,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/49413584/