Q. 如何在 stackview、UIKit 中为每个视图设置不同的约束? 我想让屏幕像捕获的那样。
在下面的代码中,结果是好的。但 我有错误无法同时满足约束...
在问答之前我学习了StackView。但该屏幕具有相同的限制。就像之前写的那样,我设置了约束,例如
titleLabel.leadingAnchor.constraint(equalTo: scrollView.contentLayoutGuide.trailingAnchor, constant: 20)
...
所以,我尝试过失败的原因https://www.wtfautolayout.com/,答案是为每个视图设置0个约束。现在我写了这个问题。感谢您的阅读。
import UIKit
class DetailViewController: UIViewController {
@IBOutlet var centerNavtigationItems: UINavigationItem!
private let titleLabel: UILabel = {
let titleLabel = UILabel()
titleLabel.numberOfLines = 2
titleLabel.textAlignment = .left
titleLabel.font = UIFont(name: "Pretendard-SemiBold", size: 24)
titleLabel.backgroundColor = .yellow
return titleLabel
}()
private let dateLabel: UILabel = {
let view = UILabel()
view.textAlignment = .right
view.font = UIFont(name: "Pretendard-Light", size: 16)
view.textColor = .gray
return view
}()
private let scrollView: UIScrollView = {
let view = UIScrollView()
return view
}()
private let imageContainer: UIImageView = {
let ic = UIImageView()
return ic
}()
private let pageController: UIPageControl = {
let controller = UIPageControl()
controller.pageIndicatorTintColor = .gray
controller.currentPageIndicatorTintColor = .darkGray
return controller
}()
private let contentTextView: UILabel = {
let content = UILabel()
content.numberOfLines = 0
content.font = UIFont(name: "Pretendard-Regular", size: 18)
return content
}()
var fileName: String!
var id: String!
var entryNumber: Int!
var dataSize: Int!
var entry: Entry!
var imageNames: [String] = []
var imageIndex: Int = 0
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
// Get contents id and parse file name
parsingFileName(id: id)
let dateText = String(entry.year) + "." + String(entry.month) + "." + String(entry.day)
centerNavtigationItems.title = dateText
titleLabel.text = entry.title
dateLabel.text = dateText
// Add Image to an Array
// If an image doesn't exist, then set empty array, and make hide UIImageView ... (1)
if entry.isImage == true {
for e in entry.imageName {
imageNames.append(String(e + ".jpeg"))
}
pageController.numberOfPages = imageNames.count
pageController.currentPage = 0
print("image name in Array: \(imageNames)")
imageContainer.image = UIImage(named: imageNames[0])
pageController.addTarget(self, action: #selector(action(sender: )), for: .touchUpInside)
}
// Set Swipe Gesture for the image container
let swipeRight = UISwipeGestureRecognizer(target: self, action: #selector(DetailViewController.reponderToSwipeGesture(_:)))
swipeRight.direction = UISwipeGestureRecognizer.Direction.right
self.imageContainer.addGestureRecognizer(swipeRight)
let swipeLeft = UISwipeGestureRecognizer(target: self, action: #selector(DetailViewController.reponderToSwipeGesture(_:)))
swipeLeft.direction = UISwipeGestureRecognizer.Direction.left
self.imageContainer.addGestureRecognizer(swipeLeft)
// Set textView Contents
contentTextView.text = entry.article
// stackView Setting
let stackView = UIStackView()
stackView.axis = .vertical
stackView.spacing = 8
// Arrange subviews to Stack View
[titleLabel, dateLabel, imageContainer, contentTextView].forEach { v in
v.translatesAutoresizingMaskIntoConstraints = false
stackView.addArrangedSubview(v)
}
// If image doesn't exist (1) Set the image container hidden
if entry.isImage == true {
imageContainer.heightAnchor.constraint(equalToConstant: self.view.frame.width).isActive = true
} else {
imageContainer.isHidden = true
}
// Set stakcView and scrollView
stackView.translatesAutoresizingMaskIntoConstraints = false
scrollView.translatesAutoresizingMaskIntoConstraints = false
scrollView.addSubview(stackView)
view.addSubview(scrollView)
// Set constraint
let g = view.safeAreaLayoutGuide
let cg = scrollView.contentLayoutGuide
let fg = scrollView.frameLayoutGuide
NSLayoutConstraint.activate([
scrollView.topAnchor.constraint(equalTo: g.topAnchor, constant: 0),
scrollView.leadingAnchor.constraint(equalTo: g.leadingAnchor, constant: 0),
scrollView.trailingAnchor.constraint(equalTo: g.trailingAnchor, constant: -0),
scrollView.bottomAnchor.constraint(equalTo: g.bottomAnchor, constant: -0),
stackView.topAnchor.constraint(equalTo: cg.topAnchor, constant: 0.0),
stackView.leadingAnchor.constraint(equalTo: cg.leadingAnchor, constant: 0.0),
stackView.trailingAnchor.constraint(equalTo: cg.trailingAnchor, constant: -0.0),
stackView.bottomAnchor.constraint(equalTo: cg.bottomAnchor, constant: -0.0),
stackView.widthAnchor.constraint(equalTo: fg.widthAnchor, constant: -0),
// set detail components constraint
titleLabel.trailingAnchor.constraint(equalTo: cg.trailingAnchor, constant: -20),
titleLabel.leadingAnchor.constraint(equalTo: cg.leadingAnchor, constant: 20),
dateLabel.trailingAnchor.constraint(equalTo: cg.trailingAnchor, constant: -20),
dateLabel.leadingAnchor.constraint(equalTo: cg.leadingAnchor, constant: 20),
imageContainer.leadingAnchor.constraint(equalTo: cg.leadingAnchor, constant: 0),
imageContainer.trailingAnchor.constraint(equalTo: cg.trailingAnchor, constant: 0),
contentTextView.leadingAnchor.constraint(equalTo: cg.leadingAnchor, constant: 20),
contentTextView.trailingAnchor.constraint(equalTo: cg.trailingAnchor, constant: -20),
])
}
}
错误
Unknown class detail in Interface Builder file.
Unable to simultaneously satisfy constraints.
Probably at least one of the constraints in the following list is one you don't want.
Try this:
(1) look at each constraint and try to figure out which you don't expect;
(2) find the code that added the unwanted constraint or constraints and fix it.
(
"<NSLayoutConstraint:0x6000021406e0 UILabel:0x103c1f3a0.leading == _UIScrollViewLayoutGuide:0x600003b0ea00'UIScrollView-contentLayoutGuide'.leading + 20 (active)>",
"<NSLayoutConstraint:0x600002140050 UIImageView:0x103c183d0.leading == _UIScrollViewLayoutGuide:0x600003b0ea00'UIScrollView-contentLayoutGuide'.leading (active)>",
"<NSLayoutConstraint:0x60000213b2f0 'UISV-alignment' UILabel:0x103c1f3a0.leading == UIImageView:0x103c183d0.leading (active)>"
)
Will attempt to recover by breaking constraint
<NSLayoutConstraint:0x60000213b2f0 'UISV-alignment' UILabel:0x103c1f3a0.leading == UIImageView:0x103c183d0.leading (active)>
Make a symbolic breakpoint at UIViewAlertForUnsatisfiableConstraints to catch this in the debugger.
The methods in the UIConstraintBasedLayoutDebugging category on UIView listed in <UIKitCore/UIView.h> may also be helpful.
Unable to simultaneously satisfy constraints.
Probably at least one of the constraints in the following list is one you don't want.
Try this:
(1) look at each constraint and try to figure out which you don't expect;
(2) find the code that added the unwanted constraint or constraints and fix it.
(
"<NSLayoutConstraint:0x600002142800 UILabel:0x103c1f3a0.trailing == _UIScrollViewLayoutGuide:0x600003b0ea00'UIScrollView-contentLayoutGuide'.trailing - 20 (active)>",
"<NSLayoutConstraint:0x600002140820 UIImageView:0x103c183d0.trailing == _UIScrollViewLayoutGuide:0x600003b0ea00'UIScrollView-contentLayoutGuide'.trailing (active)>",
"<NSLayoutConstraint:0x60000213b250 'UISV-alignment' UILabel:0x103c1f3a0.trailing == UIImageView:0x103c183d0.trailing (active)>"
)
Will attempt to recover by breaking constraint
<NSLayoutConstraint:0x60000213b250 'UISV-alignment' UILabel:0x103c1f3a0.trailing == UIImageView:0x103c183d0.trailing (active)>
Make a symbolic breakpoint at UIViewAlertForUnsatisfiableConstraints to catch this in the debugger.
The methods in the UIConstraintBasedLayoutDebugging category on UIView listed in <UIKitCore/UIView.h> may also be helpful.
Unable to simultaneously satisfy constraints.
Probably at least one of the constraints in the following list is one you don't want.
Try this:
(1) look at each constraint and try to figure out which you don't expect;
(2) find the code that added the unwanted constraint or constraints and fix it.
(
"<NSLayoutConstraint:0x600002140aa0 UIStackView:0x103c27b90.leading == _UIScrollViewLayoutGuide:0x600003b0ea00'UIScrollView-contentLayoutGuide'.leading (active)>",
"<NSLayoutConstraint:0x6000021406e0 UILabel:0x103c1f3a0.leading == _UIScrollViewLayoutGuide:0x600003b0ea00'UIScrollView-contentLayoutGuide'.leading + 20 (active)>",
"<NSLayoutConstraint:0x60000213b1b0 'UISV-canvas-connection' UIStackView:0x103c27b90.leading == UILabel:0x103c1f3a0.leading (active)>"
)
Will attempt to recover by breaking constraint
<NSLayoutConstraint:0x60000213b1b0 'UISV-canvas-connection' UIStackView:0x103c27b90.leading == UILabel:0x103c1f3a0.leading (active)>
Make a symbolic breakpoint at UIViewAlertForUnsatisfiableConstraints to catch this in the debugger.
The methods in the UIConstraintBasedLayoutDebugging category on UIView listed in <UIKitCore/UIView.h> may also be helpful.
Unable to simultaneously satisfy constraints.
Probably at least one of the constraints in the following list is one you don't want.
Try this:
(1) look at each constraint and try to figure out which you don't expect;
(2) find the code that added the unwanted constraint or constraints and fix it.
(
"<NSLayoutConstraint:0x6000021414a0 UIStackView:0x103c27b90.trailing == _UIScrollViewLayoutGuide:0x600003b0ea00'UIScrollView-contentLayoutGuide'.trailing (active)>",
"<NSLayoutConstraint:0x600002142800 UILabel:0x103c1f3a0.trailing == _UIScrollViewLayoutGuide:0x600003b0ea00'UIScrollView-contentLayoutGuide'.trailing - 20 (active)>",
"<NSLayoutConstraint:0x60000213b200 'UISV-canvas-connection' H:[UILabel:0x103c1f3a0]-(0)-| (active, names: '|':UIStackView:0x103c27b90 )>"
)
Will attempt to recover by breaking constraint
<NSLayoutConstraint:0x60000213b200 'UISV-canvas-connection' H:[UILabel:0x103c1f3a0]-(0)-| (active, names: '|':UIStackView:0x103c27b90 )>
Make a symbolic breakpoint at UIViewAlertForUnsatisfiableConstraints to catch this in the debugger.
The methods in the UIConstraintBasedLayoutDebugging category on UIView listed in <UIKitCore/UIView.h> may also be helpful.
我认为您的主要问题是您在堆栈视图中对视图设置的约束以及您未能完全配置堆栈视图。
删除以下限制:
titleLabel.trailingAnchor.constraint(equalTo: cg.trailingAnchor, constant: -20),
titleLabel.leadingAnchor.constraint(equalTo: cg.leadingAnchor, constant: 20),
dateLabel.trailingAnchor.constraint(equalTo: cg.trailingAnchor, constant: -20),
dateLabel.leadingAnchor.constraint(equalTo: cg.leadingAnchor, constant: 20),
imageContainer.leadingAnchor.constraint(equalTo: cg.leadingAnchor, constant: 0),
imageContainer.trailingAnchor.constraint(equalTo: cg.trailingAnchor, constant: 0),
contentTextView.leadingAnchor.constraint(equalTo: cg.leadingAnchor, constant: 20),
contentTextView.trailingAnchor.constraint(equalTo: cg.trailingAnchor, constant: -20),
以下更改将确保堆栈视图的视图填充堆栈视图的宽度。
通过设置
distribution
和 alignment
属性来完全设置堆栈视图。您可能需要在设置 axis
后添加以下两行:
stackView.distribution = .equalSpacing // Use each view's intrinsic height as-is when possible
stackView.alignment = .fill // Make each view's width the same as the width of the stack view
您应该更改图像视图的高度限制。替换:
imageContainer.heightAnchor.constraint(equalToConstant: self.view.frame.width).isActive = true
与:
imageContainer.heightAnchor.constraint(equalTo: imageContainer.widthAnchor).isActive = true
这将使图像视图的高度与其宽度相同,这就是我认为您正在尝试做的事情(使其成为正方形)。图像视图的宽度将来自于填充堆栈视图的宽度。