如何使编程滚动视图容器的高度与其内容的确切大小相同 Swift?
How to make a programatic scrollviews container height the exact size of its content in Swift?
我的问题如下:
contentView的高度比它的子视图高,所以虽然contentView的子视图没有垂直占据整个屏幕,您仍然可以滚动浏览内容。
如何设置 contentView 的高度以匹配其子视图的高度,这样如果屏幕在垂直方向上足够大以适应内容,您不能滚动,但如果屏幕较小或发送键盘信号,则可以垂直滚动?
我知道问题出在 contentView.anchor 中的高度限制,但我不知道如何修复它,而且我一直无法解决找到任何答案。
let scrollView = UIScrollView()
let contentView = UIView()
override func viewDidLoad() {
super.viewDidLoad()
configureScrollView()
configureUI()
}
func configureScrollView() {
view.addSubview(scrollView)
scrollView.anchor(top: view.safeAreaLayoutGuide.topAnchor,
left: view.leftAnchor,
bottom: view.safeAreaLayoutGuide.bottomAnchor,
right: view.rightAnchor)
scrollView.addSubview(contentView)
contentView.anchor(top: scrollView.topAnchor,
left: scrollView.leftAnchor,
bottom: scrollView.bottomAnchor,
right: scrollView.rightAnchor,
width: view.frame.size.width,
height: view.frame.size.height)
}
func configureUI() {
contentView.addSubview(previewTitleLabel)
previewTitleLabel.anchor(top: contentView.topAnchor,
left: contentView.leftAnchor,
right: contentView.rightAnchor,
paddingTop: 20,
paddingLeft: 20,
paddingRight: 20,
height: 20)
contentView.addSubview(previewView)
previewView.anchor(top: previewTitleLabel.bottomAnchor,
left: contentView.leftAnchor,
right: contentView.rightAnchor,
paddingTop: 20,
paddingLeft: 20,
paddingRight: 20) // Has dynamic height
contentView.addSubview(detailsTitleLabel)
detailsTitleLabel.anchor(top: previewView.bottomAnchor,
left: contentView.leftAnchor,
right: contentView.rightAnchor,
paddingTop: 20,
paddingLeft: 20,
paddingRight: 20,
height: 20)
contentView.addSubview(descriptionView)
descriptionView.anchor(top: detailsTitleLabel.bottomAnchor,
left: contentView.leftAnchor,
right: contentView.rightAnchor,
paddingTop: 20,
paddingLeft: 20,
paddingRight: 20,
height: 278)
}
情侣提示:
- 浏览 half-dozen 左右的滚动视图教程,了解它们的工作原理。
- 完成 half-dozen 左右 auto-layout 教程,以便了解约束的工作原理。
- 使用标准约束语法代替您的
.anchor()
“助手”,直到您完全理解约束的工作原理。这也让您可以逻辑地“分组”您的约束,正如您将在本示例代码中看到的那样。
- 在布局开发期间,为您的 UI 元素提供对比鲜明的背景颜色,以便于查看框架。
因此,示例代码:
class ExampleScrollViewController: UIViewController {
let scrollView = UIScrollView()
let contentView = UIView()
let previewTitleLabel = UILabel()
let previewView = UIView()
let detailsTitleLabel = UILabel()
let descriptionView = UIView()
override func viewDidLoad() {
super.viewDidLoad()
configureScrollView()
configureUI()
// use some background colors so we can easily see frames
scrollView.backgroundColor = .red
contentView.backgroundColor = .blue
previewTitleLabel.backgroundColor = .cyan
previewView.backgroundColor = .green
detailsTitleLabel.backgroundColor = .cyan
descriptionView.backgroundColor = .green
previewTitleLabel.text = "Preview Title Label"
detailsTitleLabel.text = "Details Title Label"
}
func configureScrollView() {
contentView.translatesAutoresizingMaskIntoConstraints = false
scrollView.translatesAutoresizingMaskIntoConstraints = false
scrollView.addSubview(contentView)
view.addSubview(scrollView)
// respect safe area
let g = view.safeAreaLayoutGuide
// reference to scrollView's contentLayoutGuide
let svContentLG = scrollView.contentLayoutGuide
// reference to scrollView's frameLayoutGuide
let svFrameLG = scrollView.frameLayoutGuide
NSLayoutConstraint.activate([
// constrain scroll view to full safe area
scrollView.topAnchor.constraint(equalTo: g.topAnchor),
scrollView.leadingAnchor.constraint(equalTo: g.leadingAnchor),
scrollView.trailingAnchor.constraint(equalTo: g.trailingAnchor),
scrollView.bottomAnchor.constraint(equalTo: g.bottomAnchor),
// constrain content view to all 4 sides of scroll view's content layout guide
contentView.topAnchor.constraint(equalTo: svContentLG.topAnchor),
contentView.leadingAnchor.constraint(equalTo: svContentLG.leadingAnchor),
contentView.trailingAnchor.constraint(equalTo: svContentLG.trailingAnchor),
contentView.bottomAnchor.constraint(equalTo: svContentLG.bottomAnchor),
// we want vertical scrolling,
// so constrain width of content view to scroll view's frame
contentView.widthAnchor.constraint(equalTo: svFrameLG.widthAnchor),
])
}
func configureUI() {
[previewTitleLabel, previewView, detailsTitleLabel, descriptionView].forEach {
[=10=].translatesAutoresizingMaskIntoConstraints = false
contentView.addSubview([=10=])
}
NSLayoutConstraint.activate([
// horizontal constraints
// all 4 subviews will be constrained
// Leading and Trailing to the contentView
// with 20-pts "padding" on left and right
previewTitleLabel.leadingAnchor.constraint(equalTo: contentView.leadingAnchor, constant: 20.0),
previewTitleLabel.trailingAnchor.constraint(equalTo: contentView.trailingAnchor, constant: -20.0),
previewView.leadingAnchor.constraint(equalTo: contentView.leadingAnchor, constant: 20.0),
previewView.trailingAnchor.constraint(equalTo: contentView.trailingAnchor, constant: -20.0),
detailsTitleLabel.leadingAnchor.constraint(equalTo: contentView.leadingAnchor, constant: 20.0),
detailsTitleLabel.trailingAnchor.constraint(equalTo: contentView.trailingAnchor, constant: -20.0),
descriptionView.leadingAnchor.constraint(equalTo: contentView.leadingAnchor, constant: 20.0),
descriptionView.trailingAnchor.constraint(equalTo: contentView.trailingAnchor, constant: -20.0),
// vertical spacing constraints
// previewTitleLabel Top 20-pts from contentView Top
previewTitleLabel.topAnchor.constraint(equalTo: contentView.topAnchor, constant: 20.0),
// previewView Top 20-pts from previewTitleLabel Bottom
previewView.topAnchor.constraint(equalTo: previewTitleLabel.bottomAnchor, constant: 20.0),
// detailsTitleLabel Top 20-pts from previewView Bottom
detailsTitleLabel.topAnchor.constraint(equalTo: previewView.bottomAnchor, constant: 20.0),
// descriptionView Top 20-pts from detailsTitleLabel Bottom
descriptionView.topAnchor.constraint(equalTo: detailsTitleLabel.bottomAnchor, constant: 20.0),
// complete the vertical spacing constraints by
// constraining descriptionView Bottom 20-pts from contentView Bottom
descriptionView.bottomAnchor.constraint(equalTo: contentView.bottomAnchor, constant: -20.0),
// vertical height constraints
// previewTitleLabel Height: 20
previewTitleLabel.heightAnchor.constraint(equalToConstant: 20.0),
// previewView Height: 20
previewView.heightAnchor.constraint(equalToConstant: 20.0),
// detailsTitleLabel Height: 20
detailsTitleLabel.heightAnchor.constraint(equalToConstant: 20.0),
// descriptionView Height: 270
descriptionView.heightAnchor.constraint(equalToConstant: 270.0),
])
}
}
结果:
如果我将 previewView
的高度也更改为 270
:
previewView.heightAnchor.constraint(equalToConstant: 270.0),
我们得到这个结果:
我们可以向上滚动查看内容的底部:
我的问题如下:
contentView的高度比它的子视图高,所以虽然contentView的子视图没有垂直占据整个屏幕,您仍然可以滚动浏览内容。
如何设置 contentView 的高度以匹配其子视图的高度,这样如果屏幕在垂直方向上足够大以适应内容,您不能滚动,但如果屏幕较小或发送键盘信号,则可以垂直滚动?
我知道问题出在 contentView.anchor 中的高度限制,但我不知道如何修复它,而且我一直无法解决找到任何答案。
let scrollView = UIScrollView()
let contentView = UIView()
override func viewDidLoad() {
super.viewDidLoad()
configureScrollView()
configureUI()
}
func configureScrollView() {
view.addSubview(scrollView)
scrollView.anchor(top: view.safeAreaLayoutGuide.topAnchor,
left: view.leftAnchor,
bottom: view.safeAreaLayoutGuide.bottomAnchor,
right: view.rightAnchor)
scrollView.addSubview(contentView)
contentView.anchor(top: scrollView.topAnchor,
left: scrollView.leftAnchor,
bottom: scrollView.bottomAnchor,
right: scrollView.rightAnchor,
width: view.frame.size.width,
height: view.frame.size.height)
}
func configureUI() {
contentView.addSubview(previewTitleLabel)
previewTitleLabel.anchor(top: contentView.topAnchor,
left: contentView.leftAnchor,
right: contentView.rightAnchor,
paddingTop: 20,
paddingLeft: 20,
paddingRight: 20,
height: 20)
contentView.addSubview(previewView)
previewView.anchor(top: previewTitleLabel.bottomAnchor,
left: contentView.leftAnchor,
right: contentView.rightAnchor,
paddingTop: 20,
paddingLeft: 20,
paddingRight: 20) // Has dynamic height
contentView.addSubview(detailsTitleLabel)
detailsTitleLabel.anchor(top: previewView.bottomAnchor,
left: contentView.leftAnchor,
right: contentView.rightAnchor,
paddingTop: 20,
paddingLeft: 20,
paddingRight: 20,
height: 20)
contentView.addSubview(descriptionView)
descriptionView.anchor(top: detailsTitleLabel.bottomAnchor,
left: contentView.leftAnchor,
right: contentView.rightAnchor,
paddingTop: 20,
paddingLeft: 20,
paddingRight: 20,
height: 278)
}
情侣提示:
- 浏览 half-dozen 左右的滚动视图教程,了解它们的工作原理。
- 完成 half-dozen 左右 auto-layout 教程,以便了解约束的工作原理。
- 使用标准约束语法代替您的
.anchor()
“助手”,直到您完全理解约束的工作原理。这也让您可以逻辑地“分组”您的约束,正如您将在本示例代码中看到的那样。 - 在布局开发期间,为您的 UI 元素提供对比鲜明的背景颜色,以便于查看框架。
因此,示例代码:
class ExampleScrollViewController: UIViewController {
let scrollView = UIScrollView()
let contentView = UIView()
let previewTitleLabel = UILabel()
let previewView = UIView()
let detailsTitleLabel = UILabel()
let descriptionView = UIView()
override func viewDidLoad() {
super.viewDidLoad()
configureScrollView()
configureUI()
// use some background colors so we can easily see frames
scrollView.backgroundColor = .red
contentView.backgroundColor = .blue
previewTitleLabel.backgroundColor = .cyan
previewView.backgroundColor = .green
detailsTitleLabel.backgroundColor = .cyan
descriptionView.backgroundColor = .green
previewTitleLabel.text = "Preview Title Label"
detailsTitleLabel.text = "Details Title Label"
}
func configureScrollView() {
contentView.translatesAutoresizingMaskIntoConstraints = false
scrollView.translatesAutoresizingMaskIntoConstraints = false
scrollView.addSubview(contentView)
view.addSubview(scrollView)
// respect safe area
let g = view.safeAreaLayoutGuide
// reference to scrollView's contentLayoutGuide
let svContentLG = scrollView.contentLayoutGuide
// reference to scrollView's frameLayoutGuide
let svFrameLG = scrollView.frameLayoutGuide
NSLayoutConstraint.activate([
// constrain scroll view to full safe area
scrollView.topAnchor.constraint(equalTo: g.topAnchor),
scrollView.leadingAnchor.constraint(equalTo: g.leadingAnchor),
scrollView.trailingAnchor.constraint(equalTo: g.trailingAnchor),
scrollView.bottomAnchor.constraint(equalTo: g.bottomAnchor),
// constrain content view to all 4 sides of scroll view's content layout guide
contentView.topAnchor.constraint(equalTo: svContentLG.topAnchor),
contentView.leadingAnchor.constraint(equalTo: svContentLG.leadingAnchor),
contentView.trailingAnchor.constraint(equalTo: svContentLG.trailingAnchor),
contentView.bottomAnchor.constraint(equalTo: svContentLG.bottomAnchor),
// we want vertical scrolling,
// so constrain width of content view to scroll view's frame
contentView.widthAnchor.constraint(equalTo: svFrameLG.widthAnchor),
])
}
func configureUI() {
[previewTitleLabel, previewView, detailsTitleLabel, descriptionView].forEach {
[=10=].translatesAutoresizingMaskIntoConstraints = false
contentView.addSubview([=10=])
}
NSLayoutConstraint.activate([
// horizontal constraints
// all 4 subviews will be constrained
// Leading and Trailing to the contentView
// with 20-pts "padding" on left and right
previewTitleLabel.leadingAnchor.constraint(equalTo: contentView.leadingAnchor, constant: 20.0),
previewTitleLabel.trailingAnchor.constraint(equalTo: contentView.trailingAnchor, constant: -20.0),
previewView.leadingAnchor.constraint(equalTo: contentView.leadingAnchor, constant: 20.0),
previewView.trailingAnchor.constraint(equalTo: contentView.trailingAnchor, constant: -20.0),
detailsTitleLabel.leadingAnchor.constraint(equalTo: contentView.leadingAnchor, constant: 20.0),
detailsTitleLabel.trailingAnchor.constraint(equalTo: contentView.trailingAnchor, constant: -20.0),
descriptionView.leadingAnchor.constraint(equalTo: contentView.leadingAnchor, constant: 20.0),
descriptionView.trailingAnchor.constraint(equalTo: contentView.trailingAnchor, constant: -20.0),
// vertical spacing constraints
// previewTitleLabel Top 20-pts from contentView Top
previewTitleLabel.topAnchor.constraint(equalTo: contentView.topAnchor, constant: 20.0),
// previewView Top 20-pts from previewTitleLabel Bottom
previewView.topAnchor.constraint(equalTo: previewTitleLabel.bottomAnchor, constant: 20.0),
// detailsTitleLabel Top 20-pts from previewView Bottom
detailsTitleLabel.topAnchor.constraint(equalTo: previewView.bottomAnchor, constant: 20.0),
// descriptionView Top 20-pts from detailsTitleLabel Bottom
descriptionView.topAnchor.constraint(equalTo: detailsTitleLabel.bottomAnchor, constant: 20.0),
// complete the vertical spacing constraints by
// constraining descriptionView Bottom 20-pts from contentView Bottom
descriptionView.bottomAnchor.constraint(equalTo: contentView.bottomAnchor, constant: -20.0),
// vertical height constraints
// previewTitleLabel Height: 20
previewTitleLabel.heightAnchor.constraint(equalToConstant: 20.0),
// previewView Height: 20
previewView.heightAnchor.constraint(equalToConstant: 20.0),
// detailsTitleLabel Height: 20
detailsTitleLabel.heightAnchor.constraint(equalToConstant: 20.0),
// descriptionView Height: 270
descriptionView.heightAnchor.constraint(equalToConstant: 270.0),
])
}
}
结果:
如果我将 previewView
的高度也更改为 270
:
previewView.heightAnchor.constraint(equalToConstant: 270.0),
我们得到这个结果:
我们可以向上滚动查看内容的底部: