Swift 4:如何将带已有约束的视图加入滚动视图并适配小屏
嘿,这个场景我太熟了!很多人在给小屏机型适配时,都会碰到“已经布局好视图,现在要套滚动视图还得保留原有约束”的问题,下面给你一步步拆解,保证原有布局丝毫不乱,滚动功能正常工作:
步骤1:给ViewController添加滚动视图并设基础约束
不管你用Storyboard还是纯代码,第一步都是先把UIScrollView放进去:
- 如果是Storyboard:拖一个
UIScrollView到控制器的根view上,给它设置全屏约束——顶部、底部、左、右四个边缘都和根view对齐,常量设为0,让滚动视图占满整个屏幕。 - 如果是纯代码:初始化滚动视图后,关闭
translatesAutoresizingMaskIntoConstraints,再添加全屏约束(代码示例后面会放)。
步骤2:必须加的“ContentView”容器
这是最关键的一步!滚动视图不能直接放业务视图,必须套一个容器视图(我习惯叫它contentView),所有原有子视图都要移到这个容器里:
- Storyboard操作:拖一个
UIView到滚动视图里,命名为contentView。给它设置四个约束:顶部、底部、左、右都和滚动视图的contentLayoutGuide对齐(注意是内容布局指南,不是滚动视图自身的frame指南!),常量0。然后给contentView加一个宽度等于滚动视图frameLayoutGuide宽度的约束(如果只需要纵向滚动的话),这样横向不会出现滚动条;如果需要横向滚动,就改成高度等于frameLayoutGuide的高度。
划重点:滚动视图的
contentSize是由contentView的大小自动计算的,只要contentView里的子视图约束完整,它的高度会自动撑开,滚动视图就能正常滚动。
步骤3:迁移原有视图并保留约束
现在把你之前布局好的所有子视图,一个个从根view拖到contentView里:
- 拖的时候按住
Command键,这样原来的约束会一起被迁移过去,不会丢失! - 拖完后检查一下所有子视图的约束,确保它们的参照对象都是
contentView,而不是原来的根view。如果有个别约束没带过来,手动补一下就行,和原来的布局保持一致。
纯代码布局的对应实现
如果不用Storyboard,代码层面的步骤完全对应:
- 初始化并添加滚动视图:
let scrollView = UIScrollView() scrollView.translatesAutoresizingMaskIntoConstraints = false view.addSubview(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:
let contentView = UIView() contentView.translatesAutoresizingMaskIntoConstraints = false scrollView.addSubview(contentView) // 绑定contentView与滚动视图的内容指南,同时固定宽度(纵向滚动场景) 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上,将原来参照根view的约束,改成参照contentView即可。
避坑提醒
- 绝对不要直接把业务视图加到滚动视图上,必须通过
contentView,否则滚动视图无法正确计算contentSize,滚动功能会失效。 - 别搞混
contentLayoutGuide和frameLayoutGuide:前者是滚动内容的范围,后者是滚动视图自身的显示范围,约束错了直接导致布局混乱。 - 如果
contentView高度没撑开,检查子视图的约束是否形成了完整的垂直链条(从contentView顶部到底部都有约束连接),AutoLayout需要这个链条来计算contentView的高度。
这样操作完,原有布局的约束会完整保留,小屏机型上内容超出屏幕时就会自动滚动,完美适配~
内容的提问来源于stack exchange,提问作者DevilRunner
相关产品推荐
相关产品推荐

