UIScrollerView 與 AutoLayout 的狗血故事

image.png

一個(gè)常見的情景是:
用 AutoLayout 使用 UIScrollView,使得 UIScrollView 的子視圖能撐開 UIScrollView,而不用手動(dòng)設(shè)置 contentSize,因?yàn)橛袝r(shí)候子視圖的內(nèi)容是不固定的,從而高度也不固定。

如何做?(以垂直滑動(dòng)舉例說明)

  1. 如果是 UILabel,寬度可以根據(jù) scrollView 來設(shè)置。高度不必管,它會(huì)自己撐開。
NSLayoutConstraint.activate([
    contentLabel.topAnchor.constraint(equalTo: titleLabel.bottomAnchor, constant: 10),
    contentLabel.leftAnchor.constraint(equalTo: titleLabel.leftAnchor),
    contentLabel.rightAnchor.constraint(equalTo: titleLabel.rightAnchor),
    contentLabel.widthAnchor.constraint(equalTo: scrollView.widthAnchor, constant: -20),
])
  1. 所有子視圖都必須設(shè)置 translatesAutoresizingMaskIntoConstraints 為 NO。因?yàn)橐粋€(gè) View 如果是用代碼創(chuàng)建的,那它的translatesAutoresizingMaskIntoConstraints 默認(rèn)為 YES,為 YES 的含義是:這個(gè) View 現(xiàn)在使用AutoResizing 進(jìn)行布局,AutoLayout會(huì)根據(jù) autoresizing mask,給這個(gè) View 創(chuàng)建一系列「同等行為」的約束(the system creates a set of constraints that duplicate the behavior specified by the view’s autoresizing mask),這時(shí)候開發(fā)者就不能寫自己的 AutoLayout 約束了,沖突了。
    所以,要把translatesAutoresizingMaskIntoConstraints 設(shè)置為 NO,寫自己的 AutoLayout 約束,這樣才能動(dòng)態(tài)地計(jì)算View 的位置和大小。

    魚與熊掌不可兼得

  2. 最后一個(gè)子視圖(最底或者最右,當(dāng)然也可能是最左和最上,此處以最底示范)添加「跟 ScrollView底部的約束」,這樣才能撐開ScrollView

bottomLabel.bottomAnchor.constraint(equalTo: scrollView.bottomAnchor, constant: -10)

完整可運(yùn)行代碼

import UIKit

class ViewController: 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 ViewController {
    func setupSubviews() {
        // 1. 設(shè)置 scrollView 的約束
        view.addSubview(scrollView)
        scrollView.translatesAutoresizingMaskIntoConstraints = false
        
        NSLayoutConstraint.activate([
            scrollView.topAnchor.constraint(equalTo: view.safeAreaLayoutGuide.topAnchor),
            scrollView.leftAnchor.constraint(equalTo: view.safeAreaLayoutGuide.leftAnchor, constant: 20),
            scrollView.bottomAnchor.constraint(equalTo: view.safeAreaLayoutGuide.bottomAnchor),
            scrollView.rightAnchor.constraint(equalTo: view.safeAreaLayoutGuide.rightAnchor)
            ])
        
        // 2.添加子控件,設(shè)置內(nèi)部約束
        titleLabel.text = "===========titleLabel==========="
        scrollView.addSubview(titleLabel)
        
        titleLabel.translatesAutoresizingMaskIntoConstraints = false
        NSLayoutConstraint.activate([
            titleLabel.topAnchor.constraint(equalTo: scrollView.topAnchor, constant: 10),
            titleLabel.leftAnchor.constraint(equalTo: scrollView.leftAnchor, constant: 10),
            titleLabel.rightAnchor.constraint(equalTo: scrollView.rightAnchor, constant: -10)
            ])
        
        contentLabel.text = "將此處替換為你自己的字符串(超過一屏),即可看見滑動(dòng)效果"
        contentLabel.numberOfLines = 0
        scrollView.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),
            contentLabel.widthAnchor.constraint(equalTo: scrollView.widthAnchor, constant: -20),
            ])
        
        scrollView.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),
            // 3.最后一個(gè) subview,添加跟 scrollView 的約束
            bottomLabel.bottomAnchor.constraint(equalTo: scrollView.bottomAnchor, constant: -10)
            ])
    }
}



參考文檔:

  1. 掘金文章,
  2. Stack Overflow 大佬的回答
  3. Apple 文檔:translatesAutoresizingMaskIntoConstraints
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容