场景分析
在实际开发中遇到UIScrollView的场景大概分为两类: 超过一个竖屏的信息展示 和 轮播图,以少数派App做个例子
技术难点
通常来说,UIScrollView的布局 有两种方法:
- StoryBoard + AutoLayout的方式
- 代码 + SnapKit布局的方式 进行
不管我们采取哪种布局技术,如果我们直接在UIScrollView中添加子视图,然后给子视图相对于UIScrollView添加约束,会发现子视图是无法显示的,这是什么原因呢?
其实是因为: UIScrollView的leading/trailing/top/bottom是相对于自己的ContentSize来说的,而不是Frame; 而在给所有子视图添加完视图前ContentSize还不确定,我们这时候又给子视图添加约束到ContentSize,相互依赖,不就成了蛋生鸡,鸡生蛋的问题了。
解决方案
我们可以给UIScrollView添加一个充满自己的ContainerView,然后我们所有子视图的布局相对于这个ContainerView就好了; 同时,只要确定了ContainerView的尺寸,也就确定了UIScrollView的ContentSize
干起来
我们通过SnapKit + 代码的方式给一个垂直滚动的UIScollView加约束来做例子,其他情况原理都是类似的。
- Step1: 给UIScollView添加约束,没什么可说的
view.addSubview(scrollView)
scrollView.snp.makeConstraints { (make) in
make.edges.equalToSuperview()
}
- step2 : 给UIScollView添加一个充满他的ContainerView(重要)
注意:ContainerView给定了宽度,即UIScollView的ContentSize的宽度
确定了,还需要确定高度
scrollView.addSubview(containerView)
containerView.snp.makeConstraints { (make) in
make.edges.equalToSuperview()
make.width.equalTo(ScreenWidth)
}
Step3: 在ContainerView中添加子视图
//add 5 orange view
for i in 0..<5 {
let orangeView = UIView()
orangeView.backgroundColor = #colorLiteral(red: 0.9372549057, green: 0.3490196168, blue: 0.1921568662, alpha: 1)
containerView.addSubview(orangeView)
orangeView.snp.makeConstraints({ (make) in
make.left.right.equalTo(containerView)
make.height.equalTo(orangeViewGap)
if i == 0 {
make.top.equalTo(containerView.snp.top).offset(orangeViewGap)
} else if let previousView = containerView.subviews[i-1] as? UIView{
make.top.equalTo(previousView.snp.bottom).offset(orangeViewGap)
}
if i == 4 {
containerView.snp.makeConstraints({ (make) in
make.bottom.equalTo(orangeView.snp.bottom).offset(orangeViewGap)
})
}
})
}
上面代码中,第一个View很简单,关键是最后一个子视图,一定要加好最后一个子视图到ContainerView的间隔,即我们确定了ContainerView的高度
,那么我们就确定了UIScrollView的ContentSize的高度
,到此,完成整个布局过程; 核心代码都在上面。
最终,完成效果如下: