如何使用 AutoLayout 自動計算 ScrollView 的 contentSize

iOS version: 12.2
字數:900+
閱讀時長:10 min
複製代碼

在平常開發中,使人看了就想素質三連的代碼,莫過於手動計算各類數字的代碼。以下圖,看了真的是頭皮發麻。bash

手動計算
那麼,咱們如何避免上面的問題,從而使咱們的代碼變得友好、可讀性更高呢(主要爲了保住咱們爲數很少的頭髮😭)?答案就是使用 AutoLayout 讓系統 自動計算數字。

下面,咱們舉一個實際的例子來一步一步的實現:使用 AutoLayout 自動計算 ScrollView 的 contentSize 。ide

先來講一下實現的大致步驟:

  • 設置 scrollView 的約束
    • 約束上下左右間距爲 0
  • 建立一個 contentView ,設置 contentView 的約束
    • 上下左右間距爲 0
    • 寬度和 scrollView 的父視圖相等
    • 高度和 scrollView 的父視圖相等,且優先級要低(這一步很重要,千萬不要寫錯)
  • 將全部子控件添加到 contentView (而不是直接添加到 scrollView 上),並設置好子控件的內部約束

設置 scrollView 的約束

首先,給使用的 scrollView 添加完整的約束:ui

// 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 的約束:spa

// 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 去作了。code

// 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)
    ])

複製代碼

到這裏,咱們就大功告成了。媽媽不再用擔憂我手動計算數字了😏 (成功保住了本身的頭髮)。cdn

完整代碼

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)
            ])
    }
}
複製代碼

效果圖:blog

參考

相關文章
相關標籤/搜索