我正在努力解决一些基本的UIStackView分发和对齐问题。
我有一个UICollectionViewCell,它在contentView子视图中有一个水平的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发行版,限制了“时间标签”以及“标题标签”的拥抱优先级。
但无论如何我无法做对。任何提示?
答案 0 :(得分:1)
由于您正在设置titleLabel.numberOfLines = 3
,因此一种方法是在标题文字中添加三个换行符。这将迫使titleLabel
始终消耗其三行全高,迫使timeLabel
到底。 p>
也就是说,当您设置titleLabel.text
时,请执行以下操作:
titleLabel.text = theTitle + "\n\n\n"
如果让其中一个标签垂直拉伸,拉伸标签的文本将在拉伸标签的边界内垂直居中,这不是您想要的。所以我们不能让标签垂直伸展。因此,我们需要引入一个可以拉伸但不可见的填充视图。
如果填充视图被压缩到零高度,堆栈视图仍然会在它之前和之后放置间距,导致titleLabel
和timeLabel
之间的双倍间距,你也不会这样做。 ;想要。
因此我们需要使用填充视图实现所有间距。将verticalStackView.spacing
更改为0。
在UIView
之后padding1
之后,将名为verticalStackView
的通用categoryLabel
添加到titleLabel
。将其高度限制为等于10.
在UIView
之后padding2
之后,将名为verticalStackView
的通用titleLabel
添加到timeLabel
。将其高度限制在大于或等于10,以便它可以伸展。
将categoryLabel
,titleLabel
和timeLabel
的垂直拥抱优先级设置为必需,以便它们不会垂直拉伸。
将verticalStackView
的高度约束到containerStackView
的高度,以便在需要填充可用的垂直空间时拉伸其中一个或多个已排列的子视图。唯一可以拉伸的子视图是padding2
,因此它会拉伸,使标题文本靠近顶部,时间文本保持在底部。
另外,将containerStackView
限制在contentView
的边界并设置containerStackView.translatesAutoresizingMaskIntoConstraints = false
。
结果:
这是我的游乐场:
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
答案 1 :(得分:0)
问题是垂直堆栈视图。你显然想说:中间标签的顶部应该拥抱MyCustomLabel底部,但3天前底部应该拥抱整体底部。这不是你可以对堆栈视图说的。
即使这不是您想要说的,您仍然需要使垂直堆栈视图占据单元格的整个高度,您将如何做到这一点?在您展示的代码中,您根本不会这样做;实际上,您的堆栈视图基于该代码具有零大小,这将导致各种问题。
因此,我建议您只需删除所有堆栈视图,然后直接配置布局。您的布局很容易使用自动布局约束进行配置。