UIStackView :破坏了内部子视图的约束
UIStackView : broken constraints for internal subviews
我在 UIScrollView 中有一个 UIStackView 和一个简单的视图,如下所示:
class OnboardingView : UIView {
private let onboardingImageView : UIImageView = {
let view = UIImageView()
view.translatesAutoresizingMaskIntoConstraints = false
view.contentMode = .scaleAspectFit
view.layer.cornerRadius = 8
view.image = UIImage(named: "OnboardingImage")
return view
}()
private lazy var scrollView: UIScrollView = {
let view = UIScrollView()
view.translatesAutoresizingMaskIntoConstraints = false
view.showsVerticalScrollIndicator = false
view.showsHorizontalScrollIndicator = false
return view
}()
private lazy var scrollViewContainer: UIStackView = {
let view = UIStackView()
view.axis = .vertical
view.spacing = 0
view.distribution = .fillProportionally
view.translatesAutoresizingMaskIntoConstraints = false
return view
}()
private let imageArea : UIView = {
let view = UIView()
view.translatesAutoresizingMaskIntoConstraints = false
return view
}()
private func setupScrollView()
{
let constraints = [
scrollView.leadingAnchor.constraint(equalTo: self.safeAreaLayoutGuide.leadingAnchor),
scrollView.trailingAnchor.constraint(equalTo: self.safeAreaLayoutGuide.trailingAnchor),
scrollView.topAnchor.constraint(equalTo: self.safeAreaLayoutGuide.topAnchor),
scrollView.bottomAnchor.constraint(equalTo: self.safeAreaLayoutGuide.bottomAnchor),
scrollViewContainer.leadingAnchor.constraint(equalTo: scrollView.leadingAnchor),
scrollViewContainer.trailingAnchor.constraint(equalTo: scrollView.trailingAnchor),
scrollViewContainer.topAnchor.constraint(equalTo: scrollView.topAnchor),
scrollViewContainer.bottomAnchor.constraint(equalTo: scrollView.bottomAnchor),
scrollViewContainer.widthAnchor.constraint(equalTo: scrollView.widthAnchor),
]
NSLayoutConstraint.activate(constraints)
}
private func setupAreas()
{
let constraints = [
imageArea.heightAnchor.constraint(equalToConstant: 400)
]
NSLayoutConstraint.activate(constraints)
}
private func setupImage()
{
imageArea.addSubview(onboardingImageView)
let constraints = [
onboardingImageView.topAnchor.constraint(equalTo: imageArea.topAnchor, constant: 62),
onboardingImageView.heightAnchor.constraint(equalToConstant: 334),
onboardingImageView.leadingAnchor.constraint(equalTo: imageArea.leadingAnchor, constant: 35.5),
onboardingImageView.trailingAnchor.constraint(equalTo: imageArea.trailingAnchor, constant : -35),
]
NSLayoutConstraint.activate(constraints)
}
private func setupLayout()
{
self.addSubview(scrollView)
scrollView.addSubview(scrollViewContainer)
scrollViewContainer.addArrangedSubview(imageArea)
setupScrollView()
setupAreas()
setupImage()
}
private func setupViews()
{
self.layer.backgroundColor = UIColor(red : 0.125, green: 0.306, blue: 0.78, alpha: 1).cgColor
setupLayout()
}
init(viewFrame : CGRect) {
super.init(frame: viewFrame)
setupViews()
}
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented for OnboardingView")
}
}
如果我为嵌套视图设置一些约束,我会在控制台中收到约束错误提示:
(
"<NSLayoutConstraint:0x600003efa440 H:|-(35.5)-[UIImageView:0x15110c090] (active, names: '|':UIView:0x14fd086d0 )>",
"<NSLayoutConstraint:0x600003efa490 UIImageView:0x15110c090.trailing == UIView:0x14fd086d0.trailing - 35 (active)>",
"<NSLayoutConstraint:0x600003ed6030 'fittingSizeHTarget' UIView:0x14fd086d0.width == 0 (active)>"
)
Will attempt to recover by breaking constraint
<NSLayoutConstraint:0x600003efa490 UIImageView:0x15110c090.trailing == UIView:0x14fd086d0.trailing - 35 (active)>
我无法整理。当我将约束应用于 UIStackView 的 arrangedView(imageArea
) 项时,我不清楚会出现什么问题,所以从我的角度来看应该没问题。我错过了什么?我该如何解决?
你的约束没问题。
由于您的 UIStackView
对其子视图使用 fillProportionally
,因此它从子视图读取 intrinsicContentSize
。
// you can override and return non zero value to fix it
class SubView: UIView {
override var intrinsicContentSize: CGSize {
return CGSize(width: 1, height: 1)
}
}
private let imageArea : UIView = {
let view = SubView()
return view
}
scrollViewContainer.addArrangedSubview(imageArea)
或
// Set lower priority witch one is breaking (here 35 or -35 any one)
private func setupImage() {
imageArea.addSubview(onboardingImageView)
let constraints = [
onboardingImageView.topAnchor.constraint(equalTo: imageArea.topAnchor, constant: 62),
onboardingImageView.heightAnchor.constraint(equalToConstant: 334),
onboardingImageView.leadingAnchor.constraint(equalTo: imageArea.leadingAnchor, constant: 35.5),
onboardingImageView.trailingAnchor.constraint(equalTo: imageArea.trailingAnchor, constant : -35),
]
constraints.last?.priority = .init(990)
NSLayoutConstraint.activate(constraints)
}
我在 UIScrollView 中有一个 UIStackView 和一个简单的视图,如下所示:
class OnboardingView : UIView {
private let onboardingImageView : UIImageView = {
let view = UIImageView()
view.translatesAutoresizingMaskIntoConstraints = false
view.contentMode = .scaleAspectFit
view.layer.cornerRadius = 8
view.image = UIImage(named: "OnboardingImage")
return view
}()
private lazy var scrollView: UIScrollView = {
let view = UIScrollView()
view.translatesAutoresizingMaskIntoConstraints = false
view.showsVerticalScrollIndicator = false
view.showsHorizontalScrollIndicator = false
return view
}()
private lazy var scrollViewContainer: UIStackView = {
let view = UIStackView()
view.axis = .vertical
view.spacing = 0
view.distribution = .fillProportionally
view.translatesAutoresizingMaskIntoConstraints = false
return view
}()
private let imageArea : UIView = {
let view = UIView()
view.translatesAutoresizingMaskIntoConstraints = false
return view
}()
private func setupScrollView()
{
let constraints = [
scrollView.leadingAnchor.constraint(equalTo: self.safeAreaLayoutGuide.leadingAnchor),
scrollView.trailingAnchor.constraint(equalTo: self.safeAreaLayoutGuide.trailingAnchor),
scrollView.topAnchor.constraint(equalTo: self.safeAreaLayoutGuide.topAnchor),
scrollView.bottomAnchor.constraint(equalTo: self.safeAreaLayoutGuide.bottomAnchor),
scrollViewContainer.leadingAnchor.constraint(equalTo: scrollView.leadingAnchor),
scrollViewContainer.trailingAnchor.constraint(equalTo: scrollView.trailingAnchor),
scrollViewContainer.topAnchor.constraint(equalTo: scrollView.topAnchor),
scrollViewContainer.bottomAnchor.constraint(equalTo: scrollView.bottomAnchor),
scrollViewContainer.widthAnchor.constraint(equalTo: scrollView.widthAnchor),
]
NSLayoutConstraint.activate(constraints)
}
private func setupAreas()
{
let constraints = [
imageArea.heightAnchor.constraint(equalToConstant: 400)
]
NSLayoutConstraint.activate(constraints)
}
private func setupImage()
{
imageArea.addSubview(onboardingImageView)
let constraints = [
onboardingImageView.topAnchor.constraint(equalTo: imageArea.topAnchor, constant: 62),
onboardingImageView.heightAnchor.constraint(equalToConstant: 334),
onboardingImageView.leadingAnchor.constraint(equalTo: imageArea.leadingAnchor, constant: 35.5),
onboardingImageView.trailingAnchor.constraint(equalTo: imageArea.trailingAnchor, constant : -35),
]
NSLayoutConstraint.activate(constraints)
}
private func setupLayout()
{
self.addSubview(scrollView)
scrollView.addSubview(scrollViewContainer)
scrollViewContainer.addArrangedSubview(imageArea)
setupScrollView()
setupAreas()
setupImage()
}
private func setupViews()
{
self.layer.backgroundColor = UIColor(red : 0.125, green: 0.306, blue: 0.78, alpha: 1).cgColor
setupLayout()
}
init(viewFrame : CGRect) {
super.init(frame: viewFrame)
setupViews()
}
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented for OnboardingView")
}
}
如果我为嵌套视图设置一些约束,我会在控制台中收到约束错误提示:
(
"<NSLayoutConstraint:0x600003efa440 H:|-(35.5)-[UIImageView:0x15110c090] (active, names: '|':UIView:0x14fd086d0 )>",
"<NSLayoutConstraint:0x600003efa490 UIImageView:0x15110c090.trailing == UIView:0x14fd086d0.trailing - 35 (active)>",
"<NSLayoutConstraint:0x600003ed6030 'fittingSizeHTarget' UIView:0x14fd086d0.width == 0 (active)>"
)
Will attempt to recover by breaking constraint
<NSLayoutConstraint:0x600003efa490 UIImageView:0x15110c090.trailing == UIView:0x14fd086d0.trailing - 35 (active)>
我无法整理。当我将约束应用于 UIStackView 的 arrangedView(imageArea
) 项时,我不清楚会出现什么问题,所以从我的角度来看应该没问题。我错过了什么?我该如何解决?
你的约束没问题。
由于您的 UIStackView
对其子视图使用 fillProportionally
,因此它从子视图读取 intrinsicContentSize
。
// you can override and return non zero value to fix it
class SubView: UIView {
override var intrinsicContentSize: CGSize {
return CGSize(width: 1, height: 1)
}
}
private let imageArea : UIView = {
let view = SubView()
return view
}
scrollViewContainer.addArrangedSubview(imageArea)
或
// Set lower priority witch one is breaking (here 35 or -35 any one)
private func setupImage() {
imageArea.addSubview(onboardingImageView)
let constraints = [
onboardingImageView.topAnchor.constraint(equalTo: imageArea.topAnchor, constant: 62),
onboardingImageView.heightAnchor.constraint(equalToConstant: 334),
onboardingImageView.leadingAnchor.constraint(equalTo: imageArea.leadingAnchor, constant: 35.5),
onboardingImageView.trailingAnchor.constraint(equalTo: imageArea.trailingAnchor, constant : -35),
]
constraints.last?.priority = .init(990)
NSLayoutConstraint.activate(constraints)
}