带有 UIImageView 的 UIStackView 没有按预期处理约束
UIStackView with UIImageView doesn't handle constraint as expected
我有一个 UIStackView(水平)addArrangedSubview 到一个 UIStackView(垂直)。
水平视图有 3 个单元格:第一个是带有 UILabel 的 addArrangedSubview,第二个是 UIImageView(具有宽度和高度恒定约束以保持我想要的大小)。第三个单元格是带有 UILabel 的 addArrangedSubview。
我希望 UIStackView 适合整个屏幕宽度
不幸的是,结果拉伸如下:
我的代码如下:
let sv = UIStackView()
sv.axis = .horizontal
sv.alignment = .center
sv.distribution = .fill
sv.spacing = 10
// Name
var label = UILabel()
label.numberOfLines = 0
label.textAlignment = .natural
label.text = poi.name
label.font = UIFont.preferredFont(forTextStyle: .title1)
sv.addArrangedSubview(label)
// Open/closed
let open = true
let _ = addImageView(open ? #imageLiteral(resourceName: "Open") : #imageLiteral(resourceName: "Closed"), to: sv)
// Stars
let maxRank = 5
let rank = 3
label = UILabel()
label.numberOfLines = 0
label.textAlignment = .natural
label.text = "".padding(right: rank, withPad: "★").padding(right: maxRank-rank, withPad: "☆")
sv.addArrangedSubview(label)
verticalStackView.addArrangedSubview(sv)
而我的工具功能如下:
let w: CGFloat = 32.0
let r = CGRect(x: 0, y: 0, width: w, height: w)
func addImageView(_ image: UIImage, to sv: UIStackView) {
let iv = UIImageView()
iv.contentMode = .scaleAspectFit
iv.image = image
//iv.translatesAutoresizingMaskIntoConstraints = true
let constraints = [
iv.widthAnchor .constraint(equalToConstant: w),
iv.heightAnchor.constraint(equalToConstant: w)
]
//let _ = constraints.map { [=11=].priority = .defaultHigh }
NSLayoutConstraint.activate(constraints)
/*
iv.setContentCompressionResistancePriority(UILayoutPriority(rawValue: 1000.0), for: .horizontal)
iv.setContentCompressionResistancePriority(UILayoutPriority(rawValue: 1000.0), for: .vertical)
*/
if true {
sv.addArrangedSubview(iv)
} else {
let v = UIView()
v.layer.borderColor = UIColor.red.cgColor
v.layer.borderWidth = 1
v.addSubview(iv)
sv.addArrangedSubview(v)
}
}
注意 1:我做了一些实验,因此注释了代码。
注2:屏幕截图中的红色条是我手绘的,以便于理解单元格的布局。
[更新]
为了解决问题,让一切变得混乱的是我添加到 UIImageView 的约束,加上 none,一切正常。我添加约束的原因是为了使 UIImageView 保持正方形并保持正确的尺寸。
出于这个原因,我添加了一个 UIView 作为 in-between 元素,以吸收 UIStackView 约束设置到内部元素的强度(因此是 if false 代码)。但是我需要在 UIView 中添加额外的约束以使 UIImageView 居中,这听起来有点过度使用布局系统。当然
我可能错过了一些简化整个事情的东西。
你能
- 尝试为 Root-StackView 添加约束,尾随、顶部、底部和前导等于常量 0。
- 尝试使用 .fill 而不是 .center 更改 Root-StackView 的对齐方式。
- 如果你想让标签更灵活,使压缩阻力和上下文拥抱 属性 的值(通常为 248、748)比其他值(251、250、750)小得多。
谢谢,
J
我终于解决了这个问题:我将标签和 UIImageView 的阻力压缩优先级更改为 .required:
label.setContentCompressionResistancePriority(UILayoutPriority.required, for: .horizontal)
同一段代码现在如下所示:
// Name
var label = UILabel()
label.numberOfLines = 0
label.textAlignment = .natural
label.text = poi.name
label.font = UIFont.preferredFont(forTextStyle: .title1)
label.setContentCompressionResistancePriority(UILayoutPriority.required, for: .horizontal)
sv.addArrangedSubview(label)
// Open/closed
let open = true
let _ = addImageView(open ? #imageLiteral(resourceName: "Open") : #imageLiteral(resourceName: "Closed"), to: sv)
// Stars
let maxRank = 5
let rank = 3
label = UILabel()
label.numberOfLines = 0
label.textAlignment = .natural
label.text = "".padding(right: rank, withPad: "★").padding(right: maxRank-rank, withPad: "☆")
label.setContentCompressionResistancePriority(UILayoutPriority.required, for: .horizontal)
sv.addArrangedSubview(label)
verticalStackView.addArrangedSubview(sv)
并且:
func addImageView(_ image: UIImage, to sv: UIStackView) {
let iv = UIImageView()
iv.contentMode = .scaleAspectFit
iv.image = image
NSLayoutConstraint.activate([
iv.widthAnchor .constraint(equalToConstant: w),
iv.heightAnchor.constraint(equalToConstant: w)
])
iv.setContentCompressionResistancePriority(UILayoutPriority.required, for: .horizontal)
iv.setContentCompressionResistancePriority(UILayoutPriority.required, for: .vertical)
sv.addArrangedSubview(iv)
}
我有一个 UIStackView(水平)addArrangedSubview 到一个 UIStackView(垂直)。
水平视图有 3 个单元格:第一个是带有 UILabel 的 addArrangedSubview,第二个是 UIImageView(具有宽度和高度恒定约束以保持我想要的大小)。第三个单元格是带有 UILabel 的 addArrangedSubview。 我希望 UIStackView 适合整个屏幕宽度
不幸的是,结果拉伸如下:
我的代码如下:
let sv = UIStackView()
sv.axis = .horizontal
sv.alignment = .center
sv.distribution = .fill
sv.spacing = 10
// Name
var label = UILabel()
label.numberOfLines = 0
label.textAlignment = .natural
label.text = poi.name
label.font = UIFont.preferredFont(forTextStyle: .title1)
sv.addArrangedSubview(label)
// Open/closed
let open = true
let _ = addImageView(open ? #imageLiteral(resourceName: "Open") : #imageLiteral(resourceName: "Closed"), to: sv)
// Stars
let maxRank = 5
let rank = 3
label = UILabel()
label.numberOfLines = 0
label.textAlignment = .natural
label.text = "".padding(right: rank, withPad: "★").padding(right: maxRank-rank, withPad: "☆")
sv.addArrangedSubview(label)
verticalStackView.addArrangedSubview(sv)
而我的工具功能如下:
let w: CGFloat = 32.0
let r = CGRect(x: 0, y: 0, width: w, height: w)
func addImageView(_ image: UIImage, to sv: UIStackView) {
let iv = UIImageView()
iv.contentMode = .scaleAspectFit
iv.image = image
//iv.translatesAutoresizingMaskIntoConstraints = true
let constraints = [
iv.widthAnchor .constraint(equalToConstant: w),
iv.heightAnchor.constraint(equalToConstant: w)
]
//let _ = constraints.map { [=11=].priority = .defaultHigh }
NSLayoutConstraint.activate(constraints)
/*
iv.setContentCompressionResistancePriority(UILayoutPriority(rawValue: 1000.0), for: .horizontal)
iv.setContentCompressionResistancePriority(UILayoutPriority(rawValue: 1000.0), for: .vertical)
*/
if true {
sv.addArrangedSubview(iv)
} else {
let v = UIView()
v.layer.borderColor = UIColor.red.cgColor
v.layer.borderWidth = 1
v.addSubview(iv)
sv.addArrangedSubview(v)
}
}
注意 1:我做了一些实验,因此注释了代码。
注2:屏幕截图中的红色条是我手绘的,以便于理解单元格的布局。
[更新]
为了解决问题,让一切变得混乱的是我添加到 UIImageView 的约束,加上 none,一切正常。我添加约束的原因是为了使 UIImageView 保持正方形并保持正确的尺寸。 出于这个原因,我添加了一个 UIView 作为 in-between 元素,以吸收 UIStackView 约束设置到内部元素的强度(因此是 if false 代码)。但是我需要在 UIView 中添加额外的约束以使 UIImageView 居中,这听起来有点过度使用布局系统。当然 我可能错过了一些简化整个事情的东西。
你能 - 尝试为 Root-StackView 添加约束,尾随、顶部、底部和前导等于常量 0。 - 尝试使用 .fill 而不是 .center 更改 Root-StackView 的对齐方式。
- 如果你想让标签更灵活,使压缩阻力和上下文拥抱 属性 的值(通常为 248、748)比其他值(251、250、750)小得多。
谢谢, J
我终于解决了这个问题:我将标签和 UIImageView 的阻力压缩优先级更改为 .required:
label.setContentCompressionResistancePriority(UILayoutPriority.required, for: .horizontal)
同一段代码现在如下所示:
// Name
var label = UILabel()
label.numberOfLines = 0
label.textAlignment = .natural
label.text = poi.name
label.font = UIFont.preferredFont(forTextStyle: .title1)
label.setContentCompressionResistancePriority(UILayoutPriority.required, for: .horizontal)
sv.addArrangedSubview(label)
// Open/closed
let open = true
let _ = addImageView(open ? #imageLiteral(resourceName: "Open") : #imageLiteral(resourceName: "Closed"), to: sv)
// Stars
let maxRank = 5
let rank = 3
label = UILabel()
label.numberOfLines = 0
label.textAlignment = .natural
label.text = "".padding(right: rank, withPad: "★").padding(right: maxRank-rank, withPad: "☆")
label.setContentCompressionResistancePriority(UILayoutPriority.required, for: .horizontal)
sv.addArrangedSubview(label)
verticalStackView.addArrangedSubview(sv)
并且:
func addImageView(_ image: UIImage, to sv: UIStackView) {
let iv = UIImageView()
iv.contentMode = .scaleAspectFit
iv.image = image
NSLayoutConstraint.activate([
iv.widthAnchor .constraint(equalToConstant: w),
iv.heightAnchor.constraint(equalToConstant: w)
])
iv.setContentCompressionResistancePriority(UILayoutPriority.required, for: .horizontal)
iv.setContentCompressionResistancePriority(UILayoutPriority.required, for: .vertical)
sv.addArrangedSubview(iv)
}