代码实现带AutoLayout的UIScrollView垂直滚动遇布局问题求助
解决UIScrollView垂直滚动的AutoLayout布局问题
我懂你现在卡在代码创建可垂直滚动UIScrollView的AutoLayout设置上了,别急,咱们一步步把这个问题捋顺——核心就是给scrollView和它的contentView设置正确的约束链条,让scrollView能自动计算出滚动范围。
首先先把你现有的scrollView和contentView的创建代码补全(假设你还没写完contentView的初始化):
lazy var scrollView : UIScrollView = { let scrollView = UIScrollView() scrollView.translatesAutoresizingMaskIntoConstraints = false scrollView.keyboardDismissMode = .onDrag scrollView.showsVerticalScrollIndicator = true // 可选,开启垂直滚动条便于调试 return scrollView }() lazy var contentView: UIView = { let view = UIView() view.translatesAutoresizingMaskIntoConstraints = false return view }()
接下来是最关键的约束设置,这部分是最容易踩坑的地方,记住几个核心规则:
- scrollView的约束要和父视图(比如ViewController的view)四边缘完全对齐,确定它的显示区域
- contentView要绑定到scrollView的contentLayoutGuide,同时设置contentView的宽度等于scrollView的frameLayoutGuide宽度(确保只有垂直滚动,不会出现水平滚动)
- contentView内的所有子控件,必须形成从顶部到底部的完整约束链,让AutoLayout能算出contentView的高度,scrollView才能知道滚动范围
下面是完整的约束代码,你可以把它放在viewDidLoad()里:
override func viewDidLoad() { super.viewDidLoad() // 先把scrollView和contentView添加到视图层级 view.addSubview(scrollView) scrollView.addSubview(contentView) // 设置scrollView的约束:和父视图四边缘对齐 NSLayoutConstraint.activate([ scrollView.topAnchor.constraint(equalTo: view.topAnchor), scrollView.leadingAnchor.constraint(equalTo: view.leadingAnchor), scrollView.trailingAnchor.constraint(equalTo: view.trailingAnchor), scrollView.bottomAnchor.constraint(equalTo: view.bottomAnchor) ]) // 设置contentView的约束:绑定scrollView的内容引导区,宽度和scrollView的框架引导区一致 NSLayoutConstraint.activate([ contentView.topAnchor.constraint(equalTo: scrollView.contentLayoutGuide.topAnchor), contentView.leadingAnchor.constraint(equalTo: scrollView.contentLayoutGuide.leadingAnchor), contentView.trailingAnchor.constraint(equalTo: scrollView.contentLayoutGuide.trailingAnchor), contentView.bottomAnchor.constraint(equalTo: scrollView.contentLayoutGuide.bottomAnchor), contentView.widthAnchor.constraint(equalTo: scrollView.frameLayoutGuide.widthAnchor) ]) // 给contentView添加子控件示例,重点是形成完整的垂直约束链 let sampleLabel = UILabel() sampleLabel.translatesAutoresizingMaskIntoConstraints = false sampleLabel.text = "这是测试文本,用来验证滚动效果。你可以添加任意多控件,只要保证所有控件的约束能让contentView算出明确的高度就行。比如再放几个按钮、输入框,依次从上到下排列,最后一个控件的bottom要绑定contentView的bottom。" sampleLabel.numberOfLines = 0 contentView.addSubview(sampleLabel) NSLayoutConstraint.activate([ sampleLabel.topAnchor.constraint(equalTo: contentView.topAnchor, constant: 20), sampleLabel.leadingAnchor.constraint(equalTo: contentView.leadingAnchor, constant: 16), sampleLabel.trailingAnchor.constraint(equalTo: contentView.trailingAnchor, constant: -16), // 最后一个控件的bottom必须绑定contentView的bottom,让AutoLayout能确定contentView的高度 sampleLabel.bottomAnchor.constraint(equalTo: contentView.bottomAnchor, constant: -20) ]) }
这里再划几个必注意的点:
- 一定要用
contentLayoutGuide和frameLayoutGuide,这是iOS11之后苹果官方推荐的方式,比手动设置contentSize稳定得多 - contentView的宽度必须和scrollView的宽度绑定,避免出现不必要的水平滚动
- contentView内的子控件必须形成连续的垂直约束链条:从contentView的top开始,到最后一个子控件的bottom结束,不能有约束断层,否则AutoLayout无法算出contentView的高度,scrollView也就不会滚动
内容的提问来源于stack exchange,提问作者Deepak
相关产品推荐
相关产品推荐

