抱歉,您对scrollView.contentLayoutGuide 和scrollView.frameLayoutGuide 的使用非常错误。
您希望将scrollView 本身约束到其父视图(在本例中为主view)并将滚动视图的子视图 约束到滚动视图的.contentLayoutGuide。然后,您可以使用 scrollView 的 .frameLayoutGuide 来帮助设置其子视图的大小。
因此,如果您希望标签在滚动视图中居中,但在标签太宽而无法容纳时启用水平滚动,您希望:
- 将标签添加到“持有人”视图中,并限制在中心
- 将该“持有人”视图添加到滚动视图
- 将其位置限制在
.contentLayoutGuide 和
- 将其大小限制为
.frameLayoutGuide
- 为标签添加前导和尾随约束以强制“持有人”视图在需要时增长
这是一个简单的例子。它将在标签的不同长度字符串之间循环...滚动将根据标签的最终宽度自动启用或禁用(所有这些都具有自动布局 - 无需计算大小):
class ViewController: UIViewController {
let scrollView = UIScrollView()
let label = UILabel()
let labelHolderView = UIView()
let sampleStrings: [String] = [
"Short (no scrolling).",
"A little longer (still no scrolling).",
"A much longer string, that will definitely require horizontal scrolling.",
"Just for kicks, let's make this string really, really long, to help demonstrate the benefits of using auto-layout!",
]
var stringIndex: Int = 0
override func viewDidLoad() {
super.viewDidLoad()
setupScrollView()
}
func setupScrollView() {
// add the label to the holder view
labelHolderView.addSubview(label)
// add the holder view to the scroll view
scrollView.addSubview(labelHolderView)
// add the scroll view to the view
view.addSubview(scrollView)
// all three need this
labelHolderView.translatesAutoresizingMaskIntoConstraints = false
label.translatesAutoresizingMaskIntoConstraints = false
scrollView.translatesAutoresizingMaskIntoConstraints = false
let safeG = view.safeAreaLayoutGuide
let contentG = scrollView.contentLayoutGuide
let frameG = scrollView.frameLayoutGuide
NSLayoutConstraint.activate([
// let's put a 100-pt tall scroll view
// 40-pts from the bottom
// 40-pts on each side
scrollView.bottomAnchor.constraint(equalTo: safeG.bottomAnchor, constant: -40.0),
scrollView.leadingAnchor.constraint(equalTo: safeG.leadingAnchor, constant: 40.0),
scrollView.trailingAnchor.constraint(equalTo: safeG.trailingAnchor, constant: -40.0),
scrollView.heightAnchor.constraint(equalToConstant: 100.0),
// constrain holder view to ContentGuide with Zero on all 4 sides
labelHolderView.topAnchor.constraint(equalTo: contentG.topAnchor, constant: 0.0),
labelHolderView.leadingAnchor.constraint(equalTo: contentG.leadingAnchor, constant: 0.0),
labelHolderView.trailingAnchor.constraint(equalTo: contentG.trailingAnchor, constant: 0.0),
labelHolderView.bottomAnchor.constraint(equalTo: contentG.bottomAnchor, constant: 0.0),
// we only want horizontal scrolling, so constrain
// holder view height to sccroll view FrameGuide
labelHolderView.heightAnchor.constraint(equalTo: frameG.heightAnchor),
// we want the label centered horizontally
// in the holder view and in the scroll view
// so set holder view width >= FrameGuide
labelHolderView.widthAnchor.constraint(greaterThanOrEqualTo: frameG.widthAnchor, constant: 0.0),
// center the label in the holder view
label.centerXAnchor.constraint(equalTo: labelHolderView.centerXAnchor),
label.centerYAnchor.constraint(equalTo: labelHolderView.centerYAnchor),
// as the label expands horizontally, we want at least
// 8-pts on each side
label.leadingAnchor.constraint(greaterThanOrEqualTo: labelHolderView.leadingAnchor, constant: 8.0),
label.trailingAnchor.constraint(lessThanOrEqualTo: labelHolderView.trailingAnchor, constant: -8.0),
])
// let's use some background colors so we can see the view frames
scrollView.backgroundColor = .yellow
labelHolderView.backgroundColor = .systemTeal
label.backgroundColor = .green
// add a button above the scroll view to cycle through our sample strings
let b = UIButton()
b.setTitle("Tap Me", for: [])
b.setTitleColor(.white, for: .normal)
b.setTitleColor(.lightGray, for: .highlighted)
b.backgroundColor = .systemGreen
b.translatesAutoresizingMaskIntoConstraints = false
view.addSubview(b)
NSLayoutConstraint.activate([
b.bottomAnchor.constraint(equalTo: scrollView.topAnchor, constant: -20.0),
b.widthAnchor.constraint(equalTo: safeG.widthAnchor, multiplier: 0.6),
b.centerXAnchor.constraint(equalTo: safeG.centerXAnchor),
])
b.addTarget(self, action: #selector(gotTap(_:)), for: .touchUpInside)
// set the initial text
gotTap(nil)
}
@objc func gotTap(_ sender: Any?) -> Void {
label.text = sampleStrings[stringIndex % sampleStrings.count]
stringIndex += 1
}
}