写在前面
在日常开发中,令人看了就想素质三连的代码,莫过于手动计算各种数字的代码。如下图,看了真的是头皮发麻。
那么,我们如何避免上面的问题,从而使我们的代码变得友好、可读性更高呢(主要为了保住我们为数不多的头发😭)?答案就是使用 AutoLayout 让系统自动计算数字。
下面,我们举一个实际的例子来一步一步的实现:使用 AutoLayout 自动计算 ScrollView 的 contentSize 。
先来说一下实现的大体步骤:
设置 scrollView 的约束
约束上下左右间距为 0
创建一个 contentView ,设置 contentView 的约束
上下左右间距为 0
宽度和 scrollView 的父视图相等
高度和 scrollView 的父视图相等,且优先级要低(这一步很重要,千万不要写错)
将所有子控件添加到 contentView (而不是直接添加到 scrollView 上),并设置好子控件的内部约束
设置 scrollView 的约束
首先,给使用的 scrollView 添加完整的约束:
// 1. 设置 scrollView 的约束
view.addSubview(scrollView)
scrollView.translatesAutoresizingMaskIntoConstraints = false
NSLayoutConstraint.activate([
scrollView.topAnchor.constraint(equalTo: view.safeAreaLayoutGuide.topAnchor),
scrollView.leftAnchor.constraint(equalTo: view.safeAreaLayoutGuide.leftAnchor),
scrollView.bottomAnchor.constraint(equalTo: view.safeAreaLayoutGuide.bottomAnchor),
scrollView.rightAnchor.constraint(equalTo: view.safeAreaLayoutGuide.rightAnchor)
])
创建 contentView,设置 contentView 的约束
设置完 scrollView,接下来设置 contentView 的约束:
// 2. 设置 contentView
let contentView = UIView(frame: .zero)
scrollView.addSubview(contentView)
contentView.translatesAutoresizingMaskIntoConstraints = false
let contentViewHeightAnchor = contentView.heightAnchor.constraint(equalTo: view.safeAreaLayoutGuide.heightAnchor)
// 2.1 高度和 scrollView 的父视图相等,且`优先级要低`
contentViewHeightAnchor.priority = UILayoutPriority(rawValue: 1)
NSLayoutConstraint.activate([
contentView.topAnchor.constraint(equalTo: scrollView.topAnchor),
contentView.leftAnchor.constraint(equalTo: scrollView.leftAnchor),
contentView.bottomAnchor.constraint(equalTo: scrollView.bottomAnchor),
contentView.rightAnchor.constraint(equalTo: scrollView.rightAnchor),
contentView.widthAnchor.constraint(equalTo: view.widthAnchor),
contentViewHeightAnchor
])
### 添加子控件,设置内部约束
设置完 scrollView 和 contentView 的约束,只需设置内部子控件的约束,剩下的工作就可以交给 AutoLayout 去做了。
// 3.添加子控件,设置内部约束
titleLabel.text = "titleLabel"
contentView.addSubview(titleLabel)
titleLabel.translatesAutoresizingMaskIntoConstraints = false
NSLayoutConstraint.activate([
titleLabel.topAnchor.constraint(equalTo: contentView.topAnchor, constant: 10),
titleLabel.leftAnchor.constraint(equalTo: contentView.leftAnchor, constant: 10),
titleLabel.rightAnchor.constraint(equalTo: contentView.rightAnchor, constant: -10)
])
contentLabel.text = "将此处替换为你自己的字符串(超过一屏),即可看见滑动效果。"
contentLabel.numberOfLines = 0
contentView.addSubview(contentLabel)
contentLabel.translatesAutoresizingMaskIntoConstraints = false
NSLayoutConstraint.activate([
contentLabel.topAnchor.constraint(equalTo: titleLabel.bottomAnchor, constant: 10),
contentLabel.leftAnchor.constraint(equalTo: titleLabel.leftAnchor),
contentLabel.rightAnchor.constraint(equalTo: titleLabel.rightAnchor)
])
bottomLabel.text = "bottomLabel"
contentView.addSubview(bottomLabel)
bottomLabel.translatesAutoresizingMaskIntoConstraints = false
NSLayoutConstraint.activate([
bottomLabel.topAnchor.constraint(equalTo: contentLabel.bottomAnchor, constant: 10),
bottomLabel.leftAnchor.constraint(equalTo: titleLabel.leftAnchor),
bottomLabel.rightAnchor.constraint(equalTo: titleLabel.rightAnchor),
bottomLabel.bottomAnchor.constraint(equalTo: contentView.bottomAnchor, constant: -10)
])
到这里,我们就大功告成了。妈妈再也不用担心我手动计算数字了😏 (成功保住了自己的头发)。
完整代码
class TestViewController: UIViewController {
let scrollView = UIScrollView(frame: .zero)
let titleLabel = UILabel(frame: .zero)
let contentLabel = UILabel(frame: .zero)
let bottomLabel = UILabel(frame: .zero)
override func viewDidLoad() {
super.viewDidLoad()
view.backgroundColor = UIColor.white
setupSubviews()
}
}
extension TestViewController {
func setupSubviews() {
// 1. 设置 scrollView 的约束
view.addSubview(scrollView)
scrollView.translatesAutoresizingMaskIntoConstraints = false
NSLayoutConstraint.activate([
scrollView.topAnchor.constraint(equalTo: view.safeAreaLayoutGuide.topAnchor),
scrollView.leftAnchor.constraint(equalTo: view.safeAreaLayoutGuide.leftAnchor),
scrollView.bottomAnchor.constraint(equalTo: view.safeAreaLayoutGuide.bottomAnchor),
scrollView.rightAnchor.constraint(equalTo: view.safeAreaLayoutGuide.rightAnchor)
])
// 2. 设置 contentView
let contentView = UIView(frame: .zero)
scrollView.addSubview(contentView)
contentView.translatesAutoresizingMaskIntoConstraints = false
let contentViewHeightAnchor = contentView.heightAnchor.constraint(equalTo: view.safeAreaLayoutGuide.heightAnchor)
// 2.1 高度和 scrollView 的父视图相等,且`优先级要低`
contentViewHeightAnchor.priority = UILayoutPriority(rawValue: 1)
NSLayoutConstraint.activate([
contentView.topAnchor.constraint(equalTo: scrollView.topAnchor),
contentView.leftAnchor.constraint(equalTo: scrollView.leftAnchor),
contentView.bottomAnchor.constraint(equalTo: scrollView.bottomAnchor),
contentView.rightAnchor.constraint(equalTo: scrollView.rightAnchor),
contentView.widthAnchor.constraint(equalTo: view.widthAnchor),
contentViewHeightAnchor
])
// 3.添加子控件,设置内部约束
titleLabel.text = "titleLabel"
contentView.addSubview(titleLabel)
titleLabel.translatesAutoresizingMaskIntoConstraints = false
NSLayoutConstraint.activate([
titleLabel.topAnchor.constraint(equalTo: contentView.topAnchor, constant: 10),
titleLabel.leftAnchor.constraint(equalTo: contentView.leftAnchor, constant: 10),
titleLabel.rightAnchor.constraint(equalTo: contentView.rightAnchor, constant: -10)
])
contentLabel.text = "将此处替换为你自己的字符串(超过一屏),即可看见滑动效果"
contentLabel.numberOfLines = 0
contentView.addSubview(contentLabel)
contentLabel.translatesAutoresizingMaskIntoConstraints = false
NSLayoutConstraint.activate([
contentLabel.topAnchor.constraint(equalTo: titleLabel.bottomAnchor, constant: 10),
contentLabel.leftAnchor.constraint(equalTo: titleLabel.leftAnchor),
contentLabel.rightAnchor.constraint(equalTo: titleLabel.rightAnchor)
])
bottomLabel.text = "bottomLabel"
contentView.addSubview(bottomLabel)
bottomLabel.translatesAutoresizingMaskIntoConstraints = false
NSLayoutConstraint.activate([
bottomLabel.topAnchor.constraint(equalTo: contentLabel.bottomAnchor, constant: 10),
bottomLabel.leftAnchor.constraint(equalTo: titleLabel.leftAnchor),
bottomLabel.rightAnchor.constraint(equalTo: titleLabel.rightAnchor),
bottomLabel.bottomAnchor.constraint(equalTo: contentView.bottomAnchor, constant: -10)
])
}
}